2013-01-10 11 views
26

AGGIORNAMENTO: Ho inserito e accettato una soluzione pienamente funzionante nella sezione delle risposte. Qualsiasi codice in questa sezione deve essere utilizzato come riferimento per il confronto con il proprio codice NON FUNZIONANTE, ma non deve essere utilizzato come soluzione.Mappa d3.js (<svg>) Adatta automaticamente nel contenitore principale e ridimensiona con finestra


Sto costruendo una cruscotto e utilizzando d3.js per aggiungere una mappa del mondo che tracciare i tweet in tempo reale in base alla posizione geografica.

Il world.json file di riferimento nella linea d3.json() è scaricabile HERE (si chiama mondo-countries.json).

enter image description here

La mappa è sulla pagina come un contenitore SVG e viene reso utilizzando d3.

Di seguito sono riportate le sezioni di codice rilevanti.

<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: ho scalato la mappa per una dimensione accettabile (per il mio particolare dimensione del browser), ma ancora non si scala e centro quando cambio la dimensione della finestra. SE, tuttavia, ridimensiono la finestra, quindi clicco su Aggiorna, quindi la mappa sarà centrata quando la pagina verrà ricaricata. Tuttavia, poiché la scala è statica, non viene ridimensionata correttamente.

enter image description here

risposta

28

SOLUZIONE COMPLETA:

Ecco la soluzione che ridimensionare la mappa dopo che l'utente ha rilasciato il bordo della finestra per ridimensionarla e centrarlo nel contenitore principale.

<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); 
}); 
+2

Non sta riscrivendo tutto? Come posso evitare questo? – Arkanoid

+0

@arkanoid Forse ... questa soluzione ha funzionato per me, quindi se questo è in definitiva ciò che sta facendo, allora * scrollate le spalle *. Non ho indagato su come d3 sta rendendo le cose, quindi se la mia soluzione è in realtà solo una riscrittura, allora suppongo che sia così che si fa. – Jon

4

Questo dovrebbe funzionare:

<svg 
    xmlns="http://www.w3.org/2000/svg" 
    width="860" 
    height="500" 
    viewBox="0 0 860 500" 
    preserveAspectRatio="xMinYMin meet"> 
+1

Quindi questo riempie il contenitore, ma il ridimensionamento della mappa è mooolto zumato. Esiste un modo per farlo scalare in base alle dimensioni del contenitore? Non mi interessa se devo usare jQuery o javascript, ma non so quali valori dovrei cambiare. – Jon

+0

Si desidera regolare la scala() della proiezione oltre a regolare le impostazioni della finestra di visualizzazione. Se sei interessato a mostrare più o meno la mappa da una prospettiva geospaziale a seconda di quanto spazio sullo schermo hai, allora non vorrai fare affidamento sul metodo viewBox, ma piuttosto riproiettare o ruotare in base al cambiamento larghezza e altezza del contenitore. – Elijah

8

L'oggetto di selezione è un array multidimensionale, sebbene nella maggior parte dei casi sarà probabilmente un solo oggetto in esso. Quell'oggetto ha un campo "clientWidth" che ti dice quanto è largo il suo genitore.

modo da poter fare questo:

var selection = d3.select("#chart"); 
width = selection[0][0].clientWidth; 
+2

Dal momento che non l'ho guardato per un po ', ti crederò sulla parola. Un Fiddle potrebbe aiutare le persone future se hai tempo, ma grazie per la tua risposta! – Jon

+0

Con d3v4, la seconda riga deve essere 'selection._groups [0] [0] .clientWidth' – AlexG

2

La scelta migliore è quella di avere un uso combinato di rapporto di forma normale definizione di larghezza e l'altezza del grafico d3. Questo mi ha aiutato in molti dei miei lavori grafici.
Passaggio 1: ottenere dinamicamente l'altezza del div a cui deve essere aggiunto il grafico.
Passaggio 2: dichiarare la larghezza come rapporto aspetto rispetto all'altezza rilevata dinamicamente.

var graph_div = document.getElementById(graph.divId); 
graph.height = graph_div.clientHeight; 
graph.width = (960/1200)*graph.height; 
Problemi correlati