我有一个服务器请求,该请求可能会返回巨大的json列表(〜100K记录,〜50 Mb),这些点我必须使用D3js在画布上绘制。我想在它们到达时绘制它们,以促进交互性和备用内存,所以:
我在服务器端启用了块传输编码 +我在客户端尝试过:
d3.json('?json=qDefects&operationid=' + opid) // my request
.on("load", function (json) {
draw(json); // this works, but only after a long delay that I'd avoid...
})
.on("progress", function (json) {
draw(json); // but this fails : json is not yet available here
})
.get();
在加载JSON时是否可以分块处理JSON?是否有助于以不同的方式构造JSON数据?当前它是单个数组,所以我有
[{"x":1, "y":2},{"x":2, "y":3}, // chunk 1
...
{"x":6845, "y":239426},{"x":51235, "y":234762}] // last chunk
将点分成较小的阵列是否有帮助?
答案 0 :(得分:0)
tl; dr :您无法使用progress
事件来操作JSON。
首先,您可能正在使用d3.request(D3 v3和v4),而不是d3.fetch(D3 v5)。这是一个重要的区别,因为在这两个微库中,该方法具有相同的名称,即d3.json
。但是,d3.json
在前者中是XMLHttpRequest,而在后者中是Promise。
第二,这是最重要的,(不幸的是)这是XY problem。您说过“我想在它们到来时画出它们,以促进交互性和备用内存” ,但问题是您不能:即使在XHR(或Promise)下载完数据后,D3只会在 之后开始绘制任何数据(您无法看到,请参见下文)。这意味着,在拥有50MB数据的情况下,用户将凝视空白页几秒钟……因此,此处的最佳建议是重新考虑数据文件和整个datavis的大小。
回到问题:
progress
事件仅用于监视进度。根据{{3}}:
此规范定义了一个事件接口(ProgressEvent),可用于测量进度。 (强调我的)
我们可以在下面的演示中对此进行检查(我将数组与您在问题中共享的对象一起使用,我只是多次复制/粘贴了相同的对象)。我们可以使用srcElement.response
来查看已加载的JSON,但是我们无法更改它:
d3.json("https://api.myjson.com/bins/1d7yoi")
.on("progress", function(d) {
console.log(d.srcElement.response)
})
.on("load", function() {
console.log("done")
})
.get()
<script src="https://d3js.org/d3.v4.min.js"></script>
例如,您可以看到在这种愚蠢的尝试中更改了字符串中的任何内容,没有任何改变:
d3.json("https://api.myjson.com/bins/1d7yoi")
.on("progress", function(d) {
d.srcElement.response[0] = "foo";
console.log("First character is: " + d.srcElement.response[0])
})
.on("load", function(data) {
console.log("JSON:" + JSON.stringify(data))
})
.get()
<script src="https://d3js.org/d3.v4.min.js"></script>
答案 1 :(得分:0)
请参阅随附的小提琴:http://jsfiddle.net/Q5Jag/12412/
虽然上一个答案是正确的,因为您不能修改progress事件,但是您可以执行调用外部变量的简单操作。因此,以下代码将允许您重新处理字符串并将其发送到d3
var x = ''
d3.json("https://api.myjson.com/bins/1d7yoi")
.on("progress", function(d) {
x = d.responseText
x = "ehllo" + x;
console.log(x)
})
.on("load", function() {
console.log("done")
})
.get()
您可以将responseText分配给变量x并根据需要在x上进行操作。
答案 2 :(得分:0)
由于之前的回答,我得出了以下结论:
function progressLoad(f) {
let start = 0;
return function (event) {
let str = event.responseText.substr(start);
let i = str.indexOf("{");
let j = str.lastIndexOf("}");
str = "[" + str.substr(i, j) + "]";
let data = JSON.parse(str);
f(data);
start = start + j + 1;
}
}
d3.json('?json=qDefects&operationid=' + opid)
.on("progress", progressLoad(draw));
在我没有嵌套{}的(简单)情况下,它工作得很好。 但是,我还确保了我的服务器提供了与请求的每个记录相对应的块,并且看起来responseText也随着这些块而增加,因此我在str中始终具有匹配的{}。
当然,这仍然会建立一个很长的无用的responseText,甚至可能是无用的最终json解析(即使我没有“ loaded”事件?),但我现在可以解决这个问题。