webentwicklung-frage-antwort-db.com.de

d3.js Karte (<svg>) In den übergeordneten Container automatisch anpassen und die Größe mit Fenster ändern

UPDATE: Ich habe im Antwortbereich eine voll funktionsfähige Lösung veröffentlicht und akzeptiert. Jeder Code in diesem Abschnitt dient als Referenz für den Vergleich mit Ihrem eigenen NICHT ARBEITENDEN Code, jedoch nicht als Lösung.


Ich baue ein Dashboard und verwende d3.js, um eine Weltkarte hinzuzufügen, die Tweets in Echtzeit basierend auf dem geografischen Standort plottet.

Die world.json -Datei, auf die in der Zeile d3.json () verwiesen wird, kann HERE heruntergeladen werden (sie heißt world-countries.json).

enter image description here

Die Karte befindet sich auf der Seite als SVG-Container und wird mit d3 gerendert.

Nachfolgend finden Sie die relevanten 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: Ich habe die Karte auf eine akzeptable Größe (für meine bestimmte Browsergröße) skaliert, sie wird jedoch immer noch nicht skaliert und zentriert, wenn ich die Größe des Fensters ändere. Wenn ich jedoch das Fenster verkleinere, dann auf Aktualisieren klicke, wird die Karte zentriert, sobald die Seite neu geladen wird. Da die Waage jedoch statisch ist, wird sie nicht richtig skaliert.

enter image description here

27
Jon

KOMPLETTE LÖSUNG:

Hier ist die Lösung, bei der die Größe der Karte geändert wird, nachdem der Benutzer den Rand des Fensters freigegeben hat, um die Größe zu ändern und im übergeordneten Container zu zentrieren. 

<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

Das Auswahlobjekt ist ein mehrdimensionales Array, obwohl es in den meisten Fällen wahrscheinlich nur ein Objekt enthält. Dieses Objekt verfügt über ein Feld "clientWidth", in dem die Breite des übergeordneten Objekts angegeben wird. 

So kannst du das machen:

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

Das sollte funktionieren:

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

Die beste Wahl ist die kombinierte Verwendung des Seitenverhältnisses bei der normalen Definition der Breite und Höhe des d3-Diagramms. Das hat mir bei vielen Graphiken geholfen.
Schritt 1: Dynamisch die Höhe des divs ermitteln, an das der Graph angehängt werden soll. 
Schritt 2: Breite als Seitenverhältnis in Bezug auf die dynamisch erfasste Höhe angeben.

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

In d3 v4 könnten wir das tun

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

fitSize ist äquivalent zu 

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

füllen Sie frei, um Auffüllen hinzuzufügen

1
Bimal Grg