javascript - D3.js canvas 和 svg 中的 map 缩放行为

标签 javascript canvas svg d3.js

感谢您的阅读。

目标

我想将 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绘图函数使用纬度/经度坐标的投影值,但您没有更新 scaletranslate您的projection在你的zoom处理程序。

获得您所追求的行为的一种方法是从 transform 切换。关于svgzoom处理程序,到 transform关于projection .

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

差异是:

  1. 更新zoom使用 projection 的行为translatescale作为默认值,并设置 scaleExtent值基于projection也是如此。

    var zoom = d3.behavior.zoom()
        .translate(projection.translate())
        .scale(projection.scale())
        .scaleExtent([projection.scale()/5, projection.scale()*5])
        .on("zoom", zoomed);
    
  2. 更新您的 zoomed函数为 translatescale 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();
    }
    
  3. 更新您的 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);
    }
    

    这可能是此次更改的主要组成部分之一,如 scaletranslate应用于zoom行为,当它们出现时,它们必须按当前的 zoom 进行缩放scaleclicked然后函数会触发 zoomed重绘 svg 的函数和canvas元素。

如您所见,您的canvas绘图代码是正确的。只是绘图代码使用的是 projection确定xy根据 projection 绘制点的位置zoom 没有更新它处理程序。

也可以有一个单独的 projection对于canvas ,并在zoom中更新它调用 canvas 之前的处理程序重绘函数。我将把它作为练习留给读者!

关于javascript - D3.js canvas 和 svg 中的 map 缩放行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28823152/

相关文章:

javascript - DataTables 个别列搜索框与 colvis 冲突

javascript - mxGraph:来自外部按钮的单击事件

javascript - 查找相机是否已在 Babylonjs 中将键盘控制附加或分离到 Canvas

javascript - 更新 HTML 文件文件夹中的所有 href anchor 链接

javascript - 使用 Javascript/Jquery 禁用桌面 Web 浏览器中的页面缩放

javascript - 如何将 Canvas 保存为 png 图像?

javascript - 在 Javascript 中创建非矩形形状的斜 Angular 效果

ios - iOS 是否支持 SVG Tiny?

java - 使用 XSLFO 显示 SVG

iphone - UIWebview 操作 SVG 'on the fly'