渲染多个 d3 图表而不相互覆盖
render multiple d3 charts without overwriting each other
我有一个数据集合(由 Backbone.js 集合表示)包含两组数据(对于这个例子 - 在现实世界的应用程序中,会有更多)。我想在一个小 d3.js 条形图中表示每组数据。当我渲染第一个条形图时,一切看起来都很棒,但是当我渲染第二个条形图时,第一个条形图又被重写了一遍,它看起来更暗、更模糊(比解释更容易查看,请参阅此 fiddle http://jsfiddle.net/mjmitche/avo5nnus/15/).如果有 3 组数据,第一个最终会非常暗和模糊(被覆盖两次),第二个非常暗和模糊(因为只被覆盖一次),第三个看起来正常。
我明白这个问题了。例如,当我使用 d3 添加垂直参考线时,我使用此代码
d3.selectAll('svg')
所以在第二次遍历集合时,渲染的第一个 svg 被再次选择并覆盖。请注意,在 fiddle 中,在呈现两个图表后,第一个图表也更暗(好像它有两倍的墨水)和模糊(因为数字已被渲染两次)。
最初,我没有使用 d3.selectAll('svg')
,而是尝试了 d3.select('svg')
,但只有第一个图表有垂直参考线,但是当您使用 d3.select
时,它总是选择找到的第一个项目.
如何在不连续覆盖第一个数据的情况下使用 d3 图表分别呈现两组数据?
var myModel = Backbone.Model.extend({});
var collection = Backbone.Collection.extend({
model: myModel,
initialize: function() {
}
});
var MainView = Backbone.View.extend({
el: ('.container'),
initialize: function(){
c = new collection({});
c.reset([{stats: [1,2,3]}, {stats: [4,3,2] }]);
this.render();
},
render: function(){
c.each(this.addChart, this);
},
addChart: function(chart){
alert("pause to view first chart, very clear, no overlap, second time through not so");
var view = new D3View({model: chart});
console.log(view, "view");
this.$("#d3results").append(view.render().el);
}
});
var D3View = Backbone.View.extend({
initialize: function(){
},
render: function(){
console.log("render in d3view");
var modeldata = this.model.toJSON();
var bardata = modeldata.stats;
console.log(bardata, "bardata");
var margin = { top: 30, right: 30, bottom: 40, left:70 }
var height = 200 - margin.top - margin.bottom,
width = 300 - margin.left - margin.right,
barWidth = 50,
barOffset = 5;
var tempColor;
var colors = d3.scale.linear()
.domain([0, bardata.length*.33, bardata.length*.66, bardata.length])
var yScale = d3.scale.linear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scale.ordinal()
.domain(d3.range(0, bardata.length))
.rangeBands([0, width], 0.2)
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
.style('background', 'white')
.style('opacity', 0)
var myChart = d3.select('#d3results').append('svg')
.style('background', '#fff')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate('+ margin.left +', '+ margin.top +')')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', function(d,i) {
return colors(i);
})
.attr('width', xScale.rangeBand())
.attr('x', function(d,i) {
return xScale(i);
})
.attr('height', 0)
.attr('y', height)
myChart.transition()
.attr('height', function(d) {
return yScale(d);
})
.attr('y', function(d) {
return height - yScale(d);
})
.delay(function(d, i) {
return i * 20;
})
var vGuideScale = d3.scale.linear()
.domain([0, d3.max(bardata)])
.range([height, 0])
var vAxis = d3.svg.axis()
.scale(vGuideScale)
.orient('left')
.ticks(10)
var vGuide = d3.selectAll('svg').append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')')
vGuide.selectAll('path')
.style({ fill: 'none', stroke: "#000"})
vGuide.selectAll('line')
.style({ stroke: "#000"})
var hAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.tickValues(xScale.domain().filter(function(d, i) {
return !(i % (bardata.length/5));
}))
return this;
}
});
view = new MainView();
最简单的解决方法是保留对您的 svg
的引用,您不需要 selectAll
:
var mySVG = d3.select('#d3results').append('svg');
var myChart = mySVG
.style('background', '#fff')
.attr('width', width + margin.left + margin.right)
....
var vGuide = mySVG.append('g')
vAxis(vGuide)
....
已更新 fiddle。
我有一个数据集合(由 Backbone.js 集合表示)包含两组数据(对于这个例子 - 在现实世界的应用程序中,会有更多)。我想在一个小 d3.js 条形图中表示每组数据。当我渲染第一个条形图时,一切看起来都很棒,但是当我渲染第二个条形图时,第一个条形图又被重写了一遍,它看起来更暗、更模糊(比解释更容易查看,请参阅此 fiddle http://jsfiddle.net/mjmitche/avo5nnus/15/).如果有 3 组数据,第一个最终会非常暗和模糊(被覆盖两次),第二个非常暗和模糊(因为只被覆盖一次),第三个看起来正常。
我明白这个问题了。例如,当我使用 d3 添加垂直参考线时,我使用此代码
d3.selectAll('svg')
所以在第二次遍历集合时,渲染的第一个 svg 被再次选择并覆盖。请注意,在 fiddle 中,在呈现两个图表后,第一个图表也更暗(好像它有两倍的墨水)和模糊(因为数字已被渲染两次)。
最初,我没有使用 d3.selectAll('svg')
,而是尝试了 d3.select('svg')
,但只有第一个图表有垂直参考线,但是当您使用 d3.select
时,它总是选择找到的第一个项目.
如何在不连续覆盖第一个数据的情况下使用 d3 图表分别呈现两组数据?
var myModel = Backbone.Model.extend({});
var collection = Backbone.Collection.extend({
model: myModel,
initialize: function() {
}
});
var MainView = Backbone.View.extend({
el: ('.container'),
initialize: function(){
c = new collection({});
c.reset([{stats: [1,2,3]}, {stats: [4,3,2] }]);
this.render();
},
render: function(){
c.each(this.addChart, this);
},
addChart: function(chart){
alert("pause to view first chart, very clear, no overlap, second time through not so");
var view = new D3View({model: chart});
console.log(view, "view");
this.$("#d3results").append(view.render().el);
}
});
var D3View = Backbone.View.extend({
initialize: function(){
},
render: function(){
console.log("render in d3view");
var modeldata = this.model.toJSON();
var bardata = modeldata.stats;
console.log(bardata, "bardata");
var margin = { top: 30, right: 30, bottom: 40, left:70 }
var height = 200 - margin.top - margin.bottom,
width = 300 - margin.left - margin.right,
barWidth = 50,
barOffset = 5;
var tempColor;
var colors = d3.scale.linear()
.domain([0, bardata.length*.33, bardata.length*.66, bardata.length])
var yScale = d3.scale.linear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scale.ordinal()
.domain(d3.range(0, bardata.length))
.rangeBands([0, width], 0.2)
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
.style('background', 'white')
.style('opacity', 0)
var myChart = d3.select('#d3results').append('svg')
.style('background', '#fff')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate('+ margin.left +', '+ margin.top +')')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', function(d,i) {
return colors(i);
})
.attr('width', xScale.rangeBand())
.attr('x', function(d,i) {
return xScale(i);
})
.attr('height', 0)
.attr('y', height)
myChart.transition()
.attr('height', function(d) {
return yScale(d);
})
.attr('y', function(d) {
return height - yScale(d);
})
.delay(function(d, i) {
return i * 20;
})
var vGuideScale = d3.scale.linear()
.domain([0, d3.max(bardata)])
.range([height, 0])
var vAxis = d3.svg.axis()
.scale(vGuideScale)
.orient('left')
.ticks(10)
var vGuide = d3.selectAll('svg').append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')')
vGuide.selectAll('path')
.style({ fill: 'none', stroke: "#000"})
vGuide.selectAll('line')
.style({ stroke: "#000"})
var hAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.tickValues(xScale.domain().filter(function(d, i) {
return !(i % (bardata.length/5));
}))
return this;
}
});
view = new MainView();
最简单的解决方法是保留对您的 svg
的引用,您不需要 selectAll
:
var mySVG = d3.select('#d3results').append('svg');
var myChart = mySVG
.style('background', '#fff')
.attr('width', width + margin.left + margin.right)
....
var vGuide = mySVG.append('g')
vAxis(vGuide)
....
已更新 fiddle。