shanky
shanky

Reputation: 801

Updating circle radius and animate it in d3.js

I have n number of circle's plotted on map from csv file and I want to update the radius of circle over the 2 years capacity time. My csv file format is :

ID, Latitude, Longitude, CapaYr1, CapaYr2

1, 38.957, -122.642, 94261, 288839.2857

2, 40.718, -122.42, 3690993.143 3799364.714.

Below is my code :

g.selectAll("circle")
                .data(result)
                .enter()
                .append("circle")
                .attr("r", 0)
                .attr('cx', function(d) {
                    return projection([d.Longitude, d.Latitude])[0];
                })
                .attr('cy', function(d) {
                    return projection([d.Longitude, d.Latitude])[1];
                })
                .attr('r', function(d){

                    var hd = d3.keys(d);
                    var radDataSet = [];


                    for (var i = hd.length - 1; i >= 0; i--) {
                        if((hd[i] === "ID") || (hd[i] === "Latitude") || (hd[i] === "Longitude")){
                        }else{
                            radDataSet.push(Math.round(Math.sqrt((d[hd[i]]/30000))));
                        }
                    }

                    radDataSet.forEach(function(d, i) {
                            g.selectAll("circle").transition().duration(2000).delay(i * 1000)
                            .attr("r", d);
                    });

                });

So radDataSet array in above code has CapaYr1 and CapaYr2 values. All circle's radius are getting updated but all the circle has same radSet values. So how can I make it in such a way that each circle transition has different values depending on calculated radDataSet values for each rows from csv file.

radSet values in each row is [3, 2] and [11, 11]. Its updating circle radius with [11, 11].

Here's my fiddle -> https://jsfiddle.net/7zumngdq/72/

Upvotes: 2

Views: 684

Answers (1)

torresomar
torresomar

Reputation: 2229

Here is my approach (I hope this is the issue you were trying to solve), although you may need more than two data values for it to work since I used a linear scale. Let me explain:

First of all I created a new data structure that contains your data (I just don't like keys with slashes :S)

var parsed = ca2.map(function(d, i) {
  return {
    firstYear: +d['2000/01/31'],
    secondYear: +d['2000/02/29'],
    id: d['ID'],
    lat: +d['Latitude'],
    lng: +d['Longitude']
  };
});
// Pushing a new value in order to have at least one circle that
// will change radius
parsed.push({
  firstYear: 2678933,
  secondYear: 80000000,
  id: 'DOVAL',
  lat: 35.2931129,
  lng: -119.465589
})

Lets setup a scale to take care of the radius sizes:

var max = d3.max(parsed, function(d) {
  return d.firstYear
});
var min = d3.min(parsed, function(d) {
  return d.firstYear
});
var linearScale = d3.scale.linear()
  .domain([min, max]) 
  // If we just had two values all our circles would end up being the smallest 
  // and largest values of the range defined below
  .range([5, 25]);

Now lets add the circles:

var circles_first = g.selectAll(".circle-year")
  .data(parsed)
  .enter()
  .append("circle")
  .attr('class', 'circle-year')
  .attr("r", 0)
  .attr('cx', function(d) {
    return projection([d.lng, d.lat])[0];
  })
  .attr('cy', function(d) {
    return projection([d.lng, d.lat])[1];
  });

Make an animation for the first year value

g.selectAll(".circle-year")
  .transition().duration(2000).delay(1000)
  .attr('fill', 'red')
  .attr('r', function(d) {
    return linearScale(d.firstYear);
  });

And finally make an animation for the second year value

setTimeout(function() {
  var maxS = d3.max(parsed, function(d) {
    return d.secondYear
  });
  var minS = d3.min(parsed, function(d) {
    return d.secondYear
  });
  linearScale.domain([minS, maxS]);
  g.selectAll(".circle-year")
    .transition().duration(2000).delay(1000)
    .attr('fill', 'green')
    .attr('r', function(d) {
      return linearScale(d.secondYear);
    });
}, 8000)

Working jsfiddle: https://jsfiddle.net/e693hrdL/

Update:

Here is an updated version that should work, the only issue is that your data has a giant slope in your 'SHA' data element, thus making the data changes minimal.

d3.csv('./ca.csv', function(ca2) {
  console.log('ca2', ca2);
  var parsed = ca2.map(function(d, i) {
    var dates = d3.keys(d).filter(function(key) { // get all date keys
      if (key === 'ID' || key === 'Latitude' || key === 'Longitude') {
        return false;
      }
      return true;
    });
    var dateValues = dates.map(function(date) { // Add them as an array
      // if (d.ID === 'SHA') {
      //  return +d[date] - 2000000;
      // }
      return +d[date];
    });
    return {
      dates: dateValues,
      id: d['ID'],
      lat: +d['Latitude'],
      lng: +d['Longitude']
    };
  });
  console.log(parsed);
  var circles_first = g.selectAll(".circle-year")
    .data(parsed)
    .enter()
    .append("circle")
    .attr('class', 'circle-year')
    .attr("r", 0)
    .attr('cx', function(d) {
      return projection([d.lng, d.lat])[0];
    })
    .attr('cy', function(d) {
      return projection([d.lng, d.lat])[1];
    });

  parsed[0].dates.forEach(function(d, i) { // call function based on index!
    setTimeout(function() {
      changeRadius(i);
    }, i * 500);
  })
  var linearScale = d3.scale.linear()
    .range([0, 25]);

  function changeRadius(index) {
    var maxS = d3.max(parsed, function(d) {
      return d.dates[index];
    });
    var minS = d3.min(parsed, function(d) {
      return d.dates[index];
    });
    console.log(minS, maxS)
    linearScale.domain([minS, maxS]);
    g.selectAll(".circle-year")
      .attr('fill', function(d) {
        return
      })
      .attr('r', function(d) {
        return linearScale(d.dates[index]);
      });
  }
});

Working plnkr: https://plnkr.co/edit/6GH2VWwtUp5DHOeqrKDj?p=preview

Upvotes: 1

Related Questions