【问题标题】:HTML5 Canvas - Draw on Canvas, Save Context and Restore it laterHTML5 Canvas - 在 Canvas 上绘图,保存上下文并稍后恢复
【发布时间】:2014-12-21 00:30:51
【问题描述】:

要求:

现在:在 Canvas 上绘图,然后点击 Save(离线存储 Canvas 状态/绘图 - 但不作为图像)。
稍后:打开先前保存的绘图显示的画布,并继续再次绘制。

对于绘图,我们通常使用如下代码:

canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
...
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
....

为了稍后恢复 Canvas 状态 - 导出到 Image 没有帮助。
我想将画布恢复到其原始状态,以便以后继续编辑绘图。

我猜,Canvas 上下文必须离线导出和存储 - 怎么做?

【问题讨论】:

    标签: javascript html canvas html5-canvas


    【解决方案1】:

    您最好的方法是使用既存储绘图命令又执行绘图的代理。
    由于浏览器对 Proxy 的支持很差(目前只有 FF),你必须自己构建 Proxy,要么使用 nosuchmethod,要么构建一个全新的全新 WatchedContext 类Context2D。
    我为这个简短的演示采用了最后一个解决方案(WatchedContext 类):

    function WatchedContext(hostedCtx) {
      this.commands= [];
      Context2dPrototype = CanvasRenderingContext2D.prototype;
      for (var p in Context2dPrototype ) {
        this[p] = function(methodName) {
            return function() {
                this.commands.push(methodName, arguments);
                return Context2dPrototype[methodName].apply(hostedCtx, arguments);
            }      
        }(p);
      }  
      this.replay=function() {
        for (var i=0; i<this.commands.length; i+=2) {
          var com = this.commands[i];
          var args = this.commands[i+1];
          Context2dPrototype[com].apply(hostedCtx, args);
        }
      }
    }
    

    显然您可能需要一些其他方法(开始/停止录制、清除、...)

    只是一个使用的小例子:

    var cv = document.getElementById('cv');
    var ctx=cv.getContext('2d');
    var watchedContext=new WatchedContext(ctx);
    
    // do some drawings on the watched context
    // --> they are performed also on the real context
    watchedContext.beginPath();
    watchedContext.moveTo(10, 10);
    watchedContext.lineTo(100, 100);
    watchedContext.stroke();
    
    // clear context (not using the watched context to avoid recording)
    ctx.clearRect(0,0,100,1000);
    
    // replay what was recorded
    watchedContext.replay();
    

    你可以在这里看到:

    http://jsbin.com/gehixavebe/2/edit?js,output
    

    重播确实有效,并且由于重播存储的命令而重新绘制线。

    对于离线存储,您可以使用 localStorage 将命令存储在本地,也可以使用 AJAX 调用或类似方法将它们远程存储在服务器上。

    【讨论】:

    • 一个好的开始——非常值得+1!为了完整起见,您的代码需要扩展以考虑上下文属性和返回值的上下文方法。您可以使用 Object.defineProperty 为上下文属性创建 getter/setter。大多数上下文方法都可以用您的代码很好地序列化,但某些上下文方法需要特殊处理:.drawImage(序列化 URL)、.createLinearGradient、.createRadialGradient、.createPattern、.measureText。使用 .getImageData 和 .putImageData 进行像素操作需要整个子系统。还是……干得好!
    • @markE :感谢您的友好和相关的 cmets。我在这里的目的是写一个“简短的演示”,即展示解决问题的方法,然后等待 O.P. 的 cmets 在(可能)更进一步之前。对于一些方法(比如createPattern,仅举一个例子),上面的逻辑确实需要大量的返工。但只是对于一些基本的绘图,包括更改填充/笔触/字体,我做了一些更改以允许访问属性,最新尝试在这里:jsfiddle.net/gamealchemist/b4bfj6uf
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 2011-01-23
    • 1970-01-01
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多