- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试为乒乓球运动图形编写生成器。我希望它为练习的每个集会显示一个表格,上面有箭头显示球的移动路径和比赛区域的矩形。
现在它看起来像这样:https://codepen.io/graNite/pen/grqXOo
您可以添加新表格,删除最后一个表格,并在第一个表格的同一 Canvas 层上绘制两个固定箭头。
我想要启用的是通过单击并拖动在每个表上绘制箭头*,然后右键单击它们将其删除。
*(就像它们是在 drawArrows 函数中绘制的一样)
执行此操作的最佳方法是什么?
我已经为箭头实现了一个 Canvas 层,甚至可以为每个表上的每个箭头都这样做,但是如果我右键单击它以删除它,我如何访问中间层中的箭头?
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);
}
最佳答案
良好的界面设计
高质量的界面不应该有丑陋的按钮,它应该直观易用。应该始终有反馈(光标、突出显示、翻转效果)。这些效果不是为了展示,而是为了提供用户与应用程序交互所需的信息。因此,FX 不必是主要的,只要足以让用户看到一切正常,什么是可点击的,什么是不可点击的。
我本来打算在没有帮助的情况下添加它,因为它应该有意义,但我已经添加了帮助以防万一。我们对界面的使用都有不同的方法。
更新:我添加了更多代码。现在仅在使用帮助功能之前显示帮助。一旦使用帮助不显示。
通过代码在我认为需要的地方(基本上所有地方)添加了注释
代码
表在数组 tableArray
中。使用返回表对象的 addTable()
添加表。表默认为非事件 table.active=false
。要激活,请在表格上单击鼠标或 table.active = true; table.draw();
箭头在数组 table.arrows
中为 {x:?,y?,xx:?,yy:?,highlight:false}
删除使用数组拼接或通过接口(interface)。要删除表格,请将其停用 table.active = false;
(或单击关闭)它将保留在 DOM 中,直到调用 updateTables()
。 (当用户鼠标点击更新关闭时自动调用)
总会有一个可见的非事件表,可用于添加事件表。
数组中的每个表都有完成其任务所需的一切。鼠标事件、渲染事件、关闭等
每个表格都以全帧速率呈现(当它具有内部鼠标焦点时),因此您可以根据需要添加漂亮的动画。当鼠标不在 Table 上时,它不会更新,除非您调用 table.draw()
函数。
代码有点乱,有点失控。常量定义了大多数东西(在代码的顶部)。表格、关闭图标和空表格是预呈现的。根据需要呈现箭头和帮助。
使用
单击空表以添加(激活)。单击事件表关闭图标以关闭。单击拖动添加箭头,在箭头附近单击鼠标右键删除。鼠标附近的箭头将突出显示。
Note The number of tables has no restriction. This is not a good idea and you should limit the number of tables. Also there is a bit of a layout issue when added tables cause page scroll bars to appear. Removing tables does not revert to what was. As I do not know what you want I left that for you to sort out.
Also added
GLOBAL_SCALE
const that is applied to all constants just for the fun of it so it is a little smaller that the original
// 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>
关于javascript - 如何在一个 Canvas 上启用绘制和删除多个元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38942605/
我知道如何通过iPhone开发创建sqlite数据库、向其中插入数据、删除行等,但我试图以编程方式删除整个数据库本身,但没有得到任何帮助。请有人指导我如何通过代码从设备中删除/删除整个 sqlite
请帮助指导如何在 Teradata 中删除数据库。 当我运行命令DROP DATABASE database_name时,我收到错误消息: *** Failure 3552 Cannot DROP d
Azure 警报规则的删除命令似乎不起作用,尝试了下面的方法,它返回状态为无内容,并且警报未被删除 使用的命令Remove-AzAlertRule -ResourceGroup "RGName"-Na
我在 flex 搜索中为大约50000个视频建立了索引,但是当它达到52000左右时,所有数据都被删除。嗯,这对我来说真的很奇怪,我没有为ES设置任何Heap大小或最小或最大大小的内存大小,因此它们没
我正在处理的问题是表单错误“输入由字母、数字、下划线或连字符组成的有效‘slug’。” 以下是我的表单字段验证: def clean_slug(self): slug = self.c
阅读文档,我希望 $("#wrap2").remove(".error") 从 中删除所有 .error 元素#wrap2。然而看看这个 JSFiddle: http://jsfiddle.net/h
嗨,我第一次尝试发现 laravel 我从 laravel 4.2 开始,我刚刚创建了一个新项目,但我误以为我写了这样的命令行 composer create-project laravel/lara
我已经在网上搜索了很长一段时间,但我找不到如何完全删除 apache 2.4 。 使用: Windows 7 c:\apache24\ 我已经尝试了所有命令,但没有任何效果。 httpd -k shu
可能是一个简单的答案,所以提前道歉(最少的编码经验)。 我正在尝试从任何列中删除具有特定字符串(经济 7)的任何行,并且一直在尝试离开此线程: How to drop rows from pandas
有几种方法可以删除/移除 vector 中的项目。 我有一个指针 vector ,我需要在类的析构函数中删除所有指针。 什么是最有效/最快甚至最安全的方式? // 1º std::for_each(v
我安装了一个 VNC 服务器并在某处阅读了我必须安装 xinetd 的信息。稍后我决定删除 VNC 服务器,所以我也删除了 xinetd。似乎 xinetd 删除了一些与 plesk 相关的文件,如果
我制作了一个从我们的服务器下载视频的应用。问题是: 当我取消下载时,我打电话: myAsyncTask.cancel(true) 我注意到,myAsyncTask 并没有在调用取消时停止...我的 P
是否可以在使用DELETE_MODEL删除模型之前检查模型是否存在我试图避免在尝试删除尚未创建的模型时收到错误消息。基本上我正在寻找对应的: DROP TABLE IF EXISTS 但对于模型。 最
我已经有了这个代码: 但它仍然会生成一个表行条目。 我想做的是,当输入的数量为0时,表行将被删除。请耐心等待,因为我是 php 和 mySQL 编码新手。 最佳答案 您忘记执行查询。应该是 $que
在 SharePoint 中,如果您删除/修改重复日历条目的单次出现,则不会真正删除/修改任何内容 - 相反,会创建一个新条目,告诉 SP 对于特定日期,该事件不存在或具有新参数. 因此,这可以通过删
在 routes.php 中我有以下路由: Route::post('dropzone', ['as' => 'dropzone.upload', 'uses' => 'AdminPhotoContr
在我的应用程序中,我正在尝试删除产品。当我第一次删除产品时,它会成功并且 URL 更改为/remove_category/15。我正在渲染到同一页面。现在,当我尝试删除另一个产品时,网址更改为/rem
这个问题被问了很多次,但给出的答案都是 GNU sed 特定的。 sed -i '' "/${FIND}/,+2d""$FILE" 给出“预期的上下文地址”错误。 有人可以给我一个例子,说明如何使用
在使用 V3 API 时,我找不到任何方法来删除和清理 Google map 。 我已经在 AJAX 站点中运行它,所以我想完全关闭它而无需重新加载页面。 我希望有一个 .unload() 或 .de
是否可以创建一个 Azure SQL 数据库用户来执行以下操作: 针对所有表和 View 进行 SELECT 创建/更改/删除 View 但用户不应该不拥有以下权限: 针对任何表或 View 插入/更
我是一名优秀的程序员,十分优秀!