How can I use SVG translate to center a d3.js proj

2020-02-29 09:27发布

问题:

I am using d3 to render a Mercator projection of a GeoJSON world map.

I would like to be able to use d3 to scale, and translate the map to known latitude and longitude values as the user steps through my application.

projection.center (https://github.com/mbostock/d3/wiki/Geo-Projections#wiki-center) does what I'd like, combined with transition().duration(), but this requires redrawing the map and therefore seems expensive to keep repeating. I would like to use the native translate() and scale() methods that come with SVG (https://developer.mozilla.org/en-US/docs/SVG/Attribute/transform).

I've found a few helpful examples, like Mike Bostock's (http://bl.ocks.org/mbostock/4699541), and useful questions, like the following about centering a map to a given GeoJSON object (Center a map in d3 given a geoJSON object), but I am struggling to wrap my head around them.

Please could someone help me center my projection to given latitude and longitude values using SVG's transform="translate(x, y)"?

Many thanks in advance.


Edit @Lars: First of all, thank you. I have tried your suggestion, and movement occurs, but the projection appears to move too far. I have included a screenshot and my projection code, below:

var SFMap = {
    initialise: function() {
        var width = "752";
        var height = "420";
        SFMap.projection = d3.geo.mercator()
            .scale(100)
            .translate([width/2, height/2])
            .center([0, 0]);

        SFMap.path = d3.geo.path()
            .projection(SFMap.projection);

        SFMap.svg = d3.select("#sf__map")
            .append("svg")
            .attr("width", width)
            .attr("height", height);

        SFMap.g = SFMap.svg.append("g");

        d3.json("world-110m.topo.json", SFMap.draw);
    },

    draw: function(error, topology) {
        SFMap.g
            .selectAll("path")
            .data(topojson.feature(topology, topology.objects.countries)
                .features)
            .enter()
            .append("path")
            .attr("d", SFMap.path)
            .attr("class", "feature");
    },

(View full size)

The above occurs when translateing to London - 51.5171° N, 0.1062° W - using the following code:

var coordinates = SFMap.projection([0.1062, 51.5171]);
SFMap.g.attr("transform", "translate(" + (-coordinates[0]) + "," + (-coordinates[1]) + ")");

I have also tried inverting the values a second time.

回答1:

Assuming that the center of your projection is (0,0), all you need to do is to give the coordinates of the point you want to center to your projection function (to translate into user coordinates) and give the inverse of that to translate. Something like

var coordinates = projection(point);
svg.attr("transform", "translate(" + (-coordinates[0]) + "," + (-coordinates[1]) + ")");

If you translated the projection as well, you need to take that into account, e.g.

svg.attr("transform", "translate(" + (-coordinates[0]+width/2) +
         "," + (-coordinates[1]+height/2) + ")");


标签: svg maps d3.js geo