D3.Geo performance on Pan/Zoom

萝らか妹 提交于 2019-12-06 07:16:45

问题


Last year I made a couple experiments on web maps using the Mapnik library (server-side, bitmap/tiling). Now I'm trying to replicate the same experiments using the vector, client-side approach with d3.js.

I have a map (~680 shapes) where zoom is slow and pan is sluggish (this example by Mike Bostock works well). I suspect the problem is in the zoommove callback, the selectAll("path").attr("d", path) takes too long.

function zoommove() {
    projection.translate(d3.event.translate).scale(d3.event.scale);
    mapa.selectAll("path").attr("d", path);
    console.log('zoommove fired...');
}

Questions:

  1. Am I doing something wrong here?
  2. what can I do in order to optmize performance?

The map is this (jsfiddle here):

The datasource is in topojson format. It was simplified, may be already too much, because some shapes are not closing:

[UPDATE]

Looks like the problem with open geometries occurs even when running topojson without simplification flags, I'm still investigating. I would appreciate any clues here, the documentation is not very detailed.


回答1:


(I'm not super sure what's going on under the hood here, this might be totally wrong).

mapa.selectAll("path").attr("d", path);

Redraws the map from scratch. That works fine for 50 states but starts to get pretty slow with 600+ shapes. You might have better luck if you left the paths in place and just transformed the entire svg:

function zoommove() {
  svg.attr("transform",
      "translate("+d3.event.translate+")"
      + " scale("+d3.event.scale+")");
}

Which I've used to create a county level map of the US (~500 shapes) that zooms and pans smoothly.




回答2:


Answering my own question here, If you find this helpful, please upvote Adam's answer instead, he deserves the credit.

What worked for me:

var bg = svg.append('g')
    .call(zoom);

var map = bg.append("g")
    .attr("transform", "translate(0,0) scale(1)");

...

function zoommove() {
    var t1 = projection.translate(),
        t2 = d3.event.translate,
        t = [t2[0]-t1[0], t2[1]-t1[1]];

    map.attr("transform", 
        "translate("+t+") " +
        "scale("+(d3.event.scale/s)+")"
    );
    console.log(map.attr("transform"));
}

Some tips:

  • if projection.translate() is not [0, 0], you have to take it in account, otherwise a big bump will occur on the first time you try to pan/zoom (only the first time).
  • if projection.scale() is not 1, you have to take it in account.
  • the .call(zoom) must be in the maps parent element, otherwise panning/zooming becomes bumpy.



回答3:


I've come across similar issues, and a rescaling was not suitable for my solution as i did not want the svg elements themselves to be scaled. What I did instead was optimize it such that elements out of the visible area were not recalculated. This means that when all the elements are in the view performance is still bad, but when you zoom in it's much better.

ode sample:

clippedArea.selectAll("circle")
    .style("visibility", d => pointInDomain(d, domain) ? "visible" : "hidden")
    .filter(d => pointInDomain(d, domain))
  .attr("cx", d => xz(d.x));

JSFiddle



来源:https://stackoverflow.com/questions/17093614/d3-geo-performance-on-pan-zoom

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!