2016-08-14 66 views
3

我想編碼乒乓球鍛鍊圖形的生成器。 我想讓它爲每個練習的集會顯示一張桌子,其上的箭頭顯示了球的運動路徑和要玩的區域的矩形。如何在一個畫布上啓用繪圖和刪除多個元素?

現在它看起來是這樣的: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); 
} 
+0

看到這個以前的[Q&A]( http://stackoverflow.com/questions/29692134/how-to-delete-only-a-line-from-the-canvas-not-all-the-drawings/29704300#29704300)找到哪條線最接近你的老鼠。然後按照您的設計要求處理該線。 – markE

回答

2

良好的界面設計

良好的品質界面不應該有醜陋的按鈕,它應該是直觀的 使用方便。應始終有反饋(光標,突出顯示,翻轉效果)。這些效果不如展示效果好,而是提供用戶需要與應用程序交互的信息。因此,FX不一定非常重要,只是讓用戶看到一切正在運行,什麼是可點擊的,什麼不是。

我打算在沒有幫助的情況下添加它,因爲它應該是有意義的,但我已經添加了幫助,只是將它不包含在內。我們都有不同的接口使用方法。

更新:我添加了一些更多的代碼。現在只顯示幫助,直到使用幫助功能。一旦使用幫助不顯示。雖然代碼

補充意見,我認爲這需要它(basicly無處不在)

代碼

表是在一個數組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常量所以這是一個有點小,原來

// 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 { 
 
\t position: absolute; 
 
}
<div id="tables"> 
 
</div>

+0

非常感謝,這正是我一直在尋找的。我有一些問題,可以問問他們在這裏嗎? – Tweakimp

+0

@Tweakimp是的,所有人都會問。​​這就是評論的意思。 – Blindman67

+0

1)這個自定義光標url是什麼?如果我想用我自己的光標,我可以用一個指向root/img/cursorimg.png的鏈接來替換它嗎? 2)在處理不同的屏幕尺寸時,全球尺度可能會派上用場。我可以檢測用戶的分辨率,爲他選擇正確的全球範圍嗎?3)我正在通過代碼來理解它,併合並一些我在此期間編碼的東西。你爲什麼使用const?不能我只是使用var的所有變量? – Tweakimp

0

你USI在你的代碼的問題ng的靜態ID是錯誤的,你需要計算表或div,然後你需要傳遞該ID與ID。

我熱固性酚醛樹脂這一問題檢查代碼:

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"), 
 
\t \t table = document.createElement("canvas"), 
 
\t \t arrowLayer = document.createElement("canvas"), 
 
\t \t width = 223, 
 
\t \t height = 314; 
 
\t \t 
 
    var top_level_div = document.getElementById('tables'); 
 
    var count = top_level_div.getElementsByTagName('div').length; 
 
    
 
\t 
 
\t container.appendChild(table); 
 
\t container.appendChild(arrowLayer); 
 
\t container.style.width = width + "px"; 
 
\t container.style.height = height + "px"; 
 
\t container.style.display = "inline-block"; 
 
    document.getElementById("tables").appendChild(container); 
 
\t 
 
\t table.width = width; 
 
    table.height = height; 
 
    table.className = "table"; 
 
\t table.style.zIndex = "0"; 
 
\t drawTable(table); 
 
\t 
 
\t arrowLayer.width = width; 
 
    arrowLayer.height = height; 
 
\t arrowLayer.className = "arrow"; 
 
    arrowLayer.style.zIndex = "1"; 
 
\t 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'), 
 
\t \t angle = Math.atan((end_y - start_y)/(end_x - start_x)), 
 
\t \t length = Math.sqrt(Math.pow((end_x - start_x), 2) + Math.pow((end_y - start_y), 2)); 
 
\t 
 
\t // set colors and style 
 
    draw.strokeStyle = "#ffb900"; 
 
\t draw.fillStyle = "#ffb900"; 
 
\t draw.lineWidth = 9; 
 
\t \t 
 
\t // draw arrow line 
 
    draw.beginPath(); 
 
\t 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 \t 
 
    draw.stroke(); 
 
\t draw.moveTo(-start_x, -start_y); 
 
\t 
 
\t // draw arrow head 
 
\t draw.beginPath(); 
 
\t draw.moveTo(length, 0); 
 
\t draw.lineTo(length - 24, -7.5); //^see note above 
 
\t draw.lineTo(length - 24, 7.5); 
 
\t draw.fill(); 
 
\t 
 
\t //reset context 
 
    draw.rotate(-angle); 
 
    draw.moveTo(-start_x, -start_y); 
 
    draw.translate(-start_x, -start_y); 
 
}
body { 
 
    background-color: #982439; 
 
} 
 

 
#table { 
 
    padding: 10px; 
 
} 
 

 
canvas { 
 
\t position: absolute; 
 
}
<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>

希望這個代碼將有助於你

+0

對不起,但這也不允許我通過點擊拖動來繪製箭頭,也不能通過右鍵點擊來刪除它們。 – Tweakimp

相關問題