Currently in d3 if you have a geoJSON object that you are going to draw you have to scale it and translate it in order to get it to the size that one wants and translate it
To pan/zoom the map you should look at overlaying the SVG on Leaflet. That will be a lot easier than transforming the SVG. See this example http://bost.ocks.org/mike/leaflet/ and then How to change the map center in leaflet
With d3 v4 or v5 its getting way easier!
var projection = d3.geoMercator().fitSize([width, height], geojson);
var path = d3.geoPath().projection(projection);
and finally
g.selectAll('path')
.data(geojson.features)
.enter()
.append('path')
.attr('d', path)
.style("fill", "red")
.style("stroke-width", "1")
.style("stroke", "black");
Enjoy, Cheers
I was looking around on the Internet for a fuss-free way to center my map, and got inspired by Jan van der Laan and mbostock's answer. Here's an easier way using jQuery if you are using a container for the svg. I created a border of 95% for padding/borders etc.
var width = $("#container").width() * 0.95,
height = $("#container").width() * 0.95 / 1.9 //using height() doesn't work since there's nothing inside
var projection = d3.geo.mercator().translate([width / 2, height / 2]).scale(width);
var path = d3.geo.path().projection(projection);
var svg = d3.select("#container").append("svg").attr("width", width).attr("height", height);
If you looking for exact scaling, this answer won't work for you. But if like me, you wish to display a map that centralizes in a container, this should be enough. I was trying to display the mercator map and found that this method was useful in centralizing my map, and I could easily cut off the Antarctic portion since I didn't need it.
The following seems to do approximately what you want. The scaling seems to be ok. When applying it to my map there is a small offset. This small offset is probably caused because I use the translate command to center the map, while I should probably use the center command.
In code:
var width = 300;
var height = 400;
var vis = d3.select("#vis").append("svg")
.attr("width", width).attr("height", height)
d3.json("nld.json", function(json) {
// create a first guess for the projection
var center = d3.geo.centroid(json)
var scale = 150;
var offset = [width/2, height/2];
var projection = d3.geo.mercator().scale(scale).center(center)
.translate(offset);
// create the path
var path = d3.geo.path().projection(projection);
// using the path determine the bounds of the current map and use
// these to determine better values for the scale and translation
var bounds = path.bounds(json);
var hscale = scale*width / (bounds[1][0] - bounds[0][0]);
var vscale = scale*height / (bounds[1][1] - bounds[0][1]);
var scale = (hscale < vscale) ? hscale : vscale;
var offset = [width - (bounds[0][0] + bounds[1][0])/2,
height - (bounds[0][1] + bounds[1][1])/2];
// new projection
projection = d3.geo.mercator().center(center)
.scale(scale).translate(offset);
path = path.projection(projection);
// add a rectangle to see the bound of the svg
vis.append("rect").attr('width', width).attr('height', height)
.style('stroke', 'black').style('fill', 'none');
vis.selectAll("path").data(json.features).enter().append("path")
.attr("d", path)
.style("fill", "red")
.style("stroke-width", "1")
.style("stroke", "black")
});
There is a center() method you can use that accepts a lat/lon pair.
From what I understand, translate() is only used for literally moving the pixels of the map. I am not sure how to determine what scale is.