D3访问2d对象数组中的最大值 - 刷Y轴

时间:2014-03-11 17:02:00

标签: javascript d3.js

我有一个D3堆积区域图表,我试图在刷牙时重新计算Y轴。问题在于,当我重新计算Y轴的最大值时,它不是所有不同层的组合,它只是最后一层。例如,如果我刷了1/17和1/20日期,我会得到45作为最大Y轴值而不是95(50 + 45)。这是数据:

[
  {
     "key": "Failed",
     "vis": "1",
     "values": [
        {
           "date": "2014-01-17T05:00:00.000Z",
           "total": 50
        },
        {
           "date": "2014-01-20T05:00:00.000Z",
           "total": 23
        }
     ]
  },
  {
     "key": "Success",
     "vis": "1",
     "values": [
        {
           "date": "2014-01-17T05:00:00.000Z",
           "total": 45
        },
        {
           "date": "2014-01-20T05:00:00.000Z",
           "total": 12
        }
     ]
  }
]

以下是我正在使用的一些示例代码。我知道外循环的每次迭代都消灭了之前的循环,但我不确定如何修复它:

for (var i = 0; i < dataSeries.length; i++) {
    if(dataSeries[i]['vis'] === "1") {

        dataFiltered = dataSeries[i]['values'].filter(function(d) {

            if((d.date >= main_x.domain()[0]) && (d.date <= main_x.domain()[1])) {

                // this is just returning the biggest total in the date range from the last layer (i.e.: 'Failed'),
                // not the greatest of all the layers for that day                       
                return yValue(d);   
            }                           
        });
    }
}

这是fiddle - 如果您刷过一系列日期,Y轴最大值将不正确,图表顶部将被切断。谢谢你的帮助。

1 个答案:

答案 0 :(得分:1)

你在dataFiltered的每次迭代中都在dataSeries。在dataSeries中,您的堆栈中的每个级别都有一个元素,因此这意味着dataFiltered将只包含最后一个元素的值。

但是,即使您解决了这个问题,您设置y比例域的方式仍然有些奇怪:

main_y.domain([0, d3.sum(dataFiltered.map(function(d) { return d.total; }))]);

这是将域的上限值设置为刷新范围内所有数据点的总和。您可能真正想要的是该范围内的最大完全堆叠高度。

您可以这样做:

var dataFiltered = dataSeries.map(function(series) {
    return series.values.filter(function(d) {
        if((d.date >= main_x.domain()[0]) && (d.date <= main_x.domain()[1])) {
            return yValue(d);
        }
    });
});

此时dataFiltered看起来就像dataSeries,除了它应该只包含有刷范围的数据点。

现在您需要将其内部转出,以便数据点以堆栈方式定向,而不是以系列方式定位:

var dataStackSums = {};
dataFiltered.forEach(function(series) {
    series.values.forEach(function(d) {
        if (!dataStackSums[d.date]) { dataStackSums[d.date] = 0; }
        dataStackSums[d.date] += d.total;
    });
});

此时dataStackSums包含每个X轴值(日期)的属性,其值表示该堆栈的总和Y轴。从这里你只需要确定最大堆栈:

var max = 0;
Object.keys(dataStackSums).forEach(function(key) {
    max = Math.max(max, dataStackSums[key]);
});

然后您可以设置域名:

main_y.domain([0, max]);

请注意,为了清晰起见,我打破了这些步骤,但您可以将过滤和堆栈定位分解为一步,以提高效率。