如何实现HTML5 Canvas绘图应用程序的拖放?

时间:2011-12-06 17:00:17

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

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

如何实现数字的拖放?

5 个答案:

答案 0 :(得分:3)

当用户点击画布时,您必须检查坐标(将其与对象的坐标进行比较),并查看它是否在对象上。例如。你可以用这种方法测试一个点(例如,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

上试用

答案 1 :(得分:3)

使用 Raphael.js http://raphaeljs.com/)和 Joint.jS http://www.jointjs.com/)可以达到同样的效果。

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

Joint.js有助于连接形状。他们还有一个图表库,可以帮助创建ERD,Statemachine和几个常见的图表。最好的部分是您可以扩展其图元素并创建自己的自定义元素。它的下巴很酷。

使用http://www.jointjs.com/demos

的源代码查看他们的演示

答案 2 :(得分:2)

如果您使用raphael作为“原始”库,则必须自己处理撤消/重做。 graphiti lib里面有Undo / Redo Stack,支持导出SVG,PNG,JSON,......

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

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

问候

答案 3 :(得分:1)

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

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

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

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

答案 4 :(得分:1)

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

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

如果你必须使用canvas,那么你将需要编写相当多的代码来处理鼠标命中,对象属性和重绘。