You are right, the error is in the projection.
But, the error depends on if your data is projected or unprojected (lat long pairs).
Unprojected Data
If you have data that is in WGS84 - that is to say lat long pairs, then you have this problem:
Using your projection, but changing only the data source I get something like this (I shaved off the empty ocean on the right):

To center a Mercator properly, you need to know the center coordinate of your area of interest. This generally can be fairly general, for Switzerland I might try 47N 8.25E.
Once you have this coordinate you need to place it in the middle. One way is to rotate on the x axis and center on the y:
var projection = d3.geo.mercator()
.scale(3500)
.rotate([-8.25,0])
.center([0,47])
.translate([width/2,height/2])
Note that the x rotation is negative, you are spinning the globe underneath the projection.
The other option is to rotate on both x and y, this is likely the preferred option as you approach the poles - as Mercator distortion becomes unworkable at high latitudes. This approach would look like:
var projection = d3.geo.mercator()
.scale(4000)
.rotate([-8.25,-47])
.center([0,0])
.translate([width/2,height/2])
Note again the negative rotation values. The second option requires a higher scale value as this method essentially treats Switzerland as though it were at zero,zero on a Mercator projection - and along the equator land sizes are minimized.
Using the second of these projections, I get:

So you'll have to dial in the scale a bit, but now you should be able to see your data (assuming your data is in proper lat long pairs).
Projected Data
Based on the comment below, which includes a linked json file, we can see that this is your problem.
There are two potential solutions to this:
- Convert the data to lat long pairs
- Use a geoTransform
Option one is the easiest, you'll unproject the data - which requires knowing the current projection. In GIS software this will generally be projecting it as WGS84, which is arguably not really a projection but a datum. Once you have your lat long pairs, you follow the steps above for unprojected data.
Option two skips a d3.geoProjection altogether. Instead, we'll create a transform function that will convert the projected coordinates to the desired SVG coordinates.
A geo projection looks like:
function scale (scaleFactor) {
return d3.geo.transform({
point: function(x, y) {
this.stream.point(x * scaleFactor, (y * scaleFactor);
}
});
}
And is used like a projection:
var path = d3.geo.path().projection(scale(0.1));
It simply takes a stream of x,y coordinates that are already cartesian and transforms them in a specified manner.
To translate the map so it is centered you'll need to know the center coordinate. You can find this with path.bounds
:
var bounds = path.bounds(features);
var centerX = (bounds[0][0] + bounds[1][0])/2;
var centerY = (bounds[0][1] + bounds[1][1])/2;
Path.bounds returns the top left corner and bottom right corner of a feature. This is the key part, you can make an autoscaling function, there are plenty of examples out there, but I like manually scaling often. If the map is centered, this is easy. For your map, your geoTransform might look like:
function scale (scaleFactor,cx,cy,width,height) {
return d3.geo.transform({
point: function(x, y) {
this.stream.point((x-cx) * scaleFactor + width/2, (y-cy) * scaleFactor +height/2);
}
});
}
Here cx
and cy
refer to the middle of your feature and the width and height refer to the width and height of the svg element - we don't want features clustered at SVG point [0,0].
Altogether, that gives us something like (with a scale factor of 0.002):

Here's an updated JSbin: http://jsbin.com/wolamuzeze/edit?html,output
Keep in mind that scale is dependent on window size as your width/height are relative to window size in your case. This might be best addressed with automatically setting the zoom level, though this can create problems if you have labels (for example).
This answer might help as well: Scaling d3 v4 map to fit SVG (or at all)