web-dev-qa-db-fra.com

d3.js mapper (<svg>) automatiquement dans le conteneur parent et redimensionner avec une fenêtre

MISE À JOUR: J'ai posté et accepté une solution pleinement opérationnelle dans la section des réponses. Tout code de cette section doit être utilisé comme référence pour la comparaison avec votre propre code NON-WORKING, mais ne doit pas être utilisé comme solution.


Je construis un tableau de bord et j'utilise d3.js pour ajouter une carte du monde qui tracera les tweets en temps réel en fonction de l'emplacement géographique.

Le fichier world.json référencé dans la ligne d3.json () est téléchargeable ICI (il s'appelle world-countries.json).

enter image description here

La carte se trouve sur la page en tant que conteneur SVG et est rendue à l'aide de d3.

Vous trouverez ci-dessous les tranches de code pertinentes. 

<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();
});

MISE À JOUR: j'ai redimensionné la carte à une taille acceptable (pour la taille de mon navigateur), mais elle ne sera toujours pas redimensionnée et centrée lorsque je changerai la taille de la fenêtre. SI, toutefois, je redimensionne la fenêtre, puis cliquez sur Actualiser, la carte sera centrée une fois la page rechargée. Cependant, étant donné que l'échelle est statique, elle n'est pas correctement mise à l'échelle.

enter image description here

27
Jon

SOLUTION COMPLETE:

Voici la solution qui redimensionnera la carte APRÈS que l'utilisateur ait publié le bord de la fenêtre pour la redimensionner et la centrer dans le conteneur parent. 

<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);
});
28
Jon

L'objet selection est un tableau multidimensionnel, même si dans la plupart des cas, il ne contiendra probablement qu'un seul objet. Cet objet a un champ "clientWidth" qui vous indique la largeur de son parent. 

Donc, vous pouvez faire ceci:

var selection = d3.select("#chart"); 
width = selection[0][0].clientWidth;
8
Spike Williams

Cela devrait fonctionner:

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

Le meilleur choix consiste à combiner les proportions avec la définition normale de la largeur et de la hauteur du graphique d3. Cela m'a aidé dans beaucoup de mes travaux graphiques.
Étape 1: Obtenez dynamiquement la hauteur de la div à laquelle le graphique doit être ajouté. 
Étape 2: Déclarez la largeur en format par rapport à la hauteur capturée dynamiquement.

var graph_div = document.getElementById(graph.divId);
graph.height = graph_div.clientHeight;
graph.width = (960/1200)*graph.height;
2
Raj sree

En d3 v4, nous pourrions le faire

const projection = d3.geo.equirectangular().fitSize([width, height], geojson);
const path = d3.geo.path().projection(projection);

fitSize est équivalent à 

fitExtent([[0, 0], [width, height]], geojson)

remplir libre d'ajouter du rembourrage

1
Bimal Grg