如何在一个画布上启用绘图和删除多个元素?

时间:2016-08-14 13:14:00

标签: javascript html5 canvas

我正在尝试为乒乓球运动图形编码。 我想让它为每个练习的集会展示一张桌子,上面有箭头,表示球的运动路径和可以玩的区域的矩形。

现在它看起来像这样:https://codepen.io/graNite/pen/grqXOo

您可以添加新表,删除最后一个表,并在第一个表的同一画布图层上绘制两个固定箭头。

我要启用的是通过点击并拖动在每个表格上绘制箭头*,然后右键单击它们将其删除。

*(就像它们是在drawArrows函数中绘制的

这样做的最佳方式是什么?

我已经为箭头实现了一个画布层,甚至可以为每个表上的每个箭头执行此操作,但是如果我右键单击它以删除它,我怎样才能访问中间层的箭头?

HTML

<button onclick="addTable()">Add table</button>
<button onclick="removeTable()">Remove table</button>
<button onclick="drawArrow(50, 50, 150, 250)">Draw arrow</button>
<button onclick="drawArrow(50, 300, 180, 20)">Draw arrow2</button>
</br>
<div id="tables">
</div>

CSS

body {
    background-color: #982439;
}

#table {
    padding: 10px;
}

canvas {
    position: absolute;
}

JS

function drawTable(table) {
    "use strict";
    var draw = table.getContext("2d");
    draw.shadowBlur = 20;
    draw.shadowColor = 'rgba(0,0,0,0.3)';            // shadow
    draw.fillStyle = "#2e3f73";                      // table
    draw.fillRect(35.25,    20,      152.5,  274);
    draw.fillStyle = "#ffffff";                      // lines
    draw.fillRect(111.35,   20,      0.3,    274);   // middle line
    draw.fillRect(35.25,    20,      2,      274);   // lift side
    draw.fillRect(185.75,   20,      2,      274);   // right side
    draw.fillRect(35.25,    20,      152.5,  2);     // top base line
    draw.fillRect(35.25,    292,     152.5,  2);     // bottom base line
    draw.fillRect(20,       156,     183,    2);     // net
}

function addTable() {
    "use strict";
    var container = document.createElement("div"),
        table = document.createElement("canvas"),
        arrowLayer = document.createElement("canvas"),
        width = 223,
        height = 314;


    container.appendChild(table);
    container.appendChild(arrowLayer);
    container.style.width = width + "px";
    container.style.height = height + "px";
    container.style.display = "inline-block";
    document.getElementById("tables").appendChild(container);

    table.width = width;
    table.height = height;
    table.className = "table";
    table.style.zIndex = "0";
    drawTable(table);

    arrowLayer.width = width;
    arrowLayer.height = height;
    arrowLayer.className = "arrow";
    arrowLayer.style.zIndex = "1";
    arrowLayer.id = "arrow1";
}

function removeTable() {
    "use strict";
    var child = document.getElementById("tables").lastChild;
    child.parentNode.removeChild(child);
}

function drawArrow(start_x, start_y, end_x, end_y) {
    "use strict";
    var draw = document.getElementById('arrow1').getContext('2d'),
        angle = Math.atan((end_y - start_y) / (end_x - start_x)),
        length = Math.sqrt(Math.pow((end_x - start_x), 2) + Math.pow((end_y - start_y), 2));

    // set colors and style
    draw.strokeStyle = "#ffb900";
    draw.fillStyle = "#ffb900";
    draw.lineWidth = 9;

    // draw arrow line
    draw.beginPath();
    draw.translate(start_x, start_y);
    draw.moveTo(0, 0);
    draw.rotate(angle);
    draw.lineTo(length - 23, 0); // note: arrowhead is 24px long and total arrow is line+head   
    draw.stroke();
    draw.moveTo(-start_x, -start_y);

    // draw arrow head
    draw.beginPath();
    draw.moveTo(length, 0);
    draw.lineTo(length - 24, -7.5); // ^ see note above
    draw.lineTo(length - 24, 7.5);
    draw.fill();

    //reset context 
    draw.rotate(-angle);
    draw.moveTo(-start_x, -start_y);
    draw.translate(-start_x, -start_y);
}

2 个答案:

答案 0 :(得分:2)

良好的界面设计

优质的界面不应该有丑陋的按钮,它应该直观且易于使用。应始终有反馈(光标,突出显示,翻转效果)。效果并不像节目那么多,而是提供用户与应用程序交互所需的信息。因此,FX不必是主要的,只需足以让用户看到一切正常,可点击的和不可点的。

我打算在没有帮助的情况下添加它,因为它应该有意义,但我已经添加了帮助,只是它没有。我们都有不同的界面使用方法。

更新:我添加了更多代码。现在只有在使用帮助功能之前才会显示帮助。一旦使用,帮助不会显示。

通过我认为需要它的代码添加注释(基本上无处不在)

<强>代码

表位于数组tableArray中。使用addTable()添加表,返回表对象。表默认为非活动table.active=false。要激活,请单击表格上的鼠标或table.active = true; table.draw();箭头在数组table.arrows中作为{x:?,y?,xx:?,yy:?,highlight:false}以删除使用阵列拼接或通过界面。要删除表,请将其停用table.active = false;(或单击关闭),它将保留在DOM中,直到updateTables()被调用。 (当用户点击关闭时,会自动调用点击更新)

总会有一个非活动表可见,可用于添加活动表。

数组中的每个表都包含完成所需操作所需的一切。 Mouseevent,渲染事件,关闭等

每个表都以全帧速率渲染(当它具有内部鼠标焦点时),因此您可以根据需要添加漂亮的动画。当鼠标未在表上时,除非您调用table.draw()函数,否则不会更新。

代码有点乱,因为它有点失控。 Consts定义了大多数东西(代码顶部)。表,关闭图标和空表是预先渲染的。根据需要渲染箭头和帮助。

使用

单击空表以添加(激活)。单击活动表关闭图标以关闭。单击拖动以添加箭头,在近箭头处单击鼠标右键以删除。鼠标附近的箭头会突出显示。

  

注意表的数量没有限制。这不是一个好主意,你应该限制表的数量。当添加的表导致页面滚动条出现时,还会出现一些布局问题。删除表不会恢复到原来的状态。因为我不知道你想要什么,所以我把它留给了你。

     

还添加了GLOBAL_SCALE const应用于所有常量只是为了它的乐趣所以它比原来的小一点

// contains an array of tables.
var tableArray = [];

// App constants all up top
const GLOBAL_SCALE = 0.7;
const SHOW_HELP = true;  // set to false to have the help turned off
const SHADOW = 'rgba(0,0,0,0.8)';
const WHITE = "white";
const TABLE_REFRESH_DELAY = 50; // Time in millisecond befor updating DOM for table add and remove
const FONT = {
face : "px Arial",
size : Math.max(10,18 * GLOBAL_SCALE),
fill : WHITE,
};
const TABLE = {
width  : 223 * GLOBAL_SCALE,  // size of table
height : 314 * GLOBAL_SCALE,
tables : document.getElementById("tables"),
image : { // table image styles
    shadow : SHADOW,
    shadowBlur : 20 * GLOBAL_SCALE,
    fill :  "#2e3f73",
    lines : WHITE,
    font : FONT,
    cursor : "default",
},
empty : {  // empty table styles
    inset : 30 * GLOBAL_SCALE, // amount box is inset
    lines : 'rgba(255,255,255,0.5)',
    lineWidth : 8 * GLOBAL_SCALE,
    shadow : SHADOW,
    shadowBlur : 20 * GLOBAL_SCALE,
    font : FONT,   
    cursor : "pointer",
    highlightAmount : 0.3, // amount to highlight empty table when mouse over 0 none 1 full
},
arrow : {  // arrow styles
    width : 15 * GLOBAL_SCALE, // arrow width
    shadow : SHADOW,
    shadowBlur : 10 * GLOBAL_SCALE,
    // custom cursor
    cursor : "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADcAAAAVCAYAAADiv3Z7AAACtUlEQVRYha2Ye1NTMRDFf/KqLY/SlvIolAJFqSKOoqI4o+P3/1LXP3oi23XvTUrpzJm52Zxs9mRzczeFl/u9KkDp2FV5xb/IURT42hIoGbcsp1hMGrxegw1hU9gCWsDrDFriWrTc2FYDL/K1qZiS2KywdRO0DcAiTdIBtoEdYFfYC7Arzo7426a96+B53n/idBTDlha7VmAStiGyD9wjiegCPWAAHABDg0NhqL6B0BcGZpyF5fQM98D52lcc7SaBXlhbArrGeRTQEDgCKoNzwdsq4Aw4BUZqn8qWeGOhMryRGWt9jrRwfSMwbdF/72F6SFuxLXLPORppwspMPgYq+0v93mb63rh2OFbPU9sO5hlrcXtKRstnz2atxXwb9oCqEhYmWrRdR4F6mxdQIzqyfWjwOQOutMgHzF+RlL0FcTZrXaV77MU4YZ+EXIC/InuTuIL+B809Ay6UvX3mZ4TdmgviOiIdARPgxooywr4BX4TGbRkFvoo40/4MvHPi/HtXK+5CKxOJ+y6BXwsC/ePav18gcz+AeyeuS2ZbenFN2zJlLxuUa4fbtIkTtFfOnBfzENjum8TZbWQ4j5nt9jPgPEY+KXzn1ng6UPaYnz7p+1JphW7R6WVsM6FS/x1Ph41d5dT+KB+3at/JVrn+9/Jf6fnWjEm4ofC0jD4Fhxo4kZOpwxVwaTBl/g17q4lnDjfqnxp/17IlXMt+qYxc6NnyLafoO1f3ER8Cxyx+xG3lcKL+E9N/pknPtTATPY/VNwr8nbFYvRw7nDj+qWzZCsVnr6T8snVfj//rv1SaRbVlPxhj0Wf+/lhE3MTL1paRwFzh7Kv2qMqPbgUR3/vsOET+l7oVWIElV56Su9ky9znvczPjf+n7nBUZ3YKjW/FzbuO5MXV/U6x8E68TmrP5vuf+h1IaT5b7F+ZaSjBzrT+rAAAAAElFTkSuQmCC') 10 11, pointer",
    fill : "#ffb900",
    highlight : "#ffdc44",
    lineWidth : 1,
    line : "#ffdc44",
    lineHigh : "#ffed55",
    head : 30 * GLOBAL_SCALE, // arrow head width
    minSize : 5, // min size arrow can be if smaller then arrow is not created
},
DOM : {  // variouse dom setting for table canvas and div tags
    display : "inline-block",
    canvasClass : "table",
    zIndex : 1,
},
closeIcon : { // styles for reandering and display close icon
    size : 32 * GLOBAL_SCALE,
    fill : "red",
    lines : WHITE,
    lineWidth : Math.max(1,2 * GLOBAL_SCALE),
    shadow : SHADOW,
    shadowBlur : 20 * GLOBAL_SCALE,  
    cursor : "pointer",
    pos : {
        x : 1, // as fractions
        y : 0, 
    }
},
help : {  // text help
    empty : "Click here to|add a new table".split("|"),
    active : "Click to drag arrows".split("|"),
    activeArrow : "Right click on arrow|to remove it".split("|"),
    closeTable : "To close table|move to top right|click Close Icon".split("|"),
}
}
const MOUSE = {  // event contains a list of mouse event to listen to 
buttonMasks : [1, 2, 4, 6, 5, 3],
events : "mousemove,mousedown,mouseup,mouseout,mouseover,contextmenu".split(","),
};  // contextmenu is included as that needs to be blocked for right button events

var helpItemsUsed = {
empty : false,
active : false,
activeArrow : false,
closeTable : false,
};
const turnOffHelp = function(){
helpItemsUsed.empty = true;
helpItemsUsed.active  = true;
helpItemsUsed.activeArrow  = true;
helpItemsUsed.closeTable  = true;
};
if(!SHOW_HELP){turnOffHelp();};
// returns distance of point p to line segment x, y,xx,yy
const distFromLine = function(px,py,x,y,xx,yy){
var vx,vy,pvx,pvy,lx,ly,u;
vx = xx - x;
vy = yy - y;
pvx = px - x;
pvy = py - y;
u = (pvx * vx + pvy * vy)/(vy * vy + vx * vx);
if(u >= 0 && u <= 1){
    lx = vx * u;
    ly = vy * u;
    return Math.sqrt(Math.pow(ly - pvy,2) + Math.pow(lx - pvx,2));
}
// closest point past ends of line so get dist to closest end
return Math.min(
    Math.sqrt(Math.pow(xx - px,2)+ Math.pow(yy - py,2)),
    Math.sqrt(Math.pow(x - px,2)+ Math.pow(y - py,2))
);
}
// set up functions create images and do other general setup
function setupContext(ctx,descript){ // sets common context settings
ctx.shadowBlur = descript.shadowBlur;
ctx.shadowColor = descript.shadow;   
ctx.strokeStyle = descript.lines;          
ctx.fillStyle = descript.fill;          
ctx.lineWidth = descript.lineWidth;    
ctx.lineCap = "round";    
if(descript.font){
    ctx.font = descript.font.size + descript.font.face;
}
}
function createTableImage() {  // create image of table but why write a comment when the function tells it all???
var table = document.createElement("canvas");
table.width = TABLE.width;
table.height= TABLE.height;
var ctx = table.getContext("2d");
setupContext(ctx,TABLE.image);
var scaleX = table.width / 223; /// get the scale compared to original layout
var scaleY = table.height / 314; /// get the scale compared to original layout
ctx.fillStyle = TABLE.image.fill; 
ctx.fillRect(35.25 * scaleX,    20 * scaleY,      152.5 * scaleX,  274 * scaleY);
ctx.fillStyle = TABLE.image.lines;            // lines
ctx.fillRect(111.35 * scaleX,   20 * scaleY,      0.3,    274 * scaleY);   // middle line
ctx.fillRect(35.25 * scaleX,    20 * scaleY,      2,      274 * scaleY);   // lift side
ctx.fillRect(185.75 * scaleX,   20 * scaleY,      2,      274 * scaleY);   // right side
ctx.fillRect(35.25 * scaleX,    20 * scaleY,      152.5 * scaleX,  2);     // top base line
ctx.fillRect(35.25 * scaleX,    292 * scaleY,     152.5 * scaleX,  2);     // bottom base line
ctx.fillRect(20 * scaleX,       156 * scaleY,     183 * scaleX,    2);     // net
return table
}

function createEmptyImage() { // empty table image
var i = TABLE.empty.inset;
var image = document.createElement("canvas");
var w = image.width = TABLE.width;
var h = image.height = TABLE.height;
var ctx = image.getContext("2d");
setupContext(ctx,TABLE.empty);
ctx.strokeRect(i,    i, w - i * 2, h - i * 2);
ctx.beginPath();
ctx.moveTo(i * 2, i * 2);
ctx.lineTo(w - i * 2, h - i * 2);
ctx.moveTo(i * 2, h - i * 2);
ctx.lineTo(w - i * 2, i * 2);
ctx.stroke();
return image
}
function createCloseImage() {  // create close icon
var S = TABLE.closeIcon.size;
var s = S * 0.5;
var c = s * 0.4; // cross dist from center
var sb = TABLE.closeIcon.shadowBlur;
var l = TABLE.closeIcon.lineWidth;
var image = document.createElement("canvas");
// Image must include shadowblur
image.width = S+sb; // add blur to size
image.height= S+sb;
var ctx = image.getContext("2d");
setupContext(ctx,TABLE.closeIcon);
ctx.beginPath();
var cx = s + sb / 2;  // add half blur to get center
var cy = s + sb / 2;
ctx.arc(cx, cy, s - l, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cx - c, cy - c)
ctx.lineTo(cx + c, cy + c)
ctx.moveTo(cx - c, cy + c)
ctx.lineTo(cx + c, cy - c)
ctx.stroke();
return image
}
// create the images
var tableImage = createTableImage();
var closeIcon = createCloseImage();
var emptyTableImage = createEmptyImage();


// draws a arrow a is the arrow object
function drawArrow(ctx,a){
var s = TABLE.arrow; // get arrow style
var vx,vy;
var x,y;
x = a.x;
y = a.y;
vx = a.xx-x;
vy = a.yy-y;
var dir = Math.atan2(vy,vx);
var len = Math.sqrt(vx * vx + vy * vy);
// ctx.save();
ctx.setTransform(1,0,0,1,x,y);
ctx.rotate(dir);
var w = s.width/2;
var h = Math.min(len,s.head); // ensure arrow head no bigger than arrow length
h /=2;
if(a.highlight){
    ctx.fillStyle = s.highlight;
    ctx.strokeStyle = s.lineHigh;
}else{
    ctx.fillStyle = s.fill;
    ctx.strokeStyle = s.line;
}
ctx.lineWidth = s.lineWidth;
ctx.save();
ctx.shadowBlur = s.shadowBlur;
ctx.shadowColor = s.shadow;       
ctx.beginPath();
ctx.moveTo(0,-w/2);
ctx.lineTo(len-h-h,-w);
ctx.lineTo(len-h-h,-h);
ctx.lineTo(len,0);
ctx.lineTo(len-h-h,h);
ctx.lineTo(len-h-h,w);
ctx.lineTo(0,w/2);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}

// display help text for table
function drawHelpText(ctx,text,style){
ctx.font = style.font.size + style.font.face;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
var i,len;
len = text.length;
var y = ctx.canvas.height / 2 - len * style.font.size * 1.2;
var yy = y + 1;
ctx.strokeStyle = "#000";
ctx.lineWidth = 2;
for(i = 0; i < len; i++){
    ctx.strokeText(text[i], ctx.canvas.width / 2 + 1, yy);
    yy += TABLE.empty.font.size * 1.2;
}     
ctx.fillStyle = style.font.fill;
for(i = 0; i < len; i++){
    ctx.fillText(text[i], ctx.canvas.width / 2, y);
    y += TABLE.empty.font.size * 1.2;
} 

}
//------------------------------------------------------------
// functions for table
function drawClose(){ // draws close icon. Fades in the close mouse is
var ctx = this.ctx;
var w = closeIcon.width;
var grow = w * 0.1;
var x = (this.width - w) * TABLE.closeIcon.pos.x ;
var y = (this.height - w) * TABLE.closeIcon.pos.y ;

x += w/2; // get icon center 
y += w/2;
var dist = Math.sqrt(Math.pow(this.mouse.x - x, 2) + Math.pow(this.mouse.y - y, 2));
if(dist < TABLE.closeIcon.size / 2){
    this.mouseOverClose = true;
}else{
    this.mouseOverClose = false;
}
x -= w/2; // back to icon top left
y -= w/2;
ctx.globalAlpha = 1-(Math.min(100,(dist - w * 2)) / 100);
if(this.mouseOverClose){
    ctx.drawImage(closeIcon,x-grow,y-grow,w + grow * 2,w + grow * 2);
}else{
    ctx.drawImage(closeIcon,x,y);
}
ctx.globalAlpha = 1;
}
function drawEmpty(){ // draw empty table and handle click on empty table
var ctx = this.ctx;
ctx.drawImage(emptyTableImage,0,0);
if(this.mouse.over){
    ctx.globalCompositeOperation = "lighter"; 
    ctx.globalAlpha = TABLE.empty.highlightAmount;
    ctx.drawImage(emptyTableImage,0,0);
    ctx.globalAlpha = 1;
    ctx.globalCompositeOperation = "source-over"; 
    
    if(!helpItemsUsed.empty){ // show help is the help action has not yet been done
        drawHelpText(ctx,TABLE.help.empty,TABLE.empty);
    }
    this.cursor = TABLE.empty.cursor;
    if(this.mouse.button & 1){ // bit field
        this.buttonDown = true;
    }else if( this.buttonDown){
        this.active = true;
        setTimeout(addTable,TABLE_REFRESH_DELAY);
        this.buttonDown = false;
        helpItemsUsed.empty = true; // flag this help as not needed as user has complete that task
    }
}else{
    this.cursor = "default";
}
}
function drawTable(){  // darw the table all states
var ctx = this.ctx;
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
if(this.active){
    ctx.drawImage(tableImage,0,0);
    if(this.mouse.over){
        if(!this.dragging){ // Dont draw close icon while draggin
            this.drawCloseIcon();
        }
        if(this.mouseOverClose && ! this.dragging){ // if not dragging and mouse over close
            this.cursor = TABLE.closeIcon.cursor;   // set cursor
            if(this.mouse.button & 1){ // bit field  is mouse left down
                this.buttonDown = true;
            }else if(this.buttonDown){ // only close if mouse moves up while over close.
                this.active = false;
                helpItemsUsed.closeTable = true;
                this.buttonDown = false;
                setTimeout(updateTables,TABLE_REFRESH_DELAY);
            }
        }else{ // not over close
            // if near a arrow and mouse button right is down delete the arrow
            if(this.closestArrowIndex > -1 && (this.mouse.button & 4) === 4){ // but field Only button right down
                this.arrows.splice(this.closestArrowIndex,1);
                this.closestArrowIndex = -1;
                this.mouse.button = 0;  // turn mouse click off
                helpItemsUsed.activeArrow = true; // flag arrow delete help as used
            
            }else  // if not near line or close then check for mouse left 
            if(this.mouse.button & 1){ // bit field  if down start dragging new arroe
                if(!this.dragging){ // Start of drag create arrow
                    this.arrows.push({
                        x: this.mouse.x,
                        y: this.mouse.y,
                        xx : this.mouse.x,
                        yy : this.mouse.y,
                    });
                    this.currentArrow = this.arrows[this.arrows.length-1];
                    this.dragging = true;
                    
                }else{   // during drag move arrow endpoint
                    helpItemsUsed.active = true; // flag arrow help as used
                    this.currentArrow.xx = this.mouse.x;
                    this.currentArrow.yy = this.mouse.y;
                }
            }else{ // mouse up
                if(this.dragging){ // is dragging then must be a arrow
                    // if arrow added is smaller than 2 pixels then remove it;
                    if(Math.abs(this.currentArrow.xx-this.currentArrow.x) < TABLE.arrow.minSize && Math.abs(this.currentArrow.y-this.currentArrow.yy) < TABLE.arrow.minSize){
                        this.arrows.length -= 1;
                    }
                    this.currentArrow = null;
                    this.dragging = false;
                }
            }
            this.cursor = TABLE.image.cursor; // set cursor tp table standard
        }
    }  
    if(this.closestArrowIndex > -1 && ! this.dragging){ // is mouse near arrow 
        this.cursor = TABLE.arrow.cursor;  // yes set cursor for arrow
     
    }
    // find arrow closest to mouse
    var minDist = TABLE.arrow.width; // this sets the max distance mouse can be for it to highlight an arrow
    var dist = 0;
    this.closestArrowIndex = -1;
    for(var i = 0; i < this.arrows.length; i++){ // test all arrow
        var a = this.arrows[i];
        drawArrow(ctx,a);  // draw the arrow
        a.highlight = false;  // turn off highlight
        dist = distFromLine(this.mouse.x,this.mouse.y,a.x,a.y,a.xx,a.yy); // get distance from mouse
        if(dist < minDist){  // is closer than any other arrow
            this.closestArrowIndex = i; // yes remember the index
            minDist = dist;
        }
    }
    if(this.closestArrowIndex > -1 && this.mouse.over){ // is a arror close to mouse
        this.arrows[this.closestArrowIndex].highlight = true; // highlight it
    }
    
    ctx.setTransform(1,0,0,1,0,0); // reset transform after arrows drawn
    // show help
    if(this.mouse.over){
        if(this.arrows.length === 0 && !helpItemsUsed.active){
            drawHelpText(ctx,TABLE.help.active,TABLE.image);
        }else
        if(this.closestArrowIndex > -1 && !helpItemsUsed.activeArrow){
            drawHelpText(ctx,TABLE.help.activeArrow,TABLE.image);
        }else
        if(this.closestArrowIndex === -1 && !helpItemsUsed.closeTable){
            drawHelpText(ctx,TABLE.help.closeTable,TABLE.image);
        }
    }
}else{
    this.drawEmpty();
}
}
// renders a table. Stops rendering if the mouse is not over
function tableUpdate(){
if(this.mouse.over){
    this.updating = true;
    requestAnimationFrame(this.update);
}else{
    this.buttonDown = false; // turn of button if dragged off
    this.div.style.cursor = "default";
    this.updating = false;
    this.draw(); // draw another time. This alows for the visual state to be correct
}
this.draw();    
this.div.style.cursor = this.cursor;
}
// Mousecallback starts a table rendering if not allready doing so.
function mouseInOutCallback(){
if(this.mouse.over){
    if(!this.updating){
        this.update();
    }
}else{
    this.div.style.cursor = "default";
}
}
// function to handle mouse events
function mouseEvent(e) {
var m =this; // lazy programer short cut
var t = e.type;
var bounds = m.element.getBoundingClientRect();
m.x = e.clientX - bounds.left;
m.y = e.clientY - bounds.top;
if (t === "mousedown") {
    m.button |= MOUSE.buttonMasks[e.which-1];
} else if (t === "mouseup") { 
    m.button &= MOUSE.buttonMasks[e.which + 2];
} else if (t === "mouseout") { 
    m.button = 0; 
    m.over = false;
    m.table.mouseOver();
} else if (t === "mouseover") { 
    m.over = true;
    m.table.mouseOver();
}
e.preventDefault();
}
// create the mouse inteface for a table
function createMouse(table){
var mouse = {
    x : 0,
    y : 0, 
    over : false,
    table : table,
    element : table.div,
    button : 0,
};
mouse.event = mouseEvent.bind(mouse);
mouse.start = function(){
    MOUSE.events.forEach( n => { this.element.addEventListener(n, this.event); } );
}
mouse.remove = function(){
    MOUSE.events.forEach( n => { this.element.removeEventListener(n, this.event); } );
}
return mouse;
}
function createAddTable(){ // Creates a table. Tables default in inactive
var table = {};
var div = document.createElement("div");
div.style.width =  TABLE.width+ "px";
div.style.height = TABLE.height + "px";
div.style.display = TABLE.DOM.display;
var canvas = document.createElement("canvas");
canvas.width = TABLE.width;
canvas.height = TABLE.height;
canvas.className = TABLE.DOM.tableClass
canvas.style.zIndex = TABLE.DOM.zIndex;
var ctx = canvas.getContext("2d");
table.div = div;
table.canvas = canvas;
table.ctx = ctx;
table.arrows = [];
table.width = TABLE.width;
table.height = TABLE.height;
table.mouseOverClose = false
table.drawCloseIcon = drawClose;
table.draw = drawTable;
table.dragging = false;
table.active = false;
table.update = tableUpdate.bind(table);
table.mouseOver = mouseInOutCallback;  // called by mouseEvent when mouse over out
table.drawEmpty = drawEmpty.bind(table);
table.dead = false; // when removed and not needed it is dead and can then be removed from table array
table.updating = false; // true is animation requests are happening
div.appendChild(canvas); // add canvas
table.mouse = createMouse(table);    
table.draw();
return table;
}
function removeTable(table){ // remove table from dom
table.mouse.remove();  // deactivate moue events
TABLE.tables.removeChild(table.div); // remove from DOM
table.dead = true;// flag as dead to be removed from table array
}
function addTable(){ // Adds a table to table array and DOM
var table = createAddTable();  // create new table
TABLE.tables.appendChild(table.div); // add to the dom
table.mouse.start();  // start the mouse
tableArray.push(table); // add to table array
return table;
}
function updateTables(){ // Updates tables. Removes any dead tables from table array
var closeTables = [];
closeTables = tableArray.filter(t => !t.active);
while(closeTables.length > 1){
    removeTable(closeTables.shift());
}
for(var i = 0; i < tableArray.length; i ++){
    if(tableArray[i].dead){
        tableArray.splice(i,1);
        i -= 1;
    }
}
}
addTable();
body {
    background-color: #982439;
}

#table {
    padding: 10px;
}

canvas {
	position: absolute;
}
<div id="tables">
</div>

答案 1 :(得分:0)

您的代码中使用静态ID的问题是错误的,您需要对表或div进行计数,然后您需要使用id传递该计数。

我解决这个问题检查代码:

&#13;
&#13;
function drawTable(table) {
    "use strict";
    var draw = table.getContext("2d");
    draw.shadowBlur = 20;
    draw.shadowColor = 'rgba(0,0,0,0.3)';            // shadow
    draw.fillStyle = "#2e3f73";                      // table
    draw.fillRect(35.25,    20,      152.5,  274);
    draw.fillStyle = "#ffffff";                      // lines
    draw.fillRect(111.35,   20,      0.3,    274);   // middle line
    draw.fillRect(35.25,    20,      2,      274);   // lift side
    draw.fillRect(185.75,   20,      2,      274);   // right side
    draw.fillRect(35.25,    20,      152.5,  2);     // top base line
    draw.fillRect(35.25,    292,     152.5,  2);     // bottom base line
    draw.fillRect(20,       156,     183,    2);     // net
}



function addTable() {
   "use strict";
    var container = document.createElement("div"),
		table = document.createElement("canvas"),
		arrowLayer = document.createElement("canvas"),
		width = 223,
		height = 314;
		
  var top_level_div = document.getElementById('tables');
  var count = top_level_div.getElementsByTagName('div').length;
  
	
	container.appendChild(table);
	container.appendChild(arrowLayer);
	container.style.width = width + "px";
	container.style.height = height + "px";
	container.style.display = "inline-block";
    document.getElementById("tables").appendChild(container);
	
	table.width = width;
    table.height = height;
    table.className = "table";
	table.style.zIndex = "0";
	drawTable(table);
	
	arrowLayer.width = width;
    arrowLayer.height = height;
	arrowLayer.className = "arrow";
    arrowLayer.style.zIndex = "1";
	arrowLayer.id = "arrow1"+count;
  
  
  
}



function removeTable() {
    "use strict";
    var child = document.getElementById("tables").lastChild;
    child.parentNode.removeChild(child);
}

function drawArrow(start_x, start_y, end_x, end_y) {
    "use strict";
  var top_level_div = document.getElementById('tables');
  var count = top_level_div.getElementsByTagName('div').length;
    //alert(count);
  count = count-1;
    var draw = document.getElementById('arrow1'+count).getContext('2d'),
		angle = Math.atan((end_y - start_y) / (end_x - start_x)),
		length = Math.sqrt(Math.pow((end_x - start_x), 2) + Math.pow((end_y - start_y), 2));
	
	// set colors and style
  draw.strokeStyle = "#ffb900";
	draw.fillStyle = "#ffb900";
	draw.lineWidth = 9;
		
	// draw arrow line
    draw.beginPath();
	  draw.translate(start_x, start_y);
    draw.moveTo(0, 0);
    draw.rotate(angle);
    draw.lineTo(length - 23, 0); // note: arrowhead is 24px long and total arrow is line+head	
    draw.stroke();
	  draw.moveTo(-start_x, -start_y);
	
	// draw arrow head
	draw.beginPath();
	draw.moveTo(length, 0);
	draw.lineTo(length - 24, -7.5); // ^ see note above
	draw.lineTo(length - 24, 7.5);
	draw.fill();
	
	//reset context
    draw.rotate(-angle);
    draw.moveTo(-start_x, -start_y);
    draw.translate(-start_x, -start_y);
}
&#13;
body {
    background-color: #982439;
}

#table {
    padding: 10px;
}

canvas {
	position: absolute;
}
&#13;
<button onclick="addTable()">Add table</button>
<button onclick="removeTable()">Remove table</button>
<button onclick="drawArrow(42, 25, 186, 293)">Draw arrow</button>
<button onclick="drawArrow(41, 290, 186, 20)">Draw arrow2</button>
</br>
<div id="tables">
</div>
&#13;
&#13;
&#13;

希望此代码可以帮助您