如何从画布中仅删除一行,而不是所有图纸?

时间:2015-04-17 06:45:50

标签: javascript html5 qt canvas qml

我找到的解决方案是clear the whole canvas,但我只想删除一行而不是画布上的所有绘图。

我该怎么办?

3 个答案:

答案 0 :(得分:3)

@danielfranca是正确的,绘制在画布上的一行变为“画布的像素海中的未记忆像素。”

他也是正确的,在绘制每条线时保存画布的快照图像并恢复到其中一个保存的图像以“删除”一条线是资源密集型的。 (不要使用那种技术!!)

但是,有一种有效的方法可以删除画布上以前绘制的线条!

是的,它确实清除了画布并重新绘制了线条,但它非常快且&有效......我保证!

以下是如何操作的概述:

  • 在对象内定义一条线,如下所示:{ x0:10, y0:15, x1:100, y1:75 }

  • 根据需要制作尽可能多的行并将其推入数组:var lines=[];

  • 使用lines []数组中的线条定义将线条绘制到画布上。

  • 倾听mousemovemousedown事件。

  • 在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 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>

答案 1 :(得分:2)

没有简单的方法可以做到这一点,因为在绘制任何内容之后,像素的先前信息会丢失。 在这里,您有一个更好的答案:clear line on HTML5 Canvas

  

在绘制内容时,在计算机图形学中,绘制到缓冲区。和   当你调用lineTo并且中断缓冲区时会更新所有内容   基础像素中的信息丢失(或部分丢失)   如果你使用透明度会丢失,而且没有办法让它回来   撤消(除非有一个包含旧的负载的实现   图纸,但这对记忆来说真的很重。)

     

因此,能够撤消中风可能会节省大量的CPU / GPU时间   会大大增加记忆力

所以唯一的方法似乎是使用clearRect。

答案 2 :(得分:0)

也许你会试试javascript绘图库。例如,oCanvas库可以绘制更多面向对象的库。有一个remove函数可以从画布中删除绘制的对象。