(see problem in action) generally my problem is - I can add elements with innerHTML, I can style them, but I can not addEventListeners
on to them. Has any one seen such problem? (see how it worked before I added html generation)
So I have such simple JavaScript:
function $(id) {
return document.getElementById(id);
}
/* ------------------------------------------------ */
var POINTS = $('points');
var W = 800, W1_2 = W / 2;
var H = 410, H1_2 = H / 2;
var FPS = 20, FRAMES = 0;
var str ="";
var CV = $('canvas');
var CX = CV.getContext('2d');
CV.width = W;
CV.height = H;
function reCoord(){
// coort = $('coor');
// coort.innerHTML = str;
}
/* ------------------------------------------------ */
var id = 0;
var Draggable = function(PointParams, x, y, callbacks) {
var elementIdSring;
var t = this;
switch (PointParams) {
case 'point':
POINTS.innerHTML += '<div id="p' + id + '" class="point"></div>';
elementIdSring = 'p'+String(id);
break;
case 'cp1':
POINTS.innerHTML += '<div id="p' + id + '" class="point cp1"></div>';
elementIdSring = 'p'+String(id);
break;
开发者_StackOverflow社区 case 'cp2':
POINTS.innerHTML += '<div id="p' + id + '" class="point cp2"></div>';
elementIdSring = 'p'+String(id);
break;
case 'limiter':
POINTS.innerHTML += '<div id="l' + id + '" class="point limiter"></div>';
elementIdSring = 'l'+String(id);
break;
}
id++;
coort = $('coor');
coort.innerHTML += elementIdSring + ' ';
var e = $(elementIdSring);
t.element = e;
t.callbacks = {
begin: function() {},
end: function() {},
drag: function() {}
};
if (callbacks != null) for (var v in callbacks) {
switch (v) {
case 'begin':
case 'end':
case 'drag':
if (callbacks[v] instanceof Function)
t.callbacks[v] = callbacks[v];
break;
}
}
t.move(x, y);
var e = $(elementIdSring);
e.addEventListener('mousedown', function(ev) {
if (ev.which == 1) {
Draggable.Target = [t,
t.x - ev.clientX,
t.y - ev.clientY];
t.callbacks.begin();
ev.preventDefault();
ev.stopPropagation();
}
}, false);
};
Draggable.prototype.move = function(x, y) {
reCoord();
var s = this.element.style;
s.left = (this.x = x) + 'px';
s.top = (this.y = y) + 'px';
};
Draggable.tracking = function(ev) {
var t = Draggable.Target;
str = 'X : ' +ev.clientX + ', ' + 'Y :' + ev.clientY ;
if (t) {
t[0].move(ev.clientX + t[1], ev.clientY + t[2]);
t[0].callbacks.drag();
}
};
Draggable.finish = function(ev) {
var t = Draggable.Target;
if (t) {
t[0].move(ev.clientX + t[1], ev.clientY + t[2]);
t[0].callbacks.end();
coort = $('coor');
coort.innerHTML = " ";
Draggable.Target = null;
}
};
window.addEventListener('mousemove',
Draggable.tracking, false);
window.addEventListener('mouseup',
Draggable.finish, false);
/* ------------------------------------------------ */
var linePoints = [
new Draggable('point', 50, 175),
new Draggable('cp1', 175, 225),
new Draggable('cp2', 175, 120),
new Draggable('point', 350, 120),
new Draggable('point', 370, 175),
new Draggable('cp1', 475, 225),
new Draggable('cp2', 475, 175),
new Draggable('point', 650, 165),
new Draggable('point', 50, 275) ,
new Draggable('cp1', 175, 225),
new Draggable('cp2', 175, 325),
new Draggable('point', 350, 325),
new Draggable('point', 370, 275) ,
new Draggable('cp1', 475, 225),
new Draggable('cp2', 475, 275),
new Draggable('point', 650, 285)
];
var Limits = [
new Draggable('limiter', 50, 150),
new Draggable('limiter', 650, 150),
new Draggable('limiter', 50, 300) ,
new Draggable('limiter', 650, 300)
];
/* ------------------------------------------------ */
window.addEventListener('mousemove',
Draggable.tracking, false);
window.addEventListener('mouseup',
Draggable.finish, false);
var MODE = 1;
function line(p0, p1, p2, p3, t) {
return [(1 - t) * p0.x + t * p3.x,
(1 - t) * p0.y + t * p3.y];
}
function quadratic(p0, p1, p2, p3, t) {
var s = 1 - t;
return [s*s*p0.x + 2*s*t*p1.x + t*t*p3.x,
s*s*p0.y + 2*s*t*p1.y + t*t*p3.y];
}
function bezier(p0, p1, p2, p3, t) {
var s = 1 - t;
return [s*s*s*p0.x + 3*s*s*t*p1.x +
3*s*t*t*p2.x + t*t*t*p3.x,
s*s*s*p0.y + 3*s*s*t*p1.y +
3*s*t*t*p2.y + t*t*t*p3.y];
}
function catmull(p0, p1, p2, p3, t) {
var v = [(p2.x - p0.x)/2, (p2.y - p0.y)/2];
var w = [(p3.x - p1.x)/2, (p3.y - p1.y)/2];
return [(2*p1.x-2*p2.x+v[0]+w[0])*t*t*t +
(-3*p1.x+3*p2.x-2*v[0]-w[0])*t*t +
v[0]*t + p1.x,
(2*p1.y-2*p2.y+v[1]+w[1])*t*t*t +
(-3*p1.y+3*p2.y-2*v[1]-w[1])*t*t +
v[1]*t + p1.y];
}
/* ------------------------------------------------ */
var TYPE = $('type');
TYPE.addEventListener('change', redraw, false);
function drawArrow(type, t, P0, P1, P2, P3) {
var c, c0, c1;
c0 = window[type](P0, P1, P2, P3, t - 0.1);
c = window[type](P0, P1, P2, P3, t);
c1 = window[type](P0, P1, P2, P3, t + 0.1);
CX.save();
CX.translate(c[0], c[1]);
CX.rotate(Math.atan2(c1[1] - c0[1], c1[0] - c0[0]));
CX.beginPath();
CX.moveTo(0, 0);
CX.lineTo(-10, 10);
CX.lineTo(-10, -10);
CX.closePath();
CX.stroke();
CX.restore();
}
function locLiner(P0start,P3end, color){
CX.strokeStyle = color;
CX.beginPath();
CX.moveTo(P0start.x, P0start.y);
CX.lineTo(P3end.x, P3end.y);
CX.stroke();
}
function locBesier(P0start, cp1, cp2, P3end){
CX.strokeStyle = '#000';
CX.beginPath();
CX.moveTo(P0start.x, P0start.y);
CX.bezierCurveTo(cp1.x, cp1.y,
cp2.x, cp2.y,
P3end.x, P3end.y);
CX.stroke();
CX.strokeStyle = '#ccc';
CX.beginPath();
CX.moveTo(P0start.x, P0start.y);
CX.lineTo(cp1.x, cp1.y);
CX.lineTo(cp2.x, cp2.y);
CX.lineTo(P3end.x, P3end.y);
CX.stroke();
}
function locQuadratic(P0start, cp1, P3end){
CX.strokeStyle = '#000';
CX.beginPath();
CX.moveTo(P0start.x, P0start.y);
CX.quadraticCurveTo(cp1.x, cp1.y,
P3end.x, P3end.y);
CX.stroke();
CX.strokeStyle = '#ccc';
CX.beginPath();
CX.moveTo(P0start.x, P0start.y);
CX.lineTo(cp1.x, cp1.y);
CX.lineTo(P3end.x, P3end.y);
CX.stroke();
}
function redraw() {
var type = TYPE.value, i, c, c0, c1, t, d;
CX.setTransform(1,0, 0,1, 0,0);
CX.clearRect(0, 0, W, H);
CX.setTransform(1,0, 0,1, -10,-10);
for(i =0; i<Limits.length; i=i+2){locLiner(Limits [i], Limits[i+1], '#FF0000');}
CX.strokeStyle = '#000';
CX.beginPath();
switch (POINTS.className = type) {
case 'line':
for(i =0; i<linePoints.length; i=i+4){locLiner(linePoints[i], linePoints[i+3], '#000');}
break;
case 'quadratic':
for(i =0; i<linePoints.length; i=i+4){locQuadratic(linePoints[i], linePoints[i+1], linePoints[i+3]);}
break;
case 'bezier':
for(i =0; i<linePoints.length; i=i+4){locBesier(linePoints[i], linePoints[i+1], linePoints[i+2], linePoints[i+3]);}
break;
default:
return;
}
for(i =3; i<linePoints.length; i=i+16){locLiner(linePoints[i], linePoints[i+1]); CX.beginPath();
CX.strokeStyle = '#000000';
CX.fillStyle = '#38A1DB';
CX.moveTo(linePoints[i].x,linePoints[i].y);
CX.bezierCurveTo(linePoints[i].x , (linePoints[i].y +( linePoints[i+1].y - linePoints[i].y)/2), linePoints[i+1].x, (linePoints[i].y +( linePoints[i+1].y - linePoints[i].y)/2), linePoints[i+1].x,linePoints[i+1].y);
CX.bezierCurveTo(linePoints[i+1].x , (linePoints[i+1].y +( linePoints[i+8+1].y - linePoints[i+1].y)/2), linePoints[i+8+1].x, (linePoints[i+1].y +( linePoints[i+8+1].y - linePoints[i+1].y)/2), linePoints[i+8+1].x,linePoints[i+8+1].y);
CX.bezierCurveTo(linePoints[i+8+1].x , (linePoints[i+8+1].y +( linePoints[i+8].y - linePoints[i+8+1].y)/2), linePoints[i+8].x, (linePoints[i+8+1].y +( linePoints[i+8].y - linePoints[i+8+1].y)/2), linePoints[i+8].x,linePoints[i+8].y);
CX.bezierCurveTo(linePoints[i+8].x , (linePoints[i+8].y +( linePoints[i].y - linePoints[i+8].y)/2), linePoints[i].x, (linePoints[i+8].y +( linePoints[i].y - linePoints[i+8].y)/2), linePoints[i].x,linePoints[i].y);
CX.fill();
}
CX.strokeStyle = '#39B7CD';
for (i = 0; i < 100; i += 10) {
for(j =0; j<linePoints.length; j=j+4){ drawArrow(type, (i + FRAMES % 10) / 100, linePoints[j], linePoints[j+1], linePoints[j+2], linePoints[j+3]);}
}
++FRAMES;
}
setInterval(redraw, 1500 / FPS);
and some html:
<canvas id="canvas"></canvas>
<div id="points"></div>
<p id="coor"></p>
<select id="type">
<option value="line">line</option>
<option value="quadratic">quadratic</option>
<option value="bezier" selected>bezier</option>
</select>
and some CSS:
@charset "UTF-8";
/* ------------------------------------------------ */
HTML,BODY,OL,UL,LI,DL,DT,DD,P,DIV,SPAN {
margin:0;
padding:0;
}
/* ------------------------------------------------ */
BODY {
margin:10px;
background:#eee;
color:#000;
}
#canvas {
background:#fff;
}
.point {
position:absolute;
width:9px;height:9px;
margin:-4px 0 0 -4px;
background:rgba(0, 0, 255, 0.5);
border:rgba(128, 128, 255, 0.8);
-moz-border-radius:4px;
-webkit-border-radius:4px;
border-radius:4px;
}
.limiter{
border:rgba(128, 1, 1, 0.8);
background:rgba(255, 1, 1, 0.5);
}
.line .cp1, .line .cp2
{
display:none;
}
.quadratic .cp2{
display:none;
}
.quadratic .cp1,
.bezier .cp1,
.bezier .cp2
{
background:rgba(0, 255, 0, 0.5);
border:rgba(128, 255, 128, 0.8);
}
Why don't you switch your creation of elements via innerHTML to something like
var el=document.createElement("DIV");
el.style.property="value";
el.addEventListener(myFunction, bubbleFlag);
POINTS.appendChild(el);
POINTS.innerHTML +=
Don't ever do that.
This serialises the entire DOM contents of POINTS
into an HTML string, adds a new string, and re-parses the concatenated string into new elements for everything in the POINTS
element. As well as being slow, this loses all non-serialisable information from the previous content of the element, such as form field values, event listeners and JS references.
As in kstrieder's answer, use DOM operations.
精彩评论