如何清除画布中的特定行:HTML5

Posted

技术标签:

【中文标题】如何清除画布中的特定行:HTML5【英文标题】:How to clear specific line in Canvas : HTML5 【发布时间】:2014-07-31 04:55:13 【问题描述】:

我对这个 Canvas Element 完全陌生。我可以在画布上画线,但不能只清除特定线。整个画布变为空白。

试过这个: HTML:

<canvas id="cvs"  ></canvas>
<hr />
<input type="submit" id="reDrowA" value="Draw A" />
<input type="submit" id="reDrowB" value="Draw B" />
<hr />
<input type="submit" id="clearA" value="Clear A" />
<input type="submit" id="clearB" value="Clear B" />

脚本

$(document).ready(function()
    canvas =  document.getElementById("cvs");    
    $("#reDrowA").on("click",function()
        a = canvas.getContext('2d');
        a.translate(0.5, 0.5);
        a.beginPath();
        a.setLineDash([2,10]);
        a.moveTo(10,10);
        a.lineTo(300,10);
        a.lineTo(300,300);
        a.stroke();
    );
    $("#reDrowB").on("click",function()
        b = canvas.getContext('2d');
        b.translate(0.5, 0.5);
        b.beginPath();
        b.setLineDash([2,10]);
        b.moveTo(10,10);
        b.lineTo(10,300);
        b.lineTo(300,300);
        b.stroke();
    );
    $("#clearA").on("click",function()
       a.clearRect(0, 0, canvas.width, canvas.height);
    );
    $("#clearB").on("click",function()
        b.clearRect(0, 0, canvas.width, canvas.height);
    );

);

小提琴:http://jsfiddle.net/8YNvu/

【问题讨论】:

据我所知,您无法访问画布中的特定元素,您必须完全清除它。我不知道您的要求是什么,但如果您正在绘制图表之类的内容并想要访问单个项目、响应它的事件等,请查看 svg... 你不能那样做。画布是位图。你在上面画的所有东西都留在那里。之后您无法操作特定的图纸。您只能将其作为一个整体清除。如果您希望能够在画布上绘制“对象”并稍后对其进行操作并删除它们,您需要自己(在数组中)跟踪这些对象,然后有一个绘制函数定期更新画布并原始所有数组中的当前对象。要清除特定对象,只需将其从数组中清除并重绘即可。 所以要管理两行,我需要创建两个 Canvas 元素吗? 如果你想管理多行,你需要使用多个图层(画布)或(正如 HaukurHaf 上面的评论所说)注册你绘制的每一行,然后在你清除所有内容后 - 重新绘制你需要的行。 我们无法访问画布中的元素,我们必须清除并重绘所有画布元素。 【参考方案1】:

关于画布、画布“元素”以及“元素”的可见性...

当画布上的任何元素需要更改(移动、擦除等)时,标准方法是完全擦除画布并在新位置的元素重新绘制画布(或者如果元素被擦除,则不重新绘制元素)。

这是因为 canvas 不“记住”它在哪里绘制了任何单个元素,因此无法单独移动或擦除任何元素。

您可以“记住”有关元素的足够信息,以便在画布被擦除后重新绘制它。

演示:http://jsfiddle.net/m1erickson/Wrk2e/

因此,在您的示例中,您可以创建 javascript 对象 ab 来表示您的右上角和左下线路径。

每个对象都有定义其行路径的点和一个指示它是否可见的标志(可见 == 在画布上重绘)。

// create an object containing the top-right lines
// the object contains its path points & if it is visible or not
var a=
  path:[10,10, 300,10, 300,300],
  isVisible:false,


// create an object containing the left-bottom lines
// the object contains its path points & if it is visible or not
var b=
  path:[10,10, 10,300, 300,300],
  isVisible:false,

为了便于处理,您可以将所有行路径对象放在一个数组中:

// an array containing all the line-path objects
var myObjects=[a,b];

然后,当您清除画布时,您只需使用每个对象的行路径信息来重绘线条。如果特定对象可见性标志为false,则不要重绘该特定对象。

// clear the entire canvas 
// redraw any line-paths that are visible
function redrawAll(myObjects)
    context.clearRect(0,0,canvas.width,canvas.height);
    for(var i=0;i<myObjects.length;i++)
        if(myObjects[i].isVisible)
            drawLinePath(myObjects[i]);
        
    


// redraw 1 line-path
function drawLinePath(theObject)
    var points=theObject.path;
    // save the current untranslated context state
    context.save();

    // draw lines through each point in the objects path
    context.translate(0.5, 0.5);
    context.beginPath();
    context.setLineDash([2,10]);
    context.moveTo(points[0],points[1]);
    for(var i=2;i<points.length;i+=2)
        context.lineTo(points[i],points[i+1]);
    
    context.stroke();

    // restore the context to its untranslated state
    context.restore();

所有这些都到位后,您的按钮只需更改特定线路路径对象上的可见性标志,然后清除/重绘整个画布。

// use buttons to set & clear the visibility flags on objects
// In all cases, clear the entire canvas and redraw any visible objects

$("#reDrowA").on("click",function()
    a.isVisible=true;
    redrawAll(myObjects);
);
$("#reDrowB").on("click",function()
    b.isVisible=true;
    redrawAll(myObjects);
);
$("#clearA").on("click",function()
    a.isVisible=false;
    redrawAll(myObjects);
);
$("#clearB").on("click",function()
    b.isVisible=false;
    redrawAll(myObjects);
);

【讨论】:

我认为这是我正在寻找的完美解决方案。 为了完整起见,如果要清除特定的线条或形状(如我所做的),而不是矩形区域,您可以设置 context.globalCompositeOperation = "destination-out" -- 如在andrewmu 对similar question 的解决方案——基本上将使您的填充/笔划操作就像橡皮擦工具一样。看到这个compositing and clipping tutorial。不过,这不会删除分层元素。 @TheMadDeveloper。你提到了一个很好的后续观点。请记住,使用destination-out 合成擦除描边线有时是无效的,因为canvas 添加到线条上的抗锯齿通常不会被擦除。但是destination-out 对于context.fill 的效果很好。 :-) reactjs 的连续渲染解决了这个问题吗?【参考方案2】:

画布是透明的。无法acheive in single canvas tag。因为clearRect 功能可以根据宽度和高度进行清除。我们没有给出清除画布的确切位置。试试小提琴。你用两个画布标签实现了这个场景。

Fiddle

【讨论】:

非常感谢 @sudharsan。有一种更好的方法(也是一种更标准的方法)来处理像画布中的行路径这样的“元素”。请看我的帖子。 ;-)【参考方案3】:

您只需要re-paint the lines,在您清除画布后应该会持续存在。 可能是这样的: http://jsfiddle.net/8YNvu/10/

【讨论】:

我正在创建一些流程图类型的功能,所以我猜您提供的建议可能不起作用。用户可以在其中创建 N 条线和对象。在这种情况下,这将不起作用。如果我错了,请纠正我。

以上是关于如何清除画布中的特定行:HTML5的主要内容,如果未能解决你的问题,请参考以下文章

为什么我不能用HTML5中的另一个空画布清除画布?

裁剪画布/导出具有特定宽度和高度的 html5 画布

如何旋转 HTML5 画布的现有内容?

如何仅使用 HTML5 功能使画布移动?

如何将画布保存为html5中的图像?

html5画布精灵表随机行/列