Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.js Map (<svg>) Auto Fit into Parent Container and Resize with Window

UPDATE: I have posted and accepted a fully working solution in the answers section. Any code in this section is to be used as reference for comparison to your own NON-WORKING code, but is not to be used as the solution.


I'm building a dashboard and using d3.js to add a world map that will plot tweets in real time based on geo location.

The world.json file referenced in the d3.json() line is downloadable HERE (it's called world-countries.json).

enter image description here

The map is on the page as an SVG container and is rendered using d3.

Below are the relevant code slices.

<div id="mapContainer">     <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="500"></svg> </div> 

#mapContainer svg {     display:block;     margin:0 auto; } #mapContainer path {   fill:#DDD;   stroke:#FFF; } 

// generate US plot function draw() {     var map = d3.select("svg");     var width = $("svg").parent().width();     var height = $("svg").parent().height();      var projection = d3.geo.equirectangular().scale(185).translate([width/2, height/2]);     var path = d3.geo.path().projection(projection);     d3.json('plugins/maps/world.json', function(collection) {         map.selectAll('path').data(collection.features).enter()             .append('path')             .attr('d', path)             .attr("width", width)             .attr("height", height);     }); } draw(); latestLoop(); 

$(window).resize(function() {     draw(); }); 

UPDATE: I have scaled the map to an acceptable size (for my particular browser size), but it still will not scale and center when I change the size of the window. IF, however, I resize the window, then hit refresh, then the map will be centered once the page is reloaded. However, since the scale is static, it is not scaled properly.

enter image description here

like image 642
Jon Avatar asked Jan 10 '13 18:01

Jon


2 Answers

COMPLETE SOLUTION:

Here's the solution which will resize the map AFTER the user has released the edge of the window to resize it, and center it in the parent container.

<div id="mapContainer"></div> 

function draw(ht) {     $("#mapContainer").html("<svg id='map' xmlns='http://www.w3.org/2000/svg' width='100%' height='" + ht + "'></svg>");     map = d3.select("svg");     var width = $("svg").parent().width();     var height = ht;      // I discovered that the unscaled equirectangular map is 640x360. Thus, we     // should scale our map accordingly. Depending on the width ratio of the new     // container, the scale will be this ratio * 100. You could also use the height      // instead. The aspect ratio of an equirectangular map is 2:1, so that's why     // our height is half of our width.      projection = d3.geo.equirectangular().scale((width/640)*100).translate([width/2, height/2]);     var path = d3.geo.path().projection(projection);     d3.json('plugins/maps/world.json', function(collection) {         map.selectAll('path').data(collection.features).enter()             .append('path')             .attr('d', path)             .attr("width", width)             .attr("height", width/2);     }); } draw($("#mapContainer").width()/2); 

$(window).resize(function() {     if(this.resizeTO) clearTimeout(this.resizeTO);     this.resizeTO = setTimeout(function() {         $(this).trigger('resizeEnd');     }, 500); });  $(window).bind('resizeEnd', function() {     var height = $("#mapContainer").width()/2;     $("#mapContainer svg").css("height", height);     draw(height); }); 
like image 167
Jon Avatar answered Oct 06 '22 00:10

Jon


The selection object is an multidimensional array, although in most cases it will probably have only one object in it. That object has a "clientWidth" field that tells you how wide its parent is.

So you can do this:

var selection = d3.select("#chart");  width = selection[0][0].clientWidth; 
like image 23
Spike Williams Avatar answered Oct 06 '22 01:10

Spike Williams