在多个canvas的无缝绘图
我正在尝试使用JS和Canvas元素制作一个简单的绘图工具。 我的问题是我希望有几个canvas,用户应该能够通过所有canvas画一条线。 这是我做的一个小页面:
var act = null; var context = null; var draw = false; var c = false; function boot() { $('.can') .mouseenter(function(){ act = this; context = act.getContext('2d'); // console.log(this); }) .mouseleave(function(){ act = null; context = null; // console.log('out'); }) .mousedown(function(){ draw = true; }) .mouseup(function(){ draw = false; }) .mousemove(function(ev){ // console.log(act); if (ev.layerX || ev.layerX == 0) { // Firefox x = ev.layerX; y = ev.layerY; } else if (ev.offsetX || ev.offsetX == 0) { // Opera x = ev.offsetX; y = ev.offsetY; } if(draw && context != null) if (!c) { context.beginPath(); context.moveTo(x, y); c = true; } else { context.lineTo(x, y); context.stroke(); } }); } $(document).ready(boot); .can {border: 1px solid blue; display:block; float:left; margin:0;}
它部分起作用:我只能在第一个canvas上绘制。 我调试它,我真的很困惑,因为上下文按预期更改,并且仅在第一个canvas中启用绘图。
任何想法是什么导致这种行为?
好的,我找到了问题的根源。 原文在这里:
固定版本在这里:
基本上,问题是你没有正确计算你的X和Y变量。 .offsetX
和.offsetY
计算相对于元素的直接祖先的x和y位置(在本例中是页面的主体)。 你可以通过在mouseover上警告x和y值来看到这一点。 无论如何,你需要做的是:
var o = $(this).offset(), x = (ev.pageX - o.left), y = (ev.pageY - o.top);
我的代码还有一些其他问题我已经改变了。 首先,你没有为每个canvas开始新的路径,所以当你重新进入canvas时,它会从行离开的地方开始行lineTo(x, y)
。 为了解决这个问题,我让你的mouseout事件看起来像这样:
.mouseout(function() { c=false; })
现在,只要它进入新canvas,它就会开始一条新路径。
我改变的第三件事是使它只在文档就绪时创建一次上下文。 我想这可以节省一些处理。 所以我在全球范围内添加了这一行:
var contexts = [];
这个方法在你的$('.can')
方法链中:
.each(function(el) { id = this.id; contexts[id] = this.getContext('2d'); })
所以在你的代码中的其他地方,你可以像这样引用它:
contexts[this.id].beginPath();
现在它有效。