Given that I have topoJSON data of a given geographical feature and a specific projection.
How should I center and scale the map to fit its parent object?
It seems I can use either projection.rotate(), projection.translate() or projection.center() to center a map:
https://github.com/d3/d3-3.x-api-reference/blob/master/Geo-Projections.md
What are the differences and how does scale affect the different functions?
Use projection.fitExtent()
in v4. Documentation. Example.
fitExtent
takes two parameters:
[[0, 0], [width, height]]
.If the top left corner of the projection is [0, 0]
, you can use the convenience method projection.fitSize()
, where you only pass the bottom right corner of the extent
, represented by a single array of two items – e.g. [width, height]
.
Actually, it's a mix of both. According to the API, projection.center:
sets the projection’s center to the specified location, a two-element array of longitude and latitude in degrees and returns the projection.
So, it's used to set the center of the map. Regarding projection.translate:
If point is specified, sets the projection’s translation offset to the specified two-element array [x, y] and returns the projection. If point is not specified, returns the current translation offset which defaults to [480, 250]. The translation offset determines the pixel coordinates of the projection’s center. The default translation offset places ⟨0°,0°⟩ at the center of a 960×500 area.
As you can see, projection.translate depends on projection.center ("the translation offset determines the pixel coordinates of the projection’s center"). So, both values will determine how the map sits in its container
This is a demo showing the map of Japan (this code is not mine) in a smaller SVG, 500x500. In this one, we'll set the translate to the middle of the SVG:
.translate([width/2, height/2]);
Check the demo:
var topoJsonUrl = "https://dl.dropboxusercontent.com/u/1662536/topojson/japan.topo.json";
var width = 500,
height = 500,
scale = 1;
d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g").attr("id", "all-g");
var projection = d3.geo.mercator()
.center([138, 38])
.scale(1000)
.translate([width / 2, height / 2]);
d3.json(topoJsonUrl, onLoadMap);
function onLoadMap (error, jpn) {
var path = d3.geo.path()
.projection(projection);
var features = topojson.object(jpn, jpn.objects.japan);
var mapJapan = features;
d3.select("#all-g")
.append("g").attr("id", "path-g").selectAll("path")
.data(features.geometries)
.enter()
.append("path")
.attr("fill", "#f0f0f0")
.attr("id", function(d,i){ return "path" + i})
.attr("stroke", "#999")
.attr("stroke-width", 0.5/scale)
.attr("d", path);
}
path {
stroke: black;
stroke-width: 1.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://d3js.org/topojson.v0.min.js"></script>
And, in this one, to the left:
.translate([width/4, height/2]);
Check the demo:
var topoJsonUrl = "https://dl.dropboxusercontent.com/u/1662536/topojson/japan.topo.json";
var width = 500,
height = 500,
scale = 1;
d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g").attr("id", "all-g");
var projection = d3.geo.mercator()
.center([138, 38])
.scale(1000)
.translate([width / 4, height / 2]);
d3.json(topoJsonUrl, onLoadMap);
function onLoadMap (error, jpn) {
var path = d3.geo.path()
.projection(projection);
var features = topojson.object(jpn, jpn.objects.japan);
var mapJapan = features;
d3.select("#all-g")
.append("g").attr("id", "path-g").selectAll("path")
.data(features.geometries)
.enter()
.append("path")
.attr("fill", "#f0f0f0")
.attr("id", function(d,i){ return "path" + i})
.attr("stroke", "#999")
.attr("stroke-width", 0.5/scale)
.attr("d", path);
}
path {
stroke: black;
stroke-width: 1.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://d3js.org/topojson.v0.min.js"></script>
In both cases, however, changing projection.center will move the map in its container.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With