Reputation: 219
I am playing around geo modules of D3.I have some experience with D3 but this is the first time I am trying out the geo modules. I have taken the following code (from https://github.com/alignedleft/d3-book/blob/master/chapter_12/04_fill.html) that originally displays US map(https://github.com/alignedleft/d3-book/edit/master/chapter_12/us-states.json) edit (files can now be found in the zip downloadable in https://github.com/alignedleft/d3-book/releases/tag/v1.0) in albers projection and modified to take a Geojson of India(indiastates1.json below). The code works well with the US file, but does not display anything with India json file. Am I missing something here. Any help is appreciated. I did change the projection to mercator though.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Setting path fills</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
//Define map projection
var projection = d3.geo.mercator()
.translate([w/2, h/2])
.scale([500]);
//Define path generator
var path = d3.geo.path()
.projection(projection);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load in GeoJSON data
d3.json("indiastates1.json", function(json) {
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", "steelblue");
});
</script>
</body>
</html>
indiastates1.json
{"type":"FeatureCollection","features":[
{"type":"Feature","id":"IND","properties":{"name":"India"},"geometry":{"type":"Polygon","coordinates":[[[77.837451,35.49401],[78.912269,34.321936],[78.811086,33.506198],[79.208892,32.994395],[79.176129,32.48378],[78.458446,32.618164],[78.738894,31.515906],[79.721367,30.882715],[81.111256,30.183481],[80.476721,29.729865],[80.088425,28.79447],[81.057203,28.416095],[81.999987,27.925479],[83.304249,27.364506],[84.675018,27.234901],[85.251779,26.726198],[86.024393,26.630985],[87.227472,26.397898],[88.060238,26.414615],[88.174804,26.810405],[88.043133,27.445819],[88.120441,27.876542],[88.730326,28.086865],[88.814248,27.299316],[88.835643,27.098966],[89.744528,26.719403],[90.373275,26.875724],[91.217513,26.808648],[92.033484,26.83831],[92.103712,27.452614],[91.696657,27.771742],[92.503119,27.896876],[93.413348,28.640629],[94.56599,29.277438],[95.404802,29.031717],[96.117679,29.452802],[96.586591,28.83098],[96.248833,28.411031],[97.327114,28.261583],[97.402561,27.882536],[97.051989,27.699059],[97.133999,27.083774],[96.419366,27.264589],[95.124768,26.573572],[95.155153,26.001307],[94.603249,25.162495],[94.552658,24.675238],[94.106742,23.850741],[93.325188,24.078556],[93.286327,23.043658],[93.060294,22.703111],[93.166128,22.27846],[92.672721,22.041239],[92.146035,23.627499],[91.869928,23.624346],[91.706475,22.985264],[91.158963,23.503527],[91.46773,24.072639],[91.915093,24.130414],[92.376202,24.976693],[91.799596,25.147432],[90.872211,25.132601],[89.920693,25.26975],[89.832481,25.965082],[89.355094,26.014407],[88.563049,26.446526],[88.209789,25.768066],[88.931554,25.238692],[88.306373,24.866079],[88.084422,24.501657],[88.69994,24.233715],[88.52977,23.631142],[88.876312,22.879146],[89.031961,22.055708],[88.888766,21.690588],[88.208497,21.703172],[86.975704,21.495562],[87.033169,20.743308],[86.499351,20.151638],[85.060266,19.478579],[83.941006,18.30201],[83.189217,17.671221],[82.192792,17.016636],[82.191242,16.556664],[81.692719,16.310219],[80.791999,15.951972],[80.324896,15.899185],[80.025069,15.136415],[80.233274,13.835771],[80.286294,13.006261],[79.862547,12.056215],[79.857999,10.357275],[79.340512,10.308854],[78.885345,9.546136],[79.18972,9.216544],[78.277941,8.933047],[77.941165,8.252959],[77.539898,7.965535],[76.592979,8.899276],[76.130061,10.29963],[75.746467,11.308251],[75.396101,11.781245],[74.864816,12.741936],[74.616717,13.992583],[74.443859,14.617222],[73.534199,15.990652],[73.119909,17.92857],[72.820909,19.208234],[72.824475,20.419503],[72.630533,21.356009],[71.175273,20.757441],[70.470459,20.877331],[69.16413,22.089298],[69.644928,22.450775],[69.349597,22.84318],[68.176645,23.691965],[68.842599,24.359134],[71.04324,24.356524],[70.844699,25.215102],[70.282873,25.722229],[70.168927,26.491872],[69.514393,26.940966],[70.616496,27.989196],[71.777666,27.91318],[72.823752,28.961592],[73.450638,29.976413],[74.42138,30.979815],[74.405929,31.692639],[75.258642,32.271105],[74.451559,32.7649],[74.104294,33.441473],[73.749948,34.317699],[74.240203,34.748887],[75.757061,34.504923],[76.871722,34.653544],[77.837451,35.49401]]]}}
]}
Upvotes: 15
Views: 31440
Reputation: 34074
This is a simple example showing how to centre your map projection around all the features in your feature collection (not just one or the default), it's based on the linked Mike Bostock answer, which is great but based on zooming on just one feature, and also d3.js geoJSON and bounds which shows that whole feature collections can be used.
The key changes to your code are:
Replacing the initial translate and scale with a neutral one:
var projection = d3.geo.mercator()
.scale(1)
.translate([0, 0]);
After loading the json, adding code to dynamically update the projection based on the bounding box of the entire feature collection:
var b = path.bounds( json ),
s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
projection
.scale(s)
.translate(t);
So the updated complete example would look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Setting path fills</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
//Define map projection
var projection = d3.geo.mercator()
.translate([0, 0])
.scale(1);
//Define path generator
var path = d3.geo.path()
.projection(projection);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load in GeoJSON data
d3.json("indiastates1.json", function(json) {
// Calculate bounding box transforms for entire collection
var b = path.bounds( json ),
s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
// Update the projection
projection
.scale(s)
.translate(t);
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", "steelblue");
});
</script>
</body>
</html>
Upvotes: 2
Reputation: 105
This problem happens because US map is positioned so as to center US. You have probably loaded the India file but it may be out of the screen or very tiny to see. You can manually do the correction by changing values of scale and center and translate. but a better approach is automatically finding the scale and translation from the code
var b = path.bounds(#data#),
s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
//scaled the bounding box
t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
// new projection
projection = d3.geo.mercator()
.scale(s).translate(t);
path = path.projection(projection);
Upvotes: 0
Reputation: 2874
You're (or the browser) just looking in the wrong place. I think that d3 automatically centres on the US with these geo projections. All you need to do is to use transform to move 'India' on to the svg viewport. Specifically, you need to translate the origin of the viewport to a location specified by coordinates in x,y pixels - or at least that's the way I think of it. To see India I tried
.attr("transform", "translate(-800,200)")
and it seemed to do the job.
It's pretty easy to pick these things up if you inspect the element, you can then use the path to give you some hints where to transform.
UPDATE
A far better approach is to this problem would be to compute the center and scale such as outlined in this question and answer. In particular the answer by Jan and Mike are both excellent. There is also an explaination of the code in this google groups discussion - the second last post.
Upvotes: 12