Изменение размера svg при изменении размера окна в d3.js
Я рисую диаграмму рассеяния с d3.js. С помощью этого вопроса :
получить размер экрана, текущей веб-страницы и окна браузера
Я использую этот ответ:
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;
поэтому я могу подогнать свой сюжет к окну пользователя следующим образом:
var svg = d3.select("body").append("svg")
.attr("width", x)
.attr("height", y)
.append("g");
теперь я хотел бы, чтобы что-то позаботилось об изменении размера сюжета, когда пользователь изменяет размер окна.
PS: я не использую jQuery в моем коде.
6 ответов:
ищите "отзывчивый SVG" довольно просто сделать SVG отзывчивым, и вам больше не нужно беспокоиться о размерах.
вот как я сделал это:
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);
код 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; }
Подробнее / туториалы:
http://thenewcode.com/744/Make-SVG-Responsive
http://soqr.fr/testsvg/embed-svg-liquid-layout-responsive-web-design.php
обновление просто используйте новый способ от @cminatti
старый ответ для исторических целей
IMO лучше использовать select() и on (), так как таким образом вы можете иметь несколько обработчиков событий изменения размера... только не сходи с ума
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/
это довольно уродливо, если код изменения размера почти такой же длинный, как код для построения графика в первую очередь. Поэтому вместо изменения размера каждого элемента существующей диаграммы, почему бы просто не перезагрузить его? Вот как это работало для меня:
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... }
решающая строка
d3.select('svg').remove();
. В противном случае каждое изменение размера добавит еще один элемент SVG ниже предыдущего.
в force layouts просто установка атрибутов "высота" и "ширина" не будет работать, чтобы повторно центрировать/перемещать участок в контейнер svg. Тем не менее, есть очень простой ответ, который работает для Force Layouts found здесь. Вкратце:
используйте то же самое (любое) событие, которое вам нравится.
window.on('resize', resize);
тогда предполагая, что у вас есть 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(); }
таким образом, вы не перерисовываете график полностью, мы устанавливаем атрибуты и D3 повторно вычисляет вещи по мере необходимости. Это по крайней мере работает, когда вы используете центра тяжести. Я не уверен, что это необходимое условие для этого решения. Кто-нибудь может подтвердить или опровергнуть ?
Ура, g