javascript d3.js

javascript - Redimensionar svg cuando la ventana se redimensiona en d3.js



(5)

Estoy dibujando un diagrama de dispersión con d3.js. Con la ayuda de esta pregunta:
Obtenga el tamaño de la pantalla, la página web actual y la ventana del navegador

Estoy usando esta respuesta:

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;

Así que puedo adaptar mi trama a la ventana del usuario de esta manera:

var svg = d3.select("body").append("svg") .attr("width", x) .attr("height", y) .append("g");

Ahora me gustaría que algo se ocupe de cambiar el tamaño de la trama cuando el usuario cambie el tamaño de la ventana.

PD: No estoy usando jQuery en mi código.


Busque ''SVG responsivo''. Es bastante sencillo hacer que un SVG responda y ya no tendrá que preocuparse por los tamaños.

Así es como lo hice:

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

El código CSS:

.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; }

Más información / tutoriales:

http://thenewcode.com/744/Make-SVG-Responsive

http://soqr.fr/testsvg/embed-svg-liquid-layout-responsive-web-design.php


Es algo feo si el código de redimensionamiento es casi tan largo como el código para construir el gráfico en primer lugar. Entonces, en lugar de cambiar el tamaño de cada elemento del cuadro existente, ¿por qué no simplemente volver a cargarlo? Así es como funcionó para mí:

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... }

La línea crucial es d3.select(''svg'').remove(); . De lo contrario, cada cambio de tamaño agregará otro elemento SVG debajo del anterior.


Los diseños en vigor simplemente configurando los atributos ''alto'' y ''ancho'' no funcionarán para volver a centrar / mover el trazado en el contenedor svg. Sin embargo, hay una respuesta muy simple que funciona para Force Layouts que se encuentra here . En resumen:

Use el mismo (cualquier) evento que desee.

window.on(''resize'', resize);

Luego, suponiendo que tienes variables svg & force:

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

De esta forma, no vuelve a renderizar la gráfica por completo, establecemos los atributos y d3 vuelve a calcular las cosas según sea necesario. Esto al menos funciona cuando usas un punto de gravedad. No estoy seguro de si ese es un requisito previo para esta solución. ¿Alguien puede confirmar o negar?

Saludos, g


Use 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);

http://jsfiddle.net/Zb85u/1/


ACTUALIZA solo utiliza la nueva forma de @cminatti

vieja respuesta para propósitos históricos

IMO es mejor usar select () y on () ya que de esa manera puedes tener múltiples manejadores de eventos de tamaño ... simplemente no te vuelvas loco

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/