最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Driving a D3 chart with and without d3.json() - Stack Overflow

programmeradmin3浏览0评论

I have a piece of code that creates a donut (i.e., d3.layout.pie()).

I used to load JSON data in the following way

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

My visualizations are interactive (i.e., the donut variates in size, both innerRadius and "d" attribute). So I correctly implemented the three cases, enter, remove and update and the attrTween function to transition the "d" attribute.

It worked until now. I decided to implement some sort of caching mechanism (i.e., I've a variable that holds the data so that data are pre-fetched once and re-used if needed again). I tested the behavior of my cache and it's working. Here's a snippet...

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);
            }
        }); 
    }
}

I e to the point. I replaced the way I used to load data with a simple access of my cache data containing the loaded JSON string, so now instead of the above code block I've something that looks like

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

When I inspect the json variable the json is correcty loaded and looks fine. The point is that now the transition is no longer working and I got lot of messages such as

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"

I already faced this messages before, but now the thing is that I dunno why this is happening. The code is unchanged, instead of using d3.json() I'm using the json string from a variable. Any suggestion?

I attach part of the code for reference...

// 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));
    };
}

I have a piece of code that creates a donut (i.e., d3.layout.pie()).

I used to load JSON data in the following way

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

My visualizations are interactive (i.e., the donut variates in size, both innerRadius and "d" attribute). So I correctly implemented the three cases, enter, remove and update and the attrTween function to transition the "d" attribute.

It worked until now. I decided to implement some sort of caching mechanism (i.e., I've a variable that holds the data so that data are pre-fetched once and re-used if needed again). I tested the behavior of my cache and it's working. Here's a snippet...

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);
            }
        }); 
    }
}

I e to the point. I replaced the way I used to load data with a simple access of my cache data containing the loaded JSON string, so now instead of the above code block I've something that looks like

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

When I inspect the json variable the json is correcty loaded and looks fine. The point is that now the transition is no longer working and I got lot of messages such as

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"

I already faced this messages before, but now the thing is that I dunno why this is happening. The code is unchanged, instead of using d3.json() I'm using the json string from a variable. Any suggestion?

I attach part of the code for reference...

// 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));
    };
}
Share Improve this question edited Jun 16, 2014 at 10:18 VividD 10.5k8 gold badges66 silver badges112 bronze badges asked Apr 26, 2012 at 16:37 RMinelliRMinelli 1913 silver badges13 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

Your snippet refers to an undefined variable rev. Also, don't use a for-in loop with an array. I'm going to assume you meant something like this:

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 */
  }); 
}

Or equivalently, something like this:

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 */
  }); 
}

Neither of these will work as expected because the d3.json callback is asynchronous, and closures don't capture the value of rev (or for that matter i) in the current iteration of the for loop: they capture a reference, not a value, and so when the callback is invoked at a later point, all your callbacks will see the value in the last iteration of the for loop (revs.length), not the value when each d3.json is called.

You can fix this by capturing the value with a closure. For example:

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 */
  }); 
}

This works because each unique value of rev is captured by the function fetch. For more on closures, see:

  • http://jibbering./faq/notes/closures/

I don't think you've included the code that is at fault, which I suspect is your JSON caching code. My guess is that you're still fetching JSON asynchronously, but you're trying to use it right away. d3.json() takes a callback function that isn't invoked until the data is actually loaded - I'm not seeing any similar structure in your current code, so unless you're loading the JSON inline, rather than from a remote file, that's likely to be the issue.

Checking the console manually won't help in this case, because by the time you check the console, the data has been loaded - it's when your code is actually running that you have problems.

发布评论

评论列表(0)

  1. 暂无评论