javascript - d3JS 图表无法正确呈现

标签 javascript d3.js

给出下面的代码。我能够创建一个由随机数据填充的条形图并使其正确显示。不幸的是,对我来说,我无法使图表的 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);
}());

问题演示:

http://jsfiddle.net/h8ztvmq4/

最佳答案

我认为您稍微误用了 D3 选择概念:当您执行 this.bars = ... .data() ... 时,您最终得到了更新选择,即所有元素其值(value)从以前就改变了。在该选择上,您调用了 .remove(),这意味着应该删除已更改的元素。这显然不是你想要的。之后,您可以正确处理 enter()exit() 选择,添加新元素并删除不再需要的旧元素。如果您只删除 this.bars.enter() 调用之前对 this.bars.remove() 的第一次调用,它看起来更像您可能想要的:尾部(改变柱数)按预期工作。只是,头部仍然没有正确更新。为此,您需要使用 enter() 调用之前的更新选择来修改柱的适当属性(例如 xy, height), 也许使用过渡。

Here's an updated fiddle.它看起来仍然不完美,因为只要柱数发生变化,您就会更改 x 尺度。因此,更改栏需要水平移动,但退出栏不会同步移动,因此这两个选择会短暂重叠。您可能应该考虑在单独的转换中更新轴。

关于javascript - d3JS 图表无法正确呈现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31082821/

相关文章:

javascript - 调整我的表或窗口的大小? HTML5

javascript - 通过 setInterval 添加输入不起作用

javascript - nvd3.js - 无法更改折线图中线条的颜色

javascript - d3js 给出类型错误 "d is undefined"

javascript - x 轴的 JSON 键,y 轴的值

javascript - d3(或 JavaScript): use local variable in another function

javascript - 跨源请求被阻止 : (Reason: CORS header 'Access-Control-Allow-Origin' missing)

javascript - Cmd + 文本选择不起作用,只允许在文本字段输入数字

javascript - 迭代object中的所有属性,查找并替换

javascript - d3js 树布局中的对 Angular 线路径看起来不正确