感谢您的阅读。
目标
我想将 Mike Bostock 的 block 中可用的 SVG 单击缩放功能与基于 Canvas 的系统进行比较。我将工作 SVG 放在顶部,将 Canvas 放在底部。当用户单击上部 SVG 中的状态时,我希望下部 Canvas 元素“跟随”或模仿缩放和平移。例如,单击上部 SVG 中的明尼苏达州也会导致下部 Canvas 缩放和平移到明尼苏达州。
问题
我的 Canvas 元素在加载 topojson 后绘制得很好,但它没有动画。我希望它有动画效果。我相信这是因为我不完全理解缩放行为和基于路径的投影。
http://jsfiddle.net/30w8nv4t/2/
function zoomed(d) {
g.style("stroke-width", 1.5 / d3.event.scale + "px");
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
// the zTranslate and zScale variables appear to be ok,
// but `d` is null. I'm not sure how to redraw.
var zTranslate = zoom.translate();
var zScale = zoom.scale();
console.log(zTranslate, zScale, d);
context.clearRect(0, 0, width, height);
context.beginPath();
canvasPath(d);
context.stroke();
}
在这种情况下,d
显然为空,并且我无法重绘任何内容。我认为我的问题可能出在 zoomed
方法或 clicked
函数中。
原因
我使用这种并行方法是因为我想了解路径、投影和缩放行为如何协同工作。我很欣赏 Canvas 相对于 SVG 的表现,但交互性的缺乏令人望而生畏。幸运的是,能够缩放和平移到任意几何形状将我的问题减少了一半。
感谢您的阅读。 JSFiddle 的链接位于本文顶部。
最佳答案
canvas
绘图函数使用纬度/经度坐标的投影值,但您没有更新 scale
和translate
您的projection
在你的zoom
处理程序。
获得您所追求的行为的一种方法是从 transform
切换。关于svg
在 zoom
处理程序,到 transform
关于projection
.
我已经在这个更新的 fiddle 中做到了这一点:http://jsfiddle.net/30w8nv4t/7/
差异是:
更新
zoom
使用projection
的行为translate
和scale
作为默认值,并设置scaleExtent
值基于projection
也是如此。var zoom = d3.behavior.zoom() .translate(projection.translate()) .scale(projection.scale()) .scaleExtent([projection.scale()/5, projection.scale()*5]) .on("zoom", zoomed);
更新您的
zoomed
函数为translate
和scale
projection
然后重画svg
基于路径。function zoomed(d) { //g.style("stroke-width", 1.5 / d3.event.scale + "px"); //g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); projection.translate(d3.event.translate).scale(d3.event.scale); g.selectAll("path").attr("d", path); var zTranslate = zoom.translate(); var zScale = zoom.scale(); console.log(zTranslate, zScale, d); context.clearRect(0, 0, width, height); context.beginPath(); canvasPath(states); context.stroke(); }
更新您的
clicked
相应地发挥作用。function clicked(d) { if (active.node() === this) { zoom.scale(500).translate([width/2, height/2]); active.classed("active", false); active = d3.select(null); } else { var centroid = path.centroid(d), translate = zoom.translate(), bounds = path.bounds(d), dx = bounds[1][0] - bounds[0][0], dy = bounds[1][1] - bounds[0][1], scale = .9/ Math.max(dx / width, dy / height); zoom.scale(scale * zoom.scale()) .translate([ translate[0] - centroid[0] * scale + width * scale / 2, translate[1] - centroid[1] * scale + height * scale / 2]); active.classed("active", false); active = d3.select(this).classed("active", true); } zoom.event(svg); }
这可能是此次更改的主要组成部分之一,如
scale
和translate
应用于zoom
行为,当它们出现时,它们必须按当前的zoom
进行缩放scale
。clicked
然后函数会触发zoomed
重绘svg
的函数和canvas
元素。
如您所见,您的canvas
绘图代码是正确的。只是绘图代码使用的是 projection
确定x
和y
根据 projection
绘制点的位置zoom
没有更新它处理程序。
也可以有一个单独的 projection
对于canvas
,并在zoom
中更新它调用 canvas
之前的处理程序重绘函数。我将把它作为练习留给读者!
关于javascript - D3.js canvas 和 svg 中的 map 缩放行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28823152/