D3.js canvas 和 svg 中的地图缩放行为
D3.js map zoom behaviors in canvas and svg
感谢阅读。
目标
我想将来自 Mike Bostock 块的工作 SVG 点击缩放与基于 canvas 的系统进行比较。我将工作 SVG 放在顶部,canvas 放在底部。当用户单击上方 SVG 中的状态时,我希望下方 canvas 元素 "follow" 或模仿缩放和平移。例如,单击上方 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 的 link 位于此 post 的顶部。
canvas
绘图函数使用 lat/long 坐标的投影值,但您没有更新 scale
和 translate
坐标16=] 在你的 zoom
处理程序中。
获得您想要的行为的一种方法是从 zoom
处理程序中 svg
上的 transform
切换到 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
处理程序。
也可以为 canvas
设置单独的 projection
,并在调用 canvas
重绘函数之前在 zoom
处理程序中更新它。我将把它留作 reader!
的练习
感谢阅读。
目标
我想将来自 Mike Bostock 块的工作 SVG 点击缩放与基于 canvas 的系统进行比较。我将工作 SVG 放在顶部,canvas 放在底部。当用户单击上方 SVG 中的状态时,我希望下方 canvas 元素 "follow" 或模仿缩放和平移。例如,单击上方 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 的 link 位于此 post 的顶部。
canvas
绘图函数使用 lat/long 坐标的投影值,但您没有更新 scale
和 translate
坐标16=] 在你的 zoom
处理程序中。
获得您想要的行为的一种方法是从 zoom
处理程序中 svg
上的 transform
切换到 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
处理程序。
也可以为 canvas
设置单独的 projection
,并在调用 canvas
重绘函数之前在 zoom
处理程序中更新它。我将把它留作 reader!