3

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");
    },

Projection movement (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.

Community
  • 1
  • 1
Check12
  • 352
  • 1
  • 5
  • 11

1 Answers1

2

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) + ")");
Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204
  • Hello, and thanks! I've updated my question to show the outcome. Can you see what I'm doing wrong? – Check12 May 29 '13 at 07:19
  • The thing that is interfering here is the translation you add to the projection itself. I'll update the answer. Also, your width and height should really be numbers, not strings. – Lars Kotthoff May 29 '13 at 08:36
  • That was it! Thank you for your help, and for spotting the type error. :) – Check12 May 29 '13 at 12:45