2

我有一段代码可以创建一个甜甜圈(即 d3.layout.pie())。

我曾经通过以下方式加载JSON数据

d3.json(jsonFilePath,
    function(json) {
             //logic
             ....
            })

我的可视化是交互式的(即,甜甜圈的大小不同,包括 innerRadius 和“d”属性)。所以我正确实现了三种情况,输入、删除和更新以及 attrTween 函数来转换“d”属性。

它一直工作到现在。我决定实现某种缓存机制(即,我有一个保存数据的变量,以便数据被预取一次并在需要时重新使用)。我测试了我的缓存的行为并且它正在工作。这是一个片段...

if(cache[name] == undefined) {
    console.log('Loading data and create viz');

    // Loading all the JSONs for this name
    var remaining = revs.length; 
    // revs is an array w/ json file names to load (elements in the form r1, r4 etc.)

    var current = {};

    for (var i in revs) {
        d3.json(revs[i] + ".json" , function(json) {

            current["r"+json.revision] = json;

            if (!--remaining) {
                // Data loaded, here, hence setting cache
                cache[appName] = current;
                createViz(rev);
            }
        }); 
    }
}

我说到点子上了。我用对包含加载的 JSON 字符串的缓存数据的简单访问替换了我用来加载数据的方式,所以现在代替上面的代码块,我有一些看起来像的东西

var currentCache = cache[someName];
var json = currentCache[revisionName];

当我检查 json 变量时,json 已正确加载并且看起来很好。关键是现在过渡不再起作用,我收到了很多消息,例如

Error: Problem parsing d="M2.1431318985078682e-14,-350A350,350 0 1,1 NaN,NaNLNaN,NaNA230.68565589945686,230.68565589945686 0 1,0 1.412542250532388e-14,-230.68565589945686Z"

我之前已经遇到过这些消息,但现在问题是我不知道为什么会这样。代码没有改变,而不是使用 d3.json() 我使用来自变量的 json 字符串。有什么建议吗?

我附上部分代码以供参考...

// An array of objects such as {"name" : myObject, "calls" : 23}
var calls = json.children;

var donut = d3.layout.pie()
    .value(function(d) { return d.calls; })
    .sort(null)

var arcs = d3.select("#vizGroup")
    .selectAll(".callSlice")
    .data(donut(calls));

//update
arcs
    .data(donut(calls))
    .transition()
    .duration(750)
    .attrTween("d", arcTween)
    .style("fill", function(d) { return somecolor(d.data.name); } )


//enter
arcs.enter()
    .append("svg:path")
    .style("fill", function(d) { return somecolor(d.data.name); } )
    .attr("stroke", "#EEF")
    .attr('class', 'callSlice')
    .each(function(d) { this._current = d; })
    .transition()
    .duration(750)
    .attrTween("d", arcTween)


//remove
arcs.exit().remove();

function arcTween(a) {
    a.innerRadius = myScale(myVariable);

    var i = d3.interpolate({
        startAngle: this._current.startAngle, 
        endAngle: this._current.endAngle,
        innerRadius: this._current.innerRadius}, a);

    this._current = i(0);

    return function(t) {
        return arc(i(t));
    };
}
4

2 回答 2

4

您的代码段引用了一个未定义的变量rev。另外,不要对数组使用for-in 循环。我假设你的意思是这样的:

for (var i = 0, n = revs.length; i < n; ++i) {
  d3.json(revs[i] + ".json", function(json) {
    var rev = revs[i];
    /* do something with rev here */
  }); 
}

或者等效地,像这样:

for (var i = 0, n = revs.length; i < n; ++i) {
  var rev = revs[i];
  d3.json(revs[i] + ".json", function(json) {
    /* do something with rev here */
  }); 
}

这些都不会按预期工作,因为 d3.json 回调是异步的,并且闭包不会在 for 循环的当前迭代中捕获rev(或就此而言)的值:它们捕获的是引用,而不是,并且因此,当稍后调用回调时,所有回调将看到for 循环 ( ) 的最后一次迭代中的值,而不是调用每个 d3.json 时的值。irevs.length

您可以通过使用闭包捕获值来解决此问题。例如:

for (var i = 0, n = revs.length; i < n; ++i) {
  fetch(revs[i]);
}

function fetch(rev) {
  d3.json(rev + ".json", function(json) {
    /* do something with rev here */
  }); 
}

这是有效的,因为 的每个唯一值rev都由函数捕获fetch。有关闭包的更多信息,请参阅:

于 2012-04-26T17:11:39.477 回答
2

我认为您没有包含有问题的代码,我怀疑这是您的 JSON 缓存代码。我的猜测是您仍在异步获取 JSON,但您正在尝试立即使用它。d3.json()接受一个在实际加载数据之前不会调用的回调函数 - 我在您当前的代码中没有看到任何类似的结构,所以除非您加载 JSON 内联,而不是从远程文件加载,否则很可能是问题。

在这种情况下,手动检查控制台无济于事,因为当您检查控制台时,数据已经加载——当您的代码实际运行时,您就会遇到问题。

于 2012-04-26T16:51:21.323 回答