Redimensionar svg cuando la ventana se redimensiona en d3.js


Estoy dibujando una gráfica 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 soy capaz de ajustar mi parcela 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 encargue de cambiar el tamaño de la gráfica cuando el usuario cambie el tamaño de la ventana.

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

Author: Community, 2013-04-28

6 answers

Busca 'responsive SVG' es bastante simple hacer un SVG responsive y ya no tienes que preocuparte 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

 246
Author: cminatti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-28 10:53:41

Utilice la ventana .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 /

 40
Author: Adam Pearce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-15 23:46:59

ACTUALIZAR simplemente use la nueva forma de @cminatti


Antigua respuesta para propósitos históricos

IMO es mejor usar select() y on() ya que de esa manera puede tener múltiples controladores de eventos de redimensionamiento... simplemente no te vuelvas demasiado 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 /

 32
Author: slf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-15 16:45:36

Es un poco 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 gráfico existente, ¿por qué no simplemente recargarlo? 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 redimensionamiento agregará otro elemento SVG debajo del anterior.

 12
Author: Raik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-03 02:46:21

En force layouts simplemente establecer los atributos 'height' y 'width' no funcionará para volver a centrar/mover la gráfica en el contenedor svg. Sin embargo, hay una respuesta muy simple que funciona para los diseños de fuerza que se encuentran aquí. En resumen:

Use el mismo (cualquier) evento que desee.

window.on('resize', resize);

Entonces asumiendo que tiene 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 manera, no se vuelve a renderizar el gráfico por completo, establecemos los atributos y d3 vuelve a calcular las cosas según sea necesario. Esto en menos funciona cuando se utiliza un punto de gravedad. No estoy seguro de si eso es un requisito previo para esta solución. ¿Alguien puede confirmar o negar ?

Salud, g

 8
Author: gavs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-12 21:31:41

Uso ventana.innerWidth para el ancho y la ventana del cliente.Altura interior para la altura del cliente.

 0
Author: Akshay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-24 17:38:14