Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3js scale, transform and translate

Tags:

d3.js

I've created nycMap, a project that uses angularJS (MVC), yeoman (build), d3 (mapping) and geoJSON (geo data).

Everything works very nicely, but I did have to spend quite some time getting the right scale and translation. I was wondering how I can automatically figure out at what scale the map will show its best and what x and y values go into the translation?

'use strict';

japanAndCo2App.controller('MainCtrl', function($scope) {

 function makeJapanAll(){
    var path, vis, xy;

    xy = d3.geo.mercator().scale(16000).translate([-5600,2200]);
    path = d3.geo.path().projection(xy);
    vis = d3.select("#japanAll").append("svg:svg").attr("width", 1024).attr("height", 700);
    d3.json("data/JPN_geo4.json", function(json) {
      return vis.append("svg:g")
          .attr("class", "tracts")
          .selectAll("path")
          .data(json.features).enter()
          .append("svg:path")
          .attr("d", path)
          .attr("fill",function(d,i){ return d.properties.color || "transparent"});
    });
  }
  makeJapanAll();
});

(If you are interested in the code, it's all on github. The code for the map is in scripts/controllers/main.js which is the same as shown above.)

like image 779
climboid Avatar asked Nov 07 '12 16:11

climboid


People also ask

What does ATTR transform do?

The transform attribute defines a list of transform definitions that are applied to an element and the element's children. Note: As of SVG2, transform is a presentation attribute, meaning it can be used as a CSS property.

What is D3 translation?

Translate is an important functionality in D3. js and is used to move the SVG elements inside the webpage. It takes two values, namely x and y. The x value translates the SVG element along the x-axis, while y translates the SVG element along the y-axis.

What can d3js do?

D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply data-driven transformations to the document. For example, you can use D3 to generate an HTML table from an array of numbers. Or, use the same data to create an interactive SVG bar chart with smooth transitions and interaction.

What is D3 zoomIdentity?

zoomIdentity() function in D3. js is used to get the identity transform, where k = 1, tx = ty = 0.


1 Answers

Given this:

xy = d3.geo.mercator().scale(someScale).translate([0, 0]);

someScale is the pixel width of the entire world when projected using the mercator projection. So, if your json data had outlines for the whole world – spanning from lat/lng -180,90 to latLng 180,-90 – and if someScale was 1024, then the world would be drawn such that it exactly fits within a 1024x1024-pixel square. That's what you see on in this Google Maps view (well... sort of... not quite... read on...).

That's not enough though. When the world is drawn at 1024px, without any translation, lat/lng 0,0 (i.e. the "middle" of the world) will sit at the 0,0 pixel of the projected map (i.e. the top left). Under these conditions, the whole northern hemisphere and western hemisphere have negative x or y values, and therefore fall outside the drawn region. Also, under these conditions, the bottom right of the world (i.e. lat/lng -90, 180) would sit at the exact middle of the 1024x1024 square (i.e. at pixel 512,512).

So, in order to center the world in the square described here, you need to translate the map by half its width in the X and Y directions. I.e. you need

xy = d3.geo.mercator().scale(1024).translate([512, 512]);

That'll give you exactly the Google Map view I linked to.

If your json data only has part of the world (like, nyc or NY state) drawing it with this xy projection will render the outlines in the correct geographic position relative to the entire 1024x1024 world-spanning region. So it would appear rather small, with lots of whitespace.

The challenge is how to scale and translate the projection such that the area in question fills up the 1024x1024 square. And... so far I haven't answered this question, but I hope that this explanation points you in the right direction towards figuring out this math. I'll also try to continue the answer later, when I have more time. :/

like image 134
meetamit Avatar answered Oct 22 '22 07:10

meetamit