【发布时间】:2012-01-14 06:45:02
【问题描述】:
基于Creating an HTML 5 canvas painting application我创建了一个HTML5画布绘画应用程序。它工作正常,但在创建每个对象后,我只需要拖动对象。 Working demo
如何实现图形的拖放?
【问题讨论】:
标签: javascript html canvas drag-and-drop html5-canvas
基于Creating an HTML 5 canvas painting application我创建了一个HTML5画布绘画应用程序。它工作正常,但在创建每个对象后,我只需要拖动对象。 Working demo
如何实现图形的拖放?
【问题讨论】:
标签: javascript html canvas drag-and-drop html5-canvas
当用户单击画布时,您必须检查坐标(将其与对象的坐标进行比较),并查看它是否在对象上。例如。您可以使用此方法测试一个点(例如 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
【讨论】:
使用 Raphael.js (http://raphaeljs.com/) 和 Joint.jS (http://www.jointjs.com/) 可以实现相同的效果。
使用 Raphael 创建的形状可以像任何 DOM 元素一样访问,并且可以通过属性进行操作。这是一个很棒的框架。
Joint.js 有助于连接形状。他们还有一个图表库,可以帮助创建 ERD、Statemachine 和几个常用图表。最好的部分是您可以扩展他们的图表元素并创建自己的自定义元素。它的酷到令人瞠目结舌。
在http://www.jointjs.com/demos查看他们的演示和源代码
【讨论】:
如果您使用 raphael 作为“原始”库,您必须自己处理撤消/重做。 graphiti 库内部确实有 Undo/Redo Stack,并支持 SVG、PNG、JSON 的导出...
此外,您还有一些类似 Viso 的连接器和端口。
http://www.draw2d.org/graphiti/jsdoc/#!/example
问候
【讨论】:
我认为没有简单的方法可以做到这一点。
如果您只是处理线条,我的方法是跟踪创建的所有线条,包括起始坐标、结束坐标和某种 z-index。当用户开始拖动动作(onmousedown)时,您必须检查该点是否靠近线,然后在鼠标移动时更新对象并重新绘制画布。
How can I tell if a point belongs to a certain line?
但是,如果您要处理复杂的对象,这会变得更加复杂。您可能必须找到一个解决方案来检查一个点是否在路径内。
【讨论】:
绘制到 HTML5 Canvas 中的对象会变成像素然后被遗忘。您无法调整它们的属性并更新画布以查看效果。您可以自己记住它们,但画布仍会设置这些像素,因此您在调整属性时基本上必须重新绘制整个画布(或至少部分)。
您可能希望在此应用程序中考虑使用 SVG,SVG 元素会被记住在 DOM 中,并且当更新它们的属性时,浏览器将更新图形以反映更改。
如果您必须使用画布,那么您将需要编写大量代码来处理鼠标点击、对象属性和重绘。
【讨论】: