2013-04-28 165 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