Thomas Deutsch
Thomas Deutsch

Reputation: 2544

d3 geo map overflow

I try to display my map in a div - but i want this map to be restricted to the div-size - right now, it ignores the w, and h values and the vis css setting, too.

Does it make any sense to set the svg height and width? when i put the scale of the projection up, it will always be bigger than the org. svg.

var w = 200;
var h = 300;

// this will attach a svg-element with the class "map" to "mydiv"
var map = d3.select("#mydiv").append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    .attr("class", "map"); 

var projection = d3.geo.albers()
    .origin([10.5,51])
    .scale(2000)
    .translate([100, 150]);

var path = d3.geo.path().projection(projection);

d3.json('germany.json', function(json) {
    map.selectAll('path')
        .data(json.features)
        .enter().append('path').attr('d', path);
});

and my css:

#vis {
    overflow: hidden;
    width: 350px;
    height: 220px;
}

Upvotes: 1

Views: 1430

Answers (1)

nrabinowitz
nrabinowitz

Reputation: 55678

There are basically two ways to scale D3 maps:

  • Scale the projection.

  • Put the map in a g element and set a transform on that element. This has the annoying side effect of scaling your stroke-width as well, so you might need to set a scaled stroke-width style on the g element.

In both cases, you're scaling the map without direct relation to container element. I don't think there's a way to scale to the container automatically - I think you need to get the width of the container via JS (here I use jQuery, but there are pure-JS options as well), then set the scale factor accordingly:

var containerWidth = $('#myDiv').width(),
    baseWidth = 1000,
    baseStrokeWidth = 1,
    scaleFactor = containerWidth/baseWidth;

// now use scaleFactor in a transform or projection scale, e.g.:
d3.select('g.mapContainer')
    .attr("transform", "scale(" + scaleFactor + ")")
    // and invert the scale to keep a constant stroke width:
    .style("stroke-width", baseStrokeWidth / scaleFactor + "px");

If your container size will change, you additionally need to set a window.onresize handler to recalculate the scale and update the transform. This is one reason to use a transformed g attribute instead of a projection scale - to handle the window resize, you don't have to reproject your whole map, just scale the existing paths up or down, a much faster operation.

Upvotes: 6

Related Questions