2016-07-16 35 views
0

我想将新栏添加到现有的d3条形图并使其成为实时图。带有自定义栏宽的实时d3条形图

我可以看到酒吧正在更新,但标签没有对齐时,酒吧重新调整。

var margin = { 
    top: 20, 
    right: 20, 
    bottom: 30, 
    left: 40 
    }, 
    width = 960 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

var x = d3.scale.ordinal() 
    .rangeRoundBands([0, width], .1); 

var y = d3.scale.linear() 
    .range([height, 0]); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(y) 
    .orient("left") 
    .ticks(10, "%"); 

var svg = d3.select("body").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

svg.append("g") 
    .attr("class", "x axis") 
    .attr("transform", "translate(0," + height + ")") 

svg.append("g") 
    .attr("class", "y axis") 
    .append("text") // just for the title (ticks are automatic) 
    .attr("transform", "rotate(-90)") // rotate the text! 
    .attr("y", 6) 
    .attr("dy", ".71em") 
    .style("text-anchor", "end") 
    .text("Frequency"); 

function draw(data) { 
    x.domain(data.map(function(d) { 
    return d.letter; 
    })); 
    y.domain([0, d3.max(data, function(d) { 
    return d.frequency; 
    })]); 
var labels = svg 
    .selectAll(".bartext") 
    .data(data, function(d) { 
     return d.letter; 
    }); 
labels 
.exit() 
.remove(); 

labels 
    .enter() 
    .append("text") 
    .attr("class", "bartext") 
    .attr("text-anchor", "middle") 
    .attr("fill", "black") 
    .attr("x", function(d, i) { 
    return x(d.letter) + 7.5; 
    }) 
    .attr("y", function(d, i) { 
    return height + 15; 
    }) 
    .text(function(d, i) { 
    return d.letter; 
    }); 
    svg.select(".y.axis").transition().duration(300).call(yAxis) 

    var bars = svg.selectAll(".bar").data(data, function(d) { 
     return d.letter; 
    }) 
    bars.exit() 
    .transition() 
    .duration(300) 
    .remove(); 

    bars.enter().append("rect") 
    .attr("class", "bar"); 

    bars.transition().duration(300).attr("x", function(d) { 
     return x(d.letter); 
    }) 
    .attr("width", 15) 
    .attr("y", function(d) { 
     return y(d.frequency); 
    }) 
    .attr("height", function(d) { 
     return height - y(d.frequency); 
    }); 
} 
var data1 = [{ 
    "letter": 'A', 
    "frequency": .00167 
}]; 

var data2 = [{ 
    "letter": 'A', 
    "frequency": .01167 
},{ 
    "letter": 'I', 
    "frequency": .01477 
}]; 

draw(data1); 

setTimeout(function() { 
    draw(data2); 
}, 2000); 

https://jsfiddle.net/foh7cgst/

回答

2

这里的selection.enter() documentation的相关部分:

VAR update_sel = svg.selectAll( “圆”)的数据(数据)

update_sel.attr(/*仅在旧元素上操作* /)

update_sel.enter()。append(“circle”)。attr(/ * * opera TE新元素 仅* /)

update_sel.attr(/ *对新旧元素* /)

update_sel.exit()。remove()方法/ *完整的输入更新退出运营模式 */

正如你所看到的,当你追加到输入选择,只有后面的操作目标被追加的新要素。

如果您想要定位新元素和旧元素,则应在输入节点后对更新选项进行操作。

因此,使用您的示例代码是draw函数里面,这一点:

labels.enter().append("text") 
    .attr("class", "bartext") 
    .attr("text-anchor", "middle") 
    .attr("fill", "black") 
    .attr("x", function(d, i) { 
    return x(d.letter) + 7.5; 
    }) 
    .attr("y", function(d, i) { 
    return height + 15; 
    }) 
    .text(function(d, i) { 
    return d.letter; 
    }); 

应改为这样:

labels.enter().append("text") 
    .attr("class", "bartext") 
    .attr("text-anchor", "middle") 
    .attr("fill", "black") 
    .attr("y", height + 15); 

labels 
    .attr("x", function(d) { 
    return x(d.letter) + 7.5; 
    }) 
    .text(function(d) { 
    return d.letter; 
    }); 
+0

ohh我的坏..在这里解决了这个问题。 –

+0

酒吧逻辑不同于标签逻辑。注意,首先你为'bars'输入()。append()',然后**转换并定位所有'bars',包括旧的和新的。 – Ashitaka

+1

顺便说一句,因为这种行为完全不明显,所以在新的D3版本中进行了更改。如果您想了解更多信息,Mike Bostock最近撰写了一篇关于这个主题的精彩文章https://medium.com/@mbostock/what-makes-software-good-943557f8a488#708a – Ashitaka

1

取而代之的是:

labels 
    .enter() 
    .append("text") 
    .attr("class", "bartext") 
    .attr("text-anchor", "middle") 
    .attr("fill", "black") 
    .attr("x", function(d, i) { 
    return x(d.letter) + 7.5; 
    }) 
    .attr("y", function(d, i) { 
    return height + 15; 
    }) 
    .text(function(d, i) { 
    return d.letter; 
    }); 

这样做:

labels 
    .enter() 
    .append("text") 
    .attr("class", "bartext"); 
    //update all the bar text. 
    svg 
    .selectAll(".bartext").attr("text-anchor", "middle") 
    .transition().duration(300) 
    .attr("fill", "black") 
    .attr("x", function(d, i) { 
     return x(d.letter) + 7.5; 
    }) 
    .attr("y", function(d, i) { 
     return height + 15; 
    }) 
    .text(function(d, i) { 
     return d.letter; 
    }); 

在第一种情况下,它不起作用,因为属性只会更新为新数据,更新的数据不会更新到DOM。

工作代码here

+1

感谢您的帮助 –