2013-04-28 163 views
139

我正在用d3.js绘制散点图。带着这个问题的帮助:
Get the size of the screen, current web page and browser window在d3.js中调整窗口大小时调整svg的大小

我用这样的回答:

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。

+1

可能的重复[什么是使d3.js可视化布局响应的最佳方式?](http://stackoverflow.com/questions/9400615/whats-the-best-way-to-make-a-d3-js -visualisation-layout-responsive) – ColinE 2016-06-26 18:01:21

回答

218

查找“响应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

+8

这更加优雅,也使用了应该在每个前端开发人员工具箱中使用的容器缩放方法(可用于缩放特定纵横比的任何东西)。应该是最好的答案。 – kontur 2015-06-02 09:36:04

+10

只需添加到: 'viewBox'属性应设置为SVG图的相关高度和宽度: '.attr(“viewBox”,“0 0”+ width +“”+ height)' 其中'width'和'height'在其他地方定义。也就是说,除非你想让SVG在视图框中剪切。 您可能还需要更新css中的'padding-bottom'参数以匹配svg元素的长宽比。 虽然很好的回应 - 非常有帮助,并且很有帮助。谢谢! – 2015-06-18 04:24:59

+0

这真是太棒了! – 2015-10-01 15:53:00

36

使用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/

+11

这不是一个好的答案,因为它涉及到DOM事件的绑定......更好的解决方案是只使用d3和css – alem0lars 2015-03-23 08:40:28

32

UPDATE只是用新的方式,从@cminatti


老答案历史性的目的

IMO它更好地使用select()和(),因为这样你可以有多个调整大小事件处理程序...只是不要太疯狂

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/

+0

我不能同意更少。 cminatti的方法将适用于我们处理的所有d3js文件。这种使用每个图表调整大小的方法是矫枉过正的。此外,我们需要为每个可能的图表重新编写我们可以想到的图表。上面提到的方法适用于一切。我已经尝试了4种食谱,包括你提到的重载类型,并且它们都不适用于立体派中使用的多区域情节。 – 2016-03-15 11:11:48

+1

@EamonnKenny我不能同意你的看法。在未来7个月的其他答案是优越的:) – slf 2016-03-15 16:43:57

+0

对于这种方法:“d3.select(window).on”我无法找到“d3.select(window).off”或“d3.select(window)”。取消绑定“ – 2016-04-27 10:17:45

11

这是一种丑陋如果调整大小的代码几乎与创建图形的代码一样长。因此,而不是调整现有图表的每个元素,为什么不简单地重新加载呢?下面是它是如何工作的:

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元素。

+0

这绝对会杀死性能,如果你是重绘每个窗口上的整个元素resize事件 – sdemurjian 2016-08-25 17:01:42

7

只需设置'高度'和'宽度'属性,强制布局将无法将图形重新居中/移动到svg容器中。但是,有一个非常简单的答案,适用于Force Layouts找到的here。总结:

使用相同的(任何)事件你喜欢。

window.on('resize', resize); 

然后假设你有SVG &力变量:

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

+0

这对我的强制布局具有约100个连接完美。谢谢。 – tribe84 2016-11-19 19:22:07