【问题标题】:How to implement drag and drop for HTML5 Canvas painting application?HTML5 Canvas绘画应用如何实现拖放?
【发布时间】:2012-01-14 06:45:02
【问题描述】:

基于Creating an HTML 5 canvas painting application我创建了一个HTML5画布绘画应用程序。它工作正常,但在创建每个对象后,我只需要拖动对象。 Working demo

如何实现图形的拖放?

【问题讨论】:

    标签: javascript html canvas drag-and-drop html5-canvas


    【解决方案1】:

    当用户单击画布时,您必须检查坐标(将其与对象的坐标进行比较),并查看它是否在对象上。例如。您可以使用此方法测试一个点(例如 mousedown 的坐标)是否在一个圆圈内:

    function (pt) {
        return Math.pow(pt.x - point.x,2) + Math.pow(pt.y - point.y,2) < 
                                                                 Math.pow(radius,2); 
    };
    

    如果 mousedown 在对象上,则必须根据鼠标的移动方式更改对象坐标。

    这是一个示例,您可以在其中拖动一个圆圈:

    <!DOCTYPE html>
    <html>
    <head>
    <script>
    window.onload = function() {
        drawCircle(circle);
        element = document.getElementById('canvas');
        element.addEventListener('mousedown', startDragging, false);
        element.addEventListener('mousemove', drag, false);
        element.addEventListener('mouseup', stopDragging, false);
        element.addEventListener('mouseout', stopDragging, false);
    }
    
    function mouseX(e) {
    return e.clientX - element.offsetLeft;
    }
    
    function mouseY(e) {
    return e.clientY - element.offsetTop;
    }
    
    var Point = function (x, y) {
        this.x = x;
        this.y = y;
        return this;
    }
    
    var Circle = function (point, radius) {
        this.point = point;
        this.radius = radius;
        this.isInside = function (pt) {
            return Math.pow(pt.x - point.x, 2) + Math.pow(pt.y - point.y, 2) <
                                                              Math.pow(radius, 2); 
        };
        return this;
    }
    
    function startDragging(e) {
        var p = new Point(e.offsetX, e.offsetY);
        if(circle.isInside(p)) {
            deltaCenter = new Point(p.x - circle.point.x, p.y - circle.point.y);
        }
    }
    
    function drag(e) {
        if(deltaCenter != null) {
            circle.point.x = (mouseX(e) - deltaCenter.x);
            circle.point.y = (mouseY(e) - deltaCenter.y);   
            drawCircle(circle);
        }
    }
    
    function stopDragging(e) {
        deltaCenter = null;
    }
    
    function drawCircle(circle) {
        var canvas = document.getElementById('canvas');
        var ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.beginPath();
        ctx.arc(circle.point.x, circle.point.y, circle.radius, 0, Math.PI*2, true);
        ctx.fill();
    }
    
    var circle = new Circle(new Point(30, 40), 25);
    var deltaCenter = null;
    var element;
    
    </script>
    </head>
    <body>
    <canvas id="canvas" width="400" height="300"></canvas>
    </body>
    </html>
    

    试试jsFiddle

    【讨论】:

    • 嗨 jonas .. 感谢您的回复以及如何获取形状的坐标?
    • @rajeeesh:你需要自己保存它们。
    • 嗨,这是我用来添加图像的功能......如何保存坐标? this.mouseup = function (ev) { if (tool.started) { tool.mousemove(ev);变量 x=ev._x-28;变量 y=ev._y-28; var imageObj = new Image(); imageObj.onload = function(){ var p=context.drawImage(imageObj, x, y); }; imageObj.src = "test.png"; tool.started = false; img_update(); } };
    【解决方案2】:

    使用 Raphael.js (http://raphaeljs.com/) 和 Joint.jS (http://www.jointjs.com/) 可以实现相同的效果。

    使用 Raphael 创建的形状可以像任何 DOM 元素一样访问,并且可以通过属性进行操作。这是一个很棒的框架。

    Joint.js 有助于连接形状。他们还有一个图表库,可以帮助创建 ERD、Statemachine 和几个常用图表。最好的部分是您可以扩展他们的图表元素并创建自己的自定义元素。它的酷到令人瞠目结舌。

    http://www.jointjs.com/demos查看他们的演示和源代码

    【讨论】:

      【解决方案3】:

      如果您使用 raphael 作为“原始”库,您必须自己处理撤消/重做。 graphiti 库内部确实有 Undo/Redo Stack,并支持 SVG、PNG、JSON 的导出...

      此外,您还有一些类似 Viso 的连接器和端口。

      http://www.draw2d.org/graphiti/jsdoc/#!/example

      问候

      【讨论】:

        【解决方案4】:

        我认为没有简单的方法可以做到这一点。

        如果您只是处理线条,我的方法是跟踪创建的所有线条,包括起始坐标、结束坐标和某种 z-index。当用户开始拖动动作(onmousedown)时,您必须检查该点是否靠近线,然后在鼠标移动时更新对象并重新绘制画布。

        How can I tell if a point belongs to a certain line?

        但是,如果您要处理复杂的对象,这会变得更加复杂。您可能必须找到一个解决方案来检查一个点是否在路径内。

        【讨论】:

          【解决方案5】:

          绘制到 HTML5 Canvas 中的对象会变成像素然后被遗忘。您无法调整它们的属性并更新画布以查看效果。您可以自己记住它们,但画布仍会设置这些像素,因此您在调整属性时基本上必须重新绘制整个画布(或至少部分)。

          您可能希望在此应用程序中考虑使用 SVG,SVG 元素会被记住在 DOM 中,并且当更新它们的属性时,浏览器将更新图形以反映更改。

          如果您必须使用画布,那么您将需要编写大量代码来处理鼠标点击、对象属性和重绘。

          【讨论】:

          • 嗨,詹姆斯,感谢您的回复,您有任何示例或教程吗?我是否需要重新编码我的应用程序,或者我可以根据我的要求升级它?谢谢
          • 在我的脑海中,我不知道任何与此类内容的示例或教程的链接。有像 Paper.js 或 KineticJS 这样的库,它们是画布周围的矢量图形包装器,这可能是开始阅读的好地方。我认为无论哪种方式,您都必须进行 一些 重新编码,但是如果您使用库,则可能不会那么多。 SVG 将是一个很大的变化,编写自己的矢量图形代码也将是一个很大的变化。
          • 正如 Srikanth 所指出的,Raphael.js 也是一个矢量图形库,尽管它使用 SVG 而不是画布作为后端。
          猜你喜欢
          • 2012-10-19
          • 2012-05-12
          • 2015-08-18
          • 2012-12-28
          • 2013-12-09
          • 1970-01-01
          • 1970-01-01
          • 2013-07-25
          相关资源
          最近更新 更多