假设我有一个html5 / canvas应用程序,我可以在其中将对象放在绘图画布上。某种图表编辑器,比如Visio(但更简单)
是否有框架可以帮助我找到被点击/拖动的对象?
一个选项是捕获点击事件并迭代我的所有对象(以半智能的方式)并检查它是否被点击/拖动,但是我讨厌重新发明轮子: )
答案 0 :(得分:5)
简短的版本是Canvas本身没有跟踪这些。
如果您不想重新发明轮子,请从教程"Making and Moving Selectable Shapes on an HTML5 Canvas: A Simple Example."中的示例代码开始。它为点击和拖动提供了一个很好的介绍和平台。
答案 1 :(得分:1)
对于Visio风格的应用程序,或者与绘制对象的交互性很重要的任何内容,最好使用SVG。您已经可以使用some open source projects作为起点。 SVG的问题是,与任何DOM重物一样,一旦你有大量的对象需要操作,性能就会急剧下降。
答案 2 :(得分:0)
不幸的是,你没有渲染到画布中的东西的对象模型。当您检测到点击,鼠标,mousedown,拖动时,您需要跟踪您绘制的所有内容并触发单独的事件。这意味着为所有上下文方法创建一个包装器,将行/图像及其属性存储到COM(Canvas对象模型:)中,并为每个行/图像触发事件
我没有看到任何事情。这可以是很多的工作,我每次需要为Canvas添加交互性时都会编写自定义代码
答案 3 :(得分:0)
KineticJS是你的朋友:http://www.kineticjs.com
看看这是多么容易:http://www.html5canvastutorials.com/kineticjs/html5-canvas-drag-and-drop-tutorial/
答案 4 :(得分:0)
实际上,您可以使用ctx.isPointInPath()
方法轻松地做到这一点。它采用x
坐标和y
坐标形式的一个点,并检查画布中是否存在包含该点的某条路径。>
那么,您如何使用它来找出该点属于哪个元素?好了,清除画布后,画布上显然没有剩余点,因此ctx.isPointInPath()
将始终返回false
。然后,我们开始将每个元素逐一添加到画布。在画布上绘制元素之后,我们检查函数-如果它返回false
,则该点不在该元素内,因此我们继续。
自从画布为空白以来我们一直在检查每个元素时,我们知道该点不可能在我们已经检查过的元素之一之内。因此,当我们最终找到一个返回true
的元素时,我们知道点必须在该特定元素内。
这里的好处是我们不必编写任何自定义代码即可尝试检测该点是否在形状内,这特别棘手,特别是在形状复杂的情况下-这一切都由浏览器处理。
此方法存在问题-如果该点在两个或多个形状内,则仅报告该点在第一个形状内。一种解决方案可能是使用单独的隐藏画布并循环浏览所有形状,在每个形状之后清除它,并将ctx.isPointInPath()
返回true的形状的名称存储在数组中。您可能还可以采用其他方法。在这个答案中,我更多地关注基本概念,而不是像这样的特殊情况。
下面,我有一个使用这种方法的示例。我已经设置了一个画布,一个跟踪鼠标位置的脚本以及一个对象列表(每个对象都有一个名称)以及一个将其绘制到画布上的绘制函数。您可以想象一种面向对象的方法,它只是一个对象列表,这些对象都扩展了某个AbstractShape
类,但是对于演示,我一直保持简单。
然后,我只是不断地重新绘制画布(就像您要对其进行动画处理,制作游戏等一样),并且每次使用上面定义的算法来检查鼠标指针是否处于这种形状。
//Define the objects to draw on the canvas
let objects = [
{"name":"Circle", "draw":()=>{
ctx.beginPath();
ctx.arc(200, 75, 50, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
}},
{"name":"Square", "draw":()=>{
ctx.rect(10, 10, 100, 100);
ctx.fill();
}}
];
//Keep track of the mouse pointer
let mouseX, mouseY;
document.body.addEventListener("mousemove", (event)=>{
mouseX = event.clientX;
mouseY = event.clientY;
});
//Find the canvas, its context, and the output element
let cv = document.getElementById("cv");
let ctx = cv.getContext("2d");
let output = document.getElementById("output");
//Draw the objects on the canvas
function draw() {
//Clear the canvas
ctx.clearRect(0, 0, cv.width, cv.height);
//Clear the output div
output.innerHTML = "";
//This variable is true until we find an object
let noObjectFound = true;
//Loop through all of the objects
for (let object of objects) {
//Draw the current object
object.draw();
//Check if the mouse is on top of it
if (noObjectFound && ctx.isPointInPath(mouseX, mouseY)) {
//Update the output div
output.innerHTML = object.name;
noObjectFound = false;
}
}
//Call again ASAP
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
body {
padding:0;
margin:0;
}
#cv {
background-color:#eee;
}
<canvas id="cv"></canvas>
<h1 id="output"></h1>