2012-12-06 30 views
1

正如标题所述,我创建了D3线/面积图,我发现很难让图的宽度保持不变,这取决于我给出的数据量它渲染时,它会相应地缩放图形的宽度,但我不确定如何让它保持恒定的宽度,而不管给定的数据量如何,这是我想实现的。D3线图没有填充整个svg宽度

我想它与x和y坐标的缩放有关,但我暂时陷入困境,似乎无法弄清楚它为什么这样做。

这里是我迄今为止代码,

//dimensions and margins 
    var width = 625, 
    height = 350, 
    margin = 5, 

    // get the svg and set it's width/height 
    svg = d3.select("#main") 
    .attr("width", width) 
    .attr("height", height); 

    //initialize the graph 
    init([ 
     [12345,42345,32345,22345,72345,62345,32345,92345,52345,22345], 
     [1234,4234,3234,2234,7234,6234,3234,9234,5234,2234] 
     ]); 

    $("button").live('click', function(){ 
     var id = $(this).attr("id"); 
     if(id == "one"){ 
     updateGraph([ 
       [52345,32345,12345,22345,62345,72345,92345,32345,22345,22345,52345,32345,12345,22345,62345,72345,92345,32345,22345,22345,52345,32345,12345,22345,62345,72345,92345,32345,22345,22345], 
       [4234,12345,2234,32345,6234,7234,9234,3234,2234,2234,4234,1234,2234,3234,6234,7234,9234,3234,2234,2234,4234,1234,2234,3234,6234,7234,9234,3234,2234,2234] 
       ]); 
     }else if(id == "two"){ 
     updateGraph([ 
       [12345,42345,32345,22345,72345,62345,32345,92345,52345,22345,12345,42345,32345,22345,72345,62345,32345,92345,52345,22345,12345,42345,32345,22345,72345], 
       [1234,2345,3234,2234,7234,6234,3234,9234,5234,2234,1234,4234,3234,2234,7234,6234,3234,9234,5234,2234,1234,4234,3234,2234,7234] 
      ]); 
     } 

    }); 

function init(data){ 

    var x = d3.scale.linear() 
    .domain([0,data[0].length]) 
    .range([margin, width-margin]), 

    y = d3.scale.linear() 
    .domain([0,d3.max(data[0])]) 
    .range([height-margin, margin]), 

    /* line path generator */ 
    line = d3.svg.line().interpolate('monotone') 
    .x(function(d,i) { return x(i); }) 
    .y(function(d) { return y(d); }), 

    /* area path generator */ 
    area = d3.svg.area().interpolate('monotone') 
    .x(line.x()) 
    .y1(line.y()) 
    .y0(y(0)), 

    groups = svg.selectAll("g") 
    .data(data) 
    .enter() 
    .append("g"); 

    svg.select("g") 
    .selectAll("circle") 
    .data(data[0]) 
    .enter() 
    .append("circle") 
    .attr("class", "dot") 
    .attr("cx", line.x()) 
    .attr("cy", line.y()) 
    .attr("r", 4); 

    /* add the areas */ 
    groups.append("path") 
    .attr("class", "area") 
    .attr("d",area) 
    .style("fill", function(d,i) { return (i == 0 ? "steelblue" : "red"); }); 

    /* add the lines */ 
    groups.append("path") 
    .attr("class", "line") 
    .attr("d", line); 
} 

function updateGraph(data){ 

    var x = d3.scale.linear() 
    .domain([0,data[0].length]) 
    .range([margin, width-margin]), 

    y = d3.scale.linear() 
    .domain([0,d3.max(data[0])]) 
    .range([height-margin, margin]), 

    /* line path generator */ 
    line = d3.svg.line().interpolate('monotone') 
    .x(function(d,i) { return x(i); }) 
    .y(function(d) { return y(d); }), 

    /* area path generator */ 
    area = d3.svg.area().interpolate('monotone') 
    .x(line.x()) 
    .y1(line.y()) 
    .y0(y(0)); 

    groups = svg.selectAll("g") 
    .data(data), 

    circles = svg.select("g") 
    .selectAll("circle"); 

    circles.data(data[0]) 
     .exit().remove(); 

    circles.data(data[0]) 
    .enter().append("circle") 
     .attr("class", "dot") 
     .attr("cx", line.x()) 
     .attr("cy", line.y()) 
     .attr("r", 4); 

    /* animate circles */ 
    circles.data(data[0]) 
    .transition() 
    .duration(1000) 
    .attr("cx", line.x()) 
    .attr("cy", line.y()); 

    /* animate the lines */ 
    groups.select('.line') 
    .transition() 
    .duration(1000) 
    .attr("d",line); 

    /* animate the areas */ 
    groups.select('.area') 
    .transition() 
    .duration(1000) 
    .attr("d",area); 

} 

除了作为一个小提琴http://jsfiddle.net/JL33M/

谢谢!

回答

1

图的宽度取决于您给的range()range([0,100])将始终“拉伸”domain()值以占用100个单位。

这是目前你的代码是做什么的:

var x = d3.scale.linear() 
    .domain([0,data[0].length]) 
    .range([margin, width-margin]);// <-- always a fixed width 

所需的宽度依赖于数据条目的数量。说你已经决定你想要的每个数据点占用5个单位,那么range()需要依赖于数据集的大小:

var x = d3.scale.linear() 
    .domain([0,data[0].length]) 
    .range([margin, 5 * data[0].length]);// <-- 5 units per data point 

当然,在这些情况下,您的图形宽度增长与数据集;如果你给它一个非常长的数据数组,例如500点,那么这个图表就会有2500个单位的宽度,并且很可能在屏幕上运行。但如果你的数据是这样的,你知道它的最大长度,那么你会没事的。

在一个不相关的说明中,我认为你的代码可以使用重构来减少重复性。您应该可以通过一个update()函数来实现您正在做的工作,而无需使用init()函数。

This tutorial by mbostock描述我所指的“一般更新模式”。部分IIIII然后继续解释如何工作转换到这种模式。

+0

感谢您的详细解答! :)有一点让我困惑,虽然我指定了一个固定的宽度,但图表从来没有填满整个容器,我知道它会缩放,但是如果它不能将图形放大到宽度和高度,我会给它?我认为这是非常不一致的,尽管它是有道理的,但它在试图实现数据集之间的一致性时会产生一个真正的问题。所以,如果我正确地理解了你,我的代码应该会产生一个图形,以适应我指定它使用的整个宽度。 – Odyss3us

+0

是不是因为你减去了保证金? –

+0

如果只是它会“拉伸”域值,以某种理智的方式。结果根本没有模式。有时候,较大的值会得到一个瘦的结果,而较小的值会得到一个宽的结果有时候情况恰恰相反。应该发生什么,最长的条被设置为最大宽度,并且所有其他比例都按比例缩放。 – JosephK