d3.geoPath is typically used to render spherical geometry by passing it through a geographic projection, projecting from the sphere to the plane while applying adaptive sampling. But what if your geometry is already planar? That is, what if you just want to take projected geometry, but still translate or scale it to fit the viewport?
You can implement a custom geometry transform to gain complete control over the projection process. Transforms implement the projection.stream method, and can be passed to path.projection in lieu of a geographic projection. The easiest way to implement a transform is d3.geoTransform. For example, here’s a 2D affine transform implementation:
function matrix(a, b, c, d, tx, ty) {
return d3.geoTransform({
point: function(x, y) {
this.stream.point(a * x + b * y + tx, c * x + d * y + ty);
}
});
}
For example, to invert the y-axis, you can say:
var path = d3.geoPath()
.projection(matrix(1, 0, 0, -1, 0, height));
A custom geometry transform can even use quantitative scales!