Matt Sephton
Matt Sephton

Reputation: 4132

How to update all data representing an SVG line using d3?

I used this code as my starting point: https://github.com/lucasfilippi/d3-radar

My JSFiddle is here: http://jsfiddle.net/gingerbeardman/Cdg58/

Here's a sample radar chart that it draws:

Sample radar chart ourput

The original binds data using an external JSON file, but I prefer to bind a dynamically generated JSON object. I randomly generate some data for the purposes of this proof-of-conept demo.

However, I'm stuck with how to get the chart to show the new/updated data.

function refresh() {
  var data = rndData();

  d3.select("#container")
    .datum(data)
    .call(chart);
}

function rndData() {
  var newData = [...];

  return newData;
}

I have set up a function on click event to draw a new chart with random data, but there is no visual change when it is called. I've verified that the data is different and that the call happens.

The code does not use the update() and exit() calls, perhaps that's not so bad given no points on the line are actually being added or removed. I simply want each point on the SVG line to transition to new co-ordinates.

Upvotes: 1

Views: 2134

Answers (3)

Lars Kotthoff
Lars Kotthoff

Reputation: 109242

The way the current code is set up is not really compatible with being able to update. To do this, quite substantial changes have to be made.

The first problem is that the code only operates on new SVGs. Everything happens on gEnter, which is an empty selection if the SVG is there already. This is easy enough to fix though by reselecting the g element after appending it and then operating on that. This will select both newly-appended gs and those that were there before.

 var g = svg.select("g");

Furthermore, the way appending elements is done throughout the code usually looks like this:

var something = foo.selectAll(".bar").data(data).enter().append();

This only handles the enter selection and doesn't even allow access to the other selections. Refactoring this to look like

var something = foo.selectAll(".bar").data(data);
something.enter().append();
something... // change update selection

fixes the problem.

Complete, working example here. Note that I'm not handling the exit selection in there as it is not necessary for this example.

Upvotes: 4

FernOfTheAndes
FernOfTheAndes

Reputation: 5015

The way the original code is setup, the svg element is really the pivotal element for the enter/update/exit pattern. Here are some excerpts from the code changes I made:

// Select the svg element, if it exists.
var svg = d3.select(this)
    .selectAll('svg')
    .data([metrics]);

// --> svg exit selection
svg.exit().remove();

// --> svg enter selection
svg.enter().append('svg');

// create the skeletal chart.
var svgAppend = svg
  .append('g')
    .attr('transform', 'translate(' + (side / 2) + ', ' + (side / 2) + ')');

...

// --> svg update selection
svg.selectAll('.radar')
    .each(function (d, n) {
        chart.drawArea(d3.select(this), n);
    })

I renamed the gEnter variable to svgAppend because it more clearly expresses what is happening.

Here is the complete working fiddle.

Upvotes: 3

jme11
jme11

Reputation: 17362

Actually, it looks like you need to pass in your data like this:

d3.json("radar.json", function(error, data) { d3.select("#container") .datum(data) .call(chart); });

so, I'd place your data object variable in lieu of "radar.json" in the example and just make sure that it is formatted correctly according to the doc. Did you try that already?

Upvotes: 1

Related Questions