如何只删除canvas中的一行,而不是所有的图纸?
How to delete only a line from the canvas, not all the drawings?
我找到的解决办法是clear the whole canvas,但我只想删除一行而不是canvas上的所有绘图。
我该怎么办?
或许您可以试试 javascript 绘图库。例如,oCanvas library, where you draw more object oriented. There is a remove 函数可以从 canvas.
中删除绘制的对象
没有简单的方法可以做到这一点,因为在绘制任何内容后像素的先前信息都会丢失。
这里有一个更好的答案:clear line on HTML5 Canvas
In computer graphics when drawing something, you draw to a buffer. And
when you call lineTo and stroke the buffer is updated and all
information that were in the underlying pixels are lost (or partly
lost if you use transparency) and there is no way to get it back by
undoing (unless there is an implementation containing loads of old
drawings, but that would be really heavy for the memory).
So to be able to undo a stroke might save alot of CPU/GPU time BUT
whould heavily increase the memory
所以唯一的方法似乎是使用 clearRect。
@danielfranca 是正确的,画在 canvas 上的线变成 "unremembered pixels in the canvas's sea of pixels."
他也说得对,在绘制每条线时保存 canvas 的快照图像并将这些保存的图像之一还原为 "delete" 线是资源密集型的。 (不要使用那种技巧!!)
但是,有一种有效的方法可以删除之前在 canvas!
上绘制的线条
是的,它确实清除了 canvas 并重画了线条,但它非常快速和高效......我保证!
以下是如何操作的概述:
像这样在对象内定义一条线:{ x0:10, y0:15, x1:100, y1:75 }
根据需要制作尽可能多的行并将它们放入数组中:var lines=[];
使用 lines[] 数组中的线定义将线绘制到 canvas。
侦听 mousemove
和 mousedown
事件。
在 mousemove 上,遍历 lines[] 并找到离鼠标最近的线。这是计算哪条线最接近给定 [mx,my]:
的算法片段
// Find the index of the line closest to mx,my
function setClosestLine(mx,my) {
//
closestLineIndex=-1;
var minDistanceSquared=100000000;
//
// examine each line &
// determine which line is closest to the mouse (mx,my)
for(var i=0;i<lines.length;i++){
var line=lines[i];
var dx=line.x1-line.x0;
var dy=line.y1-line.y0;
var t=((mx-line.x0)*line.dx+(my-line.y0)*line.dy)/line.dx2dy2;
var x=lerp(line.x0, line.x1, t);
var y=lerp(line.y0, line.y1, t);
var dx1=mx-x;
var dy1=my-y;
var distSquared=dx1*dx1+dy1*dy1;
if(distSquared<minDistanceSquared){
minDistanceSquared=distSquared;
closestLineIndex=i;
closestX=x;
closestY=y;
}
}
};
在 mousedown 上,使用 lines.splice(targetIndex,1)
从 lines[] 数组中删除最近的线的定义。然后清除canvas并重新绘制剩余的线。
这是带注释的代码和演示:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
ctx.lineWidth=2;
// linear interpolation -- needed in setClosestLine()
var lerp=function(a,b,x){ return(a+x*(b-a)); };
// vars to track which line is closest to the mouse
var closestLineIndex=-1;
var closestX,closestY;
// make some random lines and save them in lines[]
var n=5;
var lines=[];
var randomX=function(){return(Math.random()*cw*.67);}
var randomY=function(){return(Math.random()*ch*.67);}
var lastX=randomX();
var lastY=randomY();
for(var i=0;i<n;i++){
var x=Math.random()*cw*.67;
var y=Math.random()*ch*.67;
var dx=x-lastX;
var dy=y-lastY;
var line={
x0:lastX,
y0:lastY,
x1:x,
y1:y,
weight:Math.round(Math.random()*20),
// precalc often used values
dx:dx,
dy:dy,
dx2dy2:dx*dx+dy*dy,
};
lines.push(line);
lastX=x;
lastY=y;
}
redraw();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
//////////////////////////////
// functions
// Find the index of the line closest to mx,my
function setClosestLine(mx,my) {
//
closestLineIndex=-1;
var minDistanceSquared=100000000;
//
// examine each line &
// determine which line is closest to the mouse (mx,my)
for(var i=0;i<lines.length;i++){
var line=lines[i];
var dx=line.x1-line.x0;
var dy=line.y1-line.y0;
var t=((mx-line.x0)*line.dx+(my-line.y0)*line.dy)/line.dx2dy2;
var x=lerp(line.x0, line.x1, t);
var y=lerp(line.y0, line.y1, t);
var dx1=mx-x;
var dy1=my-y;
var distSquared=dx1*dx1+dy1*dy1;
if(distSquared<minDistanceSquared){
minDistanceSquared=distSquared;
closestLineIndex=i;
closestX=x;
closestY=y;
}
}
};
// clear & redraw all lines
function redraw(){
// clear the canvas
ctx.clearRect(0,0,cw,ch);
// draw all lines
ctx.strokeStyle='black';
for(var i=0;i<lines.length;i++){
var line=lines[i];
ctx.beginPath();
ctx.moveTo(line.x0,line.y0);
ctx.lineTo(line.x1,line.y1);
ctx.stroke();
}
// draw the line closest to the mouse in red
if(closestLineIndex<0){return;}
var line=lines[closestLineIndex];
ctx.strokeStyle='red';
ctx.beginPath();
ctx.moveTo(line.x0,line.y0);
ctx.lineTo(line.x1,line.y1);
ctx.stroke();
}
// On mousemove, find line closest to mouse
function handleMouseMove(e){
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
setClosestLine(mouseX,mouseY);
redraw();
}
// On mousedown, remove line that was closest to mouse
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
if(closestLineIndex>=0){
lines.splice(closestLineIndex,1);
redraw();
}
}
body {
background-color: ivory;
}
#canvas {
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Closest line to mouse is drawn in red<br>Click to remove that line.</h4>
<canvas id="canvas" width=300 height=300></canvas>
我找到的解决办法是clear the whole canvas,但我只想删除一行而不是canvas上的所有绘图。
我该怎么办?
或许您可以试试 javascript 绘图库。例如,oCanvas library, where you draw more object oriented. There is a remove 函数可以从 canvas.
中删除绘制的对象没有简单的方法可以做到这一点,因为在绘制任何内容后像素的先前信息都会丢失。 这里有一个更好的答案:clear line on HTML5 Canvas
In computer graphics when drawing something, you draw to a buffer. And when you call lineTo and stroke the buffer is updated and all information that were in the underlying pixels are lost (or partly lost if you use transparency) and there is no way to get it back by undoing (unless there is an implementation containing loads of old drawings, but that would be really heavy for the memory).
So to be able to undo a stroke might save alot of CPU/GPU time BUT whould heavily increase the memory
所以唯一的方法似乎是使用 clearRect。
@danielfranca 是正确的,画在 canvas 上的线变成 "unremembered pixels in the canvas's sea of pixels."
他也说得对,在绘制每条线时保存 canvas 的快照图像并将这些保存的图像之一还原为 "delete" 线是资源密集型的。 (不要使用那种技巧!!)
但是,有一种有效的方法可以删除之前在 canvas!
上绘制的线条是的,它确实清除了 canvas 并重画了线条,但它非常快速和高效......我保证!
以下是如何操作的概述:
像这样在对象内定义一条线:
{ x0:10, y0:15, x1:100, y1:75 }
根据需要制作尽可能多的行并将它们放入数组中:
var lines=[];
使用 lines[] 数组中的线定义将线绘制到 canvas。
侦听
mousemove
和mousedown
事件。在 mousemove 上,遍历 lines[] 并找到离鼠标最近的线。这是计算哪条线最接近给定 [mx,my]:
的算法片段// Find the index of the line closest to mx,my function setClosestLine(mx,my) { // closestLineIndex=-1; var minDistanceSquared=100000000; // // examine each line & // determine which line is closest to the mouse (mx,my) for(var i=0;i<lines.length;i++){ var line=lines[i]; var dx=line.x1-line.x0; var dy=line.y1-line.y0; var t=((mx-line.x0)*line.dx+(my-line.y0)*line.dy)/line.dx2dy2; var x=lerp(line.x0, line.x1, t); var y=lerp(line.y0, line.y1, t); var dx1=mx-x; var dy1=my-y; var distSquared=dx1*dx1+dy1*dy1; if(distSquared<minDistanceSquared){ minDistanceSquared=distSquared; closestLineIndex=i; closestX=x; closestY=y; } } };
在 mousedown 上,使用
lines.splice(targetIndex,1)
从 lines[] 数组中删除最近的线的定义。然后清除canvas并重新绘制剩余的线。
这是带注释的代码和演示:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
ctx.lineWidth=2;
// linear interpolation -- needed in setClosestLine()
var lerp=function(a,b,x){ return(a+x*(b-a)); };
// vars to track which line is closest to the mouse
var closestLineIndex=-1;
var closestX,closestY;
// make some random lines and save them in lines[]
var n=5;
var lines=[];
var randomX=function(){return(Math.random()*cw*.67);}
var randomY=function(){return(Math.random()*ch*.67);}
var lastX=randomX();
var lastY=randomY();
for(var i=0;i<n;i++){
var x=Math.random()*cw*.67;
var y=Math.random()*ch*.67;
var dx=x-lastX;
var dy=y-lastY;
var line={
x0:lastX,
y0:lastY,
x1:x,
y1:y,
weight:Math.round(Math.random()*20),
// precalc often used values
dx:dx,
dy:dy,
dx2dy2:dx*dx+dy*dy,
};
lines.push(line);
lastX=x;
lastY=y;
}
redraw();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
//////////////////////////////
// functions
// Find the index of the line closest to mx,my
function setClosestLine(mx,my) {
//
closestLineIndex=-1;
var minDistanceSquared=100000000;
//
// examine each line &
// determine which line is closest to the mouse (mx,my)
for(var i=0;i<lines.length;i++){
var line=lines[i];
var dx=line.x1-line.x0;
var dy=line.y1-line.y0;
var t=((mx-line.x0)*line.dx+(my-line.y0)*line.dy)/line.dx2dy2;
var x=lerp(line.x0, line.x1, t);
var y=lerp(line.y0, line.y1, t);
var dx1=mx-x;
var dy1=my-y;
var distSquared=dx1*dx1+dy1*dy1;
if(distSquared<minDistanceSquared){
minDistanceSquared=distSquared;
closestLineIndex=i;
closestX=x;
closestY=y;
}
}
};
// clear & redraw all lines
function redraw(){
// clear the canvas
ctx.clearRect(0,0,cw,ch);
// draw all lines
ctx.strokeStyle='black';
for(var i=0;i<lines.length;i++){
var line=lines[i];
ctx.beginPath();
ctx.moveTo(line.x0,line.y0);
ctx.lineTo(line.x1,line.y1);
ctx.stroke();
}
// draw the line closest to the mouse in red
if(closestLineIndex<0){return;}
var line=lines[closestLineIndex];
ctx.strokeStyle='red';
ctx.beginPath();
ctx.moveTo(line.x0,line.y0);
ctx.lineTo(line.x1,line.y1);
ctx.stroke();
}
// On mousemove, find line closest to mouse
function handleMouseMove(e){
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
setClosestLine(mouseX,mouseY);
redraw();
}
// On mousedown, remove line that was closest to mouse
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
if(closestLineIndex>=0){
lines.splice(closestLineIndex,1);
redraw();
}
}
body {
background-color: ivory;
}
#canvas {
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Closest line to mouse is drawn in red<br>Click to remove that line.</h4>
<canvas id="canvas" width=300 height=300></canvas>