D3 已经有一个直方图函数,如果你通过 API 相信你可以找到它。但是由于您想要一个自定义解决方案,因此可以使用这些方法(我是临时编写的,所以请检查一下):
版本 1 - 事件循环的单个滴答声 - 同步
让我们创建一个示例数据集:
var x = {};
for (var i =0;i<1000;++i){
x[i]=Math.random()
}
创建一个函数,该函数将获取一个对象、多个桶和一个桶间隔:
function allocate(obj,bucketCount,bucketStep){
var objLastIndex = Object.keys(obj).length - 1;
var retValue = Array.apply(null,Array(bucketCount))
.map(function(d,i){
var obj = {};
obj.count = 0;
obj.freq = 0;
return obj;
});
Object.keys(obj).forEach(function(d,i){
var bucketIndex = obj[d]/bucketStep<<0;
retValue[bucketIndex] && ++retValue[bucketIndex].count;
if(i === objLastIndex){
retValue.forEach(function(d,i){
d.freq = d.count/(objLastIndex+1)
})
}
});
return retValue;
}
使用它:
allocate(x,10,0.1);
"[
{
"count": 84,
"freq": 0.084
},
{
"count": 90,
"freq": 0.09
},
{
"count": 113,
"freq": 0.113
},
{
"count": 98,
"freq": 0.098
},
{
"count": 111,
"freq": 0.111
},
{
"count": 108,
"freq": 0.108
},
{
"count": 108,
"freq": 0.108
},
{
"count": 82,
"freq": 0.082
},
{
"count": 108,
"freq": 0.108
},
{
"count": 98,
"freq": 0.098
}
]"
或者:
allocate(x,10,0.5);
"[
{
"count": 496,
"freq": 0.496
},
{
"count": 504,
"freq": 0.504
},
{
"count": 0,
"freq": 0
},
{
"count": 0,
"freq": 0
},
{
"count": 0,
"freq": 0
},
{
"count": 0,
"freq": 0
},
{
"count": 0,
"freq": 0
},
{
"count": 0,
"freq": 0
},
{
"count": 0,
"freq": 0
},
{
"count": 0,
"freq": 0
}
]"
版本 2 - 多个周期 - 异步 - 处理 >1000000 个点
由于您没有提供任何反馈或指示输出,我假设 VERSION 1 中的格式是您想要的。
现在我将稍微修改一下上面的函数。我将它分成 2 部分,第一部分将返回一个类似于 ES6 Promises 或 yield 关键字返回的对象,另一部分(附加在第一个部分,因此不必一次又一次地创建)将完成繁重的工作。如果需要,您可以附加回调:
function allocate(obj,bucketCount,bucketStep,callback){
var keys = Object.keys(obj);
var retValue = Array.apply(null,Array(bucketCount))
.map(function(d,i){
var obj = {};
obj.count = 0;
obj.freq = 0;
return obj;
});
console.log(retValue)
retValue.__parent = {result:retValue,done:false};
allocate._iterate(keys,0,retValue,obj,bucketCount,bucketStep,callback);
return retValue.__parent;
}
allocate._iterate = function(keys,iteration,buckets,obj,bucketCount,bucketStep,callback){
var currentLoad = keys.slice(iteration*10000,++iteration*10000),
currentLoadLength = currentLoad.length,
currentLoadLastIndex = currentLoadLength - 1,
length = keys.length;
currentLoad.forEach(function(d,i){
var bucketIndex = obj[d]/bucketStep<<0;
buckets[bucketIndex] && ++buckets[bucketIndex].count;
});
if(currentLoadLength < 10000) {
buckets.forEach(function(d,i){
d.freq = d.count/length;
});
buckets.__parent.done = true;
return callback && callback(buckets);
} else {
window.requestAnimationFrame(
allocate._iterate(keys,iteration,buckets,obj,bucketCount,bucketStep,callback)
);
}
}
要使用它(最后一个参数是一个可选的回调,它作为第一个参数传递给数组):
var x = {}; //1000000 keys, I could do more but chrome could not handle his own object.
for (var i =0;i<1000000;++i){
x[i]=Math.random()
}
var returnValue = allocate(x,10,0.1,function(){console.log("done!")});
//{result: Array(10), done: false}
//after few seconds --> 'done!' is logged
returnValue.result;
//"[
{
"count": 100156,
"freq": 0.100156
},
{
"count": 100575,
"freq": 0.100575
},
{
"count": 100009,
"freq": 0.100009
},
{
"count": 99818,
"freq": 0.099818
},
{
"count": 99785,
"freq": 0.099785
},
{
"count": 100332,
"freq": 0.100332
},
{
"count": 99778,
"freq": 0.099778
},
{
"count": 99790,
"freq": 0.09979
},
{
"count": 99795,
"freq": 0.099795
},
{
"count": 99962,
"freq": 0.099962
}
]"