D3.js在canvas和svg中映射缩放行为

时间:2015-03-03 02:37:58

标签: javascript canvas svg d3.js

感谢阅读。

目标

我想比较一下从Mike Bostock的块到基于画布的系统的工作SVG点击缩放。我已将工作SVG放在顶部,将画布放在底部。当用户点击上部SVG中的状态时,我希望下部画布元素为"跟随"或模仿缩放和平移。例如,单击上部SVG中的明尼苏达州也会导致下部画布缩放并平移到明尼苏达州。

问题

我的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的链接位于这篇文章的顶部。

1 个答案:

答案 0 :(得分:1)

canvas绘图功能使用纬度/经度坐标的投影值,但您没有更新scale的{​​{1}}和translate在你的projection处理程序中。

获得您之后的行为的一种方法是从zoom处理程序中的transform上的svg切换为zoomtransform

我已经在这个更新过的小提琴中做到了这一点:http://jsfiddle.net/30w8nv4t/7/

区别在于:

  1. 更新projection行为以使用zoom projectiontranslate作为默认值,并将scale值设置为也基于scaleExtent

    projection
  2. var zoom = d3.behavior.zoom() .translate(projection.translate()) .scale(projection.scale()) .scaleExtent([projection.scale()/5, projection.scale()*5]) .on("zoom", zoomed); 功能更新为zoomedtranslate scale,然后重新绘制基于projection的路径。

    svg
  3. 相应地更新您的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 zoomscale函数会触发clicked函数重绘zoomedsvg元素。

  4. 如您所见,您的canvas绘图代码是正确的。只是绘图代码使用canvas来确定要绘制的点的projectionx位置,这些位置基于y而不是projectionzoom处理程序更新。

    还可以为projection单独canvas,并在调用zoom重绘函数之前在canvas处理程序中更新它。我将此作为练习留给读者!