Ich zeichne mit d3.js ein Streudiagramm. Mit Hilfe dieser Frage:
Liefert die Größe des Bildschirms, die aktuelle Webseite und das Browserfenster
Ich verwende diese Antwort:
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth,
y = w.innerHeight|| e.clientHeight|| g.clientHeight;
So kann ich mein Plot wie folgt an das Fenster des Benutzers anpassen:
var svg = d3.select("body").append("svg")
.attr("width", x)
.attr("height", y)
.append("g");
Nun möchte ich, dass sich die Größe der Grafik ändert, wenn der Benutzer die Größe des Fensters ändert.
PS: Ich verwende nicht jQuery in meinem Code.
Suchen Sie nach 'responsive SVG'. Es ist ziemlich einfach, eine SVG-Funktion zu aktivieren, und Sie müssen sich nicht mehr um die Größe kümmern.
So habe ich es gemacht:
d3.select("div#chartId")
.append("div")
.classed("svg-container", true) //container class to make it responsive
.append("svg")
//responsive SVG needs these 2 attributes and no width and height attr
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 600 400")
//class to make it responsive
.classed("svg-content-responsive", true);
Der CSS-Code:
.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%; /* aspect ratio */
vertical-align: top;
overflow: hidden;
}
.svg-content-responsive {
display: inline-block;
position: absolute;
top: 10px;
left: 0;
}
Weitere Infos/Tutorials:
http://thenewcode.com/744/Make-SVG-Responsive
http://soqr.fr/testsvg/embed-svg-liquid-layout-responsive-web-design.php
Verwenden Sie window.onresize :
function updateWindow(){
x = w.innerWidth || e.clientWidth || g.clientWidth;
y = w.innerHeight|| e.clientHeight|| g.clientHeight;
svg.attr("width", x).attr("height", y);
}
d3.select(window).on('resize.updatesvg', updateWindow);
UPDATE benutze einfach den neuen Weg von @cminatti
alte Antwort für historische Zwecke
IMO ist es besser, select () und on () zu verwenden, da auf diese Weise mehrere Event-Handler für die Größenänderung verwendet werden können
d3.select(window).on('resize', resize);
function resize() {
// update width
width = parseInt(d3.select('#chart').style('width'), 10);
width = width - margin.left - margin.right;
// resize the chart
x.range([0, width]);
d3.select(chart.node().parentNode)
.style('height', (y.rangeExtent()[1] + margin.top + margin.bottom) + 'px')
.style('width', (width + margin.left + margin.right) + 'px');
chart.selectAll('rect.background')
.attr('width', width);
chart.selectAll('rect.percent')
.attr('width', function(d) { return x(d.percent); });
// update median ticks
var median = d3.median(chart.selectAll('.bar').data(),
function(d) { return d.percent; });
chart.selectAll('line.median')
.attr('x1', x(median))
.attr('x2', x(median));
// update axes
chart.select('.x.axis.top').call(xAxis.orient('top'));
chart.select('.x.axis.bottom').call(xAxis.orient('bottom'));
}
http://eyeseast.github.io/visible-data/2013/08/28/responsive-charts-with-d3/
Es ist ziemlich hässlich, wenn der Code zur Größenänderung fast so lang ist wie der Code zum Erstellen des Diagramms an erster Stelle. Anstatt also jedes Element des vorhandenen Diagramms zu ändern, laden Sie es einfach neu. So funktioniert es für mich:
function data_display(data){
e = document.getElementById('data-div');
var w = e.clientWidth;
// remove old svg if any -- otherwise resizing adds a second one
d3.select('svg').remove();
// create canvas
var svg = d3.select('#data-div').append('svg')
.attr('height', 100)
.attr('width', w);
// now add lots of beautiful elements to your graph
// ...
}
data_display(my_data); // call on page load
window.addEventListener('resize', function(event){
data_display(my_data); // just call it again...
}
Die entscheidende Linie ist d3.select('svg').remove();
. Andernfalls wird bei jeder Größenänderung ein weiteres SVG-Element unterhalb des vorherigen hinzugefügt.
In Force-Layouts können durch einfaches Festlegen der Attribute 'height' und 'width' die Darstellung nicht erneut zentriert oder in den svg-Container verschoben werden. Es gibt jedoch eine sehr einfache Antwort, die für erzwungene Layouts here funktioniert. In Summe:
Verwenden Sie dasselbe (beliebige) Event, das Sie möchten.
window.on('resize', resize);
Dann nehmen wir an, Sie haben SVG & Force-Variablen:
var svg = /* D3 Code */;
var force = /* D3 Code */;
function resize(e){
// get width/height with container selector (body also works)
// or use other method of calculating desired values
var width = $('#myselector').width();
var height = $('#myselector').height();
// set attrs and 'resume' force
svg.attr('width', width);
svg.attr('height', height);
force.size([width, height]).resume();
}
Auf diese Weise rendern Sie den Graphen nicht vollständig neu, wir setzen die Attribute und d3 berechnet die Dinge nach Bedarf neu. Dies funktioniert zumindest, wenn Sie einen Schwerpunkt verwenden. Ich bin mir nicht sicher, ob dies eine Voraussetzung für diese Lösung ist. Kann jemand das bestätigen oder dementieren?
Prost, g
Für diejenigen, die kraftgerichtete Graphen in D3 v4/v5 verwenden, ist die size
-Methode nicht mehr vorhanden. Etwas wie das folgende funktionierte für mich (basierend auf dieser Github-Ausgabe ):
simulation
.force("center", d3.forceCenter(width / 2, height / 2))
.force("x", d3.forceX(width / 2))
.force("y", d3.forceY(height / 2))
.alpha(0.1).restart();
Ich verwende window.innerWidth für die Breite des Clients und window.innerHeight für die Höhe des Clients.
Wenn Sie eine benutzerdefinierte Logik binden möchten, um die Ereignisgröße zu ändern, können Sie mit today die ResizeObserver-Browser-API für den Begrenzungsrahmen eines SVGElement verwenden.
Dies behandelt auch den Fall, wenn die Größe des Containers aufgrund der Änderung der nahen Elemente geändert wird.
Es gibt eine polyfill für eine breitere Browserunterstützung.
So kann es in der UI-Komponente funktionieren:
<div class="container">
<svg></svg>
</div>
Komponente:
// Setup observer in constructor
const container = document.querySelector('.container')
const resizeObserver = new ResizeObserver((entries, observer) => {
// on resize logic specific to this component
})
resizeObserver.observe(container)
// unobserve in component destroy method
this.resizeObserver.disconnect()