那里已经有 AngularJS 的画布绘图指令了吗?

Posted

技术标签:

【中文标题】那里已经有 AngularJS 的画布绘图指令了吗?【英文标题】:Is there already a canvas drawing directive for AngularJS out there? 【发布时间】:2013-05-11 09:03:29 【问题描述】:

是否已经有在画布上绘制/绘制东西的指令?所以你可以实现像 Paint 这样的东西,甚至像 Photoshop 等更大的东西,但是一个非常基本的例子就足够了。

我在搜索中没有找到一个,如果已经有一个被认为是最佳实践,我想使用它。否则我必须自己实现一个。

【问题讨论】:

Angular 旨在创建数据管理 (CRUD) 应用程序 - 对于画布应用程序,您应该尝试其他方法,例如:createjs.com/#!/EaselJS 【参考方案1】:

Angular 非常适合以声明式风格编写应用程序。一旦你点击了画布元素,你就不能再使用声明性了,你必须转向一种命令式的编写机制。如果您的应用程序的大部分都提供 UI,您在应用程序的其余部分中用 html 定义它,我强烈建议您使用 AngularJS。它是一个了不起的框架。

另一方面,如果您的大部分代码都将位于 canvas 元素中,那么 AngularJS 可能不是您的理想工具。如果你真的坚持在你的大部分应用程序中使用 AngularJS,我建议你考虑使用像 D3 这样的东西,这是一个很好的替代方案,并在幕后使用 SVG(它本质上是声明性的,因此是 AngularJS 的一个很好的搭档)。

【讨论】:

我知道,我有一个主要是声明性的应用程序。大多数东西不需要画布。但是我还有一个需要在画布上绘制兼容性的功能......我想也许已经有一些东西可以在指令中完成。或者在指令中导入其他绘图库,但如果不是这种情况,我必须自己弄清楚。 上述答案具有误导性。 AngularJS(和声明式编程)不会妨碍画布的使用。关键在于你如何处理问题。许多流行的图表和图形 JS 库开始通过为其组件提供指令来支持 AngularJS。因此,命令式代码隐藏在指令的可重用实现中。这就是 AngularJS 的美妙之处,您只需编写一次命令式代码并以声明方式使用它,如下面的解决方案所示。 答案没有误导性。如果您编写了一堆 JQuery 意大利面条并将其全部隐藏在指令的构造函数中,那么您还没有“编写 Angular 指令”。你写了一堆命令式的垃圾,并通过以 类似于 Angular 的方式组织它来安慰自己。这就是 本可以用 Angular 正确编写的代码。但是没有 $digest 循环可以监控画布的状态,也没有像 2-way Angular 数据绑定到画布这样的东西。您可以通过将命令式画布代码包装在指令中来假装。但这不会使它成为 Angular。 这里有一个不错的 D3 Angular 教程:ng-newsletter.com/posts/d3-on-angular.html 为什么不能使用声明式? <cool-canvas><canvas-line x1="10" y1="10" x2="20 y2="10" stroke-style=vm.strokeStyle></canvas-line></cool-canvas> canvas-line 是cool-canvas 需要的指令(在许多情况下很像ng-model),而cool-canvas 是(当然)管理它的孩子的指令。【参考方案2】:

好的,我做了一个,实际上很简单:

app.directive("drawing", function()
  return 
    restrict: "A",
    link: function(scope, element)
      var ctx = element[0].getContext('2d');

      // variable that decides if something should be drawn on mousemove
      var drawing = false;

      // the last coordinates before the current move
      var lastX;
      var lastY;

      element.bind('mousedown', function(event)
        if(event.offsetX!==undefined)
          lastX = event.offsetX;
          lastY = event.offsetY;
         else  // Firefox compatibility
          lastX = event.layerX - event.currentTarget.offsetLeft;
          lastY = event.layerY - event.currentTarget.offsetTop;
        

        // begins new line
        ctx.beginPath();

        drawing = true;
      );
      element.bind('mousemove', function(event)
        if(drawing)
          // get current mouse position
          if(event.offsetX!==undefined)
            currentX = event.offsetX;
            currentY = event.offsetY;
           else 
            currentX = event.layerX - event.currentTarget.offsetLeft;
            currentY = event.layerY - event.currentTarget.offsetTop;
          

          draw(lastX, lastY, currentX, currentY);

          // set current coordinates to last one
          lastX = currentX;
          lastY = currentY;
        

      );
      element.bind('mouseup', function(event)
        // stop drawing
        drawing = false;
      );

      // canvas reset
      function reset()
       element[0].width = element[0].width; 
      

      function draw(lX, lY, cX, cY)
        // line from
        ctx.moveTo(lX,lY);
        // to
        ctx.lineTo(cX,cY);
        // color
        ctx.strokeStyle = "#4bf";
        // draw it
        ctx.stroke();
      
    
  ;
);

然后你可以像这样在画布上使用它:

<canvas drawing></canvas>

这是 Plunkr 上的演示:http://plnkr.co/aG4paH

【讨论】:

reset函数对赋值做了什么 element[0].width = element[0].width; ? 嗯,实际上,我忘记了,它与重置一些变换矩阵有关......我不记得了。编辑:啊,我在这里找到了,这是清除画布的功能:***.com/questions/2142535/… 我还在 JsPerf 中为画布清理写了一个测试用例:因为我知道清理画布的两种方法:jsperf.com/canvas-clearing-test 我将此添加到我的 Angular/Common 存储库中,并进行了一些增强:clouddueling.github.io/angular-common 在上面更新了它,可以在 firefox 和 plunker 中使用【参考方案3】:

前段时间我为此构建了一个可配置的指令。

https://github.com/pwambach/angular-canvas-painter

该指令创建画布元素并向元素添加 mousedown/mousemove/mouseup 事件(以及相应的触摸事件)的处理程序。 Mousedown 和跟随 mousemove 事件绘制贝塞尔曲线 canvasContext.quadraticCurveTo() 使笔触更平滑的方法(而不仅仅是为每个点画圆)。绘图算法的详细内容可以看这篇文章:http://codetheory.in/html5-canvas-drawing-lines-with-smooth-edges/

【讨论】:

虽然这在理论上可以回答问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。【参考方案4】:

这是一个非常好的实现!如果您想在图像上转换画布,我可以添加该方法

    function convertCanvasToImage(canvas) 
       var image = new Image();
       image.src = canvas.toDataURL("image/png");
       return image;
    

这将使您成为一个图像标签,其来源为 base64 元素。

希望对你有帮助

【讨论】:

以上是关于那里已经有 AngularJS 的画布绘图指令了吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何构建 AngularJS 和 PaperJS 项目

AngularJS:如何将参数/函数传递给指令?

尽管设置了属性,但画布绘图未正确绘制

Python绘图之(1)Turtle库详解

Angular.js 和 Fabric.js:一旦代码移动到 Angular 指令,Fabric 画布就会改变行为

将画布中的绘图保存到本地文件夹