给出下面的代码。我能够创建一个由随机数据填充的条形图并使其正确显示。不幸的是,对我来说,我无法使图表的 update
正确呈现。
The axes appear to be updating accordingly but the graph's bars are not displaying in the proper location, relative to its axes. There's a JSFiddle below that illustrates the issue. You'll notice the bars being rendered along the x-axis in various locations.
var Chart = (function (){
function Chart(options){
this.chart = d3.select(options.el);
this.margin = options.dimensions.margin;
this.height = options.dimensions.height;
this.width = options.dimensions.width;
this.data = options.data;
}
return Chart;
}());
var BarChart = (function(){
function BarChart(options){
Chart.call(this, options);
this.xscale;
this.vguidescale;
this.vaxis;
this.haxis;
this.height = this.height - this.margin.top - this.margin.bottom;
this.width = this.width - this.margin.left - this.margin.right;
this.barcolors = createBarColors(options.barcolors);
this.verticalTickCount = options.verticalTickCount;
this.horizontalTickRangeCount = options.horizontalTickRangeCount || 10;
this.chart = this.chart
.append('svg')
.attr('class', 'metric-chart')
.attr('width', this.width + this.margin.left + this.margin.right)
.attr('height', this.height + this.margin.top + this.margin.bottom)
.append('g')
.attr('class', 'metric-chart__chart-bar')
.attr('transform', 'translate('+ this.margin.left +', '+ this.margin.top +')');
this.vguide = d3.select('svg').append('g');
this.hguide = d3.select('svg').append('g');
}
BarChart.prototype = Chart.prototype;
BarChart.prototype.update = function(data) {
var that = this;
this.xscale = _getAxisScaleX(data, this.width);
this.yscale = _getAxisScaleY(data, this.height);
this.bars = this.chart.selectAll('rect')
.data(d3.values(data))
.order();
this.bars.remove()
this.bars.enter()
.append('rect')
.style('fill', function(d,i) { return that.barcolors[i % that.barcolors.length]; })
.attr('width', that.xscale.rangeBand())
.attr('x', function(d,i) {
return that.xscale(i);
})
.attr('height', 0)
.attr('y', this.height)
.transition()
.attr('height', function(d) { return that.yscale(d); })
.attr('y', function(d) {
return that.height - that.yscale(d);
})
.duration(1500)
.ease('elastic');
this.bars.exit().transition().attr('height', 0).remove();
this.vguidescale = _getVerticalGuideScale(data, this.height);
this.haxis = d3.svg.axis()
.scale(this.xscale)
.orient('bottom')
.tickValues(this.xscale.domain().filter(function(d, i) {
var remainder = i % that.horizontalTickRangeCount;
return remainder === 0;
}));
this.vaxis = d3.svg.axis()
.scale(this.vguidescale)
.orient('left')
.ticks(this.verticalTickCount);
this.vguide
.attr('transform', 'translate(' + this.margin.left + ', ' + this.margin.top + ')')
.attr('class', 'metric-chart__vert-guide');
this.hguide
.attr('transform', 'translate(' + this.margin.left + ', ' + (this.height + this.margin.top) + ')')
.attr('class', 'metric-chart__horz-guide');
this.vaxis(this.vguide);
this.haxis(this.hguide);
};
function _getAxisScaleX (data, width) {
return d3.scale.ordinal()
.domain(d3.range(0, data.length))
.rangeBands([0, width], 0.2);
}
function _getAxisScaleY (data, height) {
return d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, height]);
}
function _getVerticalGuideScale (data, height) {
return d3.scale.linear()
.domain([0, d3.max(data)])
.range([height, 0]);
}
function createBarColors(colors){
return colors || ['#363636','#565656', '#868686'];
}
return BarChart;
}());
用法:
var chartDimensions = {
margin : { top: 10, right: 10, bottom: 25, left: 25 },
height : 200,
width : 500
}, chartoptions;
chartoptions = {
el : '.graph',
data: genRandomArray(0, 50),
dimensions : chartDimensions,
verticalTickCount : 10,
horizontalTickRangeCount : 5
};
/* generate bar chart and update on an interval ... */
var chart = new BarChart(chartoptions);
(function updateChart(){
chart.update(genRandomArray(0, genrandom(10, 90)));
setTimeout(updateChart, 4000);
}());
问题演示:
最佳答案
我认为您稍微误用了 D3 选择概念:当您执行 this.bars = ... .data() ...
时,您最终得到了更新选择,即所有元素其值(value)从以前就改变了。在该选择上,您调用了 .remove()
,这意味着应该删除已更改的元素。这显然不是你想要的。之后,您可以正确处理 enter()
和 exit()
选择,添加新元素并删除不再需要的旧元素。如果您只删除 this.bars.enter()
调用之前对 this.bars.remove()
的第一次调用,它看起来更像您可能想要的:尾部(改变柱数)按预期工作。只是,头部仍然没有正确更新。为此,您需要使用 enter()
调用之前的更新选择来修改柱的适当属性(例如 x
、y
, height
), 也许使用过渡。
Here's an updated fiddle.它看起来仍然不完美,因为只要柱数发生变化,您就会更改 x 尺度。因此,更改栏需要水平移动,但退出栏不会同步移动,因此这两个选择会短暂重叠。您可能应该考虑在单独的转换中更新轴。
关于javascript - d3JS 图表无法正确呈现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31082821/