1

I have topojson data to use with d3.js here: http://mazolosite.orionhub.org:8000/ZAF_adm3.json

I also created this fiddle to demo my issue, however it doesn't seem to load my topojson data: https://jsfiddle.net/gh583j5a/

This is my code that works locally with the issue of scaling and centering properly. The US topojson from the example seem to render fine with default projection.

I find myself struggling with scaling and projection given the lack of background in mapping API's.

    var width = 960,
  height = 500;

var path = d3.geo.path();

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);
debugger;
//var url = "https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/us.json"
var url = "http://mazolosite.orionhub.org:8000/ZAF_adm3.json";
d3.json(url, function(error, topology) {

  if (error) throw error;

  //var featureCollection = topojson.feature(topology, topology.objects.counties);
  var featureCollection = topojson.feature(topology, topology.objects.collection);
  var bounds = d3.geo.bounds(featureCollection);

  var centerX = d3.sum(bounds, function(d) {
      return d[0];
    }) / 2,
    centerY = d3.sum(bounds, function(d) {
      return d[1];
    }) / 2;

  var projection = d3.geo.mercator()
    .scale(300)
    .center([0,90]);//centerX, centerY
  path.projection(projection);

  svg.selectAll("path")
    .data(featureCollection.features)
    .enter().append("path")
    .attr("d", path);
});

My problem is in understanding this part of d3.js (Scaling and center):

var projection = d3.geo.mercator() .scale(300) .center([0,90]);//centerX, centerY

Please help.

Mazolo
  • 307
  • 4
  • 19

1 Answers1

1

There may be issues with your topojson file, if you are looking to test a projection, it never hurts to use a generic world topojson to see where you are looking (sometimes by scaling out). Then, once you are happy with that, testing out the specific topojson you want to use. This can make verifying the data quality of the topojson much easier as you can rule out a projection problem.

A mercator projection is a common projection, looking like: enter image description here

It greatly distorts area in polar regions (Greenland is much smaller than Australia in reality). The centering property of a d3.geo.mercator projection will simply pan to the coordinates specified (pan not zoom). This is generally not objectionable when dealing with low latitude areas such as South Africa. In order to create a d3.js mercator projection, you need to know the center coordinate of your area of interest.

This is roughly [26,-28] for the data that you have. You can figure this out programmatically, but it generally isn't hard to find by hand.

The coordinates you specified .center([0,90]) reference the north pole. Zero degrees east/west and 90 degrees north. If you specify [26,-28] as your center point, you will get a map fairly similar to the one above, just centered on South Africa.

The scale value will zoom you in, larger numbers equal larger features. For me with a 960px by 500px svg, a scale of 1500 worked pretty well for me. Again this can be found programmatically, but it may be that you just want to set this to your own esthetic pleasing. With the above parameters I got:

enter image description here

That was with:

.scale(1500)
.center([26,-28]);

But, what if you are dealing with higher latitudes, or feel that the distortion is too much at latitudes such as South Africa? Well, we can incorporate a rotation as well. Rotate moves the earth under the map, so if we want to rotate the map to show a southern area, we apply a positive value to the y value. Rotation can get similar results:

.scale(1500)
.rotate([-26,28])

enter image description here

The difference is fairly subtle, and probably not served well by screenshots, and probably more applicable in high latitude areas. Nonetheless, it shows another method to set projection parameters.

(All d3.projection parameters with x,y components are in that order: longitude,latitude).

Andrew Reid
  • 37,021
  • 7
  • 64
  • 83
  • That's a perfect solution to begin with, it worked like a charm. "This is roughly [26,-28] for the data that you have.", did you calculate this? How did you find this out? – Mazolo Feb 01 '17 at 17:27
  • There are a few methods, you could use a program like google earth and find the coordinates of a point close to the center of what you want. For this answer I took the topojson you posted and copied it into Mapshaper.org, used the console and typed `info` to get a bounding box in geographic coordinates (display is Bounds: x(left) y(bottom) x(right) y(top)), from there I estimated the middle coordinate. Alternatively, you could google "geographic center of South Africa", I found: indexmundi.com/south_africa/geographic_coordinates.html with slightly different coordinates than my estimate. – Andrew Reid Feb 01 '17 at 18:35
  • Perfect,I learned a lot from this. I will try this. Thanks a ton. – Mazolo Feb 02 '17 at 06:04
  • One additional note, if you are planning on using different map projections, they will likely require different methods for determining projection parameters. See for example: http://stackoverflow.com/questions/39958471/d3-js-map-how-to-rotate-it/41133970#41133970 – Andrew Reid Feb 02 '17 at 17:40