Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3 How to change dataset based on drop down box selection

I am trying to update/change the data for rectangles based on drop down box selection. I have tried various things and I don't really understand the D3 dispatch function well enough. Grateful if someone could update this code so that I can see how it works in practice. I have 3 datasets with values, and I am simply trying to update rectangle dimensions based on what the user selects in the menu bar.

many thanks,

<!DOCTYPE html>

<html>
<head>
    <title>Menu Bar</title>
    <script type="text/javascript" src="d3/d3.js">
    </script>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">             

</head>
<body>

<select id = "opts">
<option value="ds1">data1</option>
<option value="ds2">data2</option> 
<option value="ds3">data3</option>
  <!-- and so on... -->   
  </select>     

<script type="text/javascript">

var w = 100,
    h = 100
;

var color = d3.scale.ordinal()
            .range(["#1459D9", "#daa520"]);


var ds1 = [[{x:0,y:12}],[{x:0,y:45}]];
var ds2 = [[{x:0,y:72}],[{x:0,y:28}]];
var ds3 = [[{x:0,y:82}],[{x:0,y:18}]];


var canvas = d3.select("body")
    .append("svg")
    .attr("width",100)
    .attr("height",100)        
;

var appending = canvas.selectAll("body")
    .data(ds2)   ///trying to make this selection dynamic based on menubar selection                         
    .enter()                    
    .append("g")
    .style("fill", function(d,i){return color(i);})
    ;

   appending.selectAll("shape")
    .data(function (d) {return d;})
    .enter()
    .append("rect")
    .attr("x",10)
    .attr("y",10)
    .attr("width",function (d) {return d.y;})
    .attr("height",19)
    ;


 </script>      
</body>
</html>
like image 331
user2259146 Avatar asked Jun 12 '14 20:06

user2259146


1 Answers

The main issue with your script is that the d3 code only executes once. When you have multiple data sets, the d3 pattern (bind, add, update, remove) must be called each time the data is updated.

Here is a rough outline of what will accomplish what you want:

// config, add svg
var canvas = d3.select('body')
    .append('svg')
    .attr('width',100)
    .attr('height',100) 
    .appeng('g');


// function that wraps around the d3 pattern (bind, add, update, remove)
function updateLegend(newData) {

    // bind data
    var appending = canvas.selectAll('rect')
       .data(newData);

    // add new elements
    appending.enter().append('rect');

    // update both new and existing elements
    appending.transition()
        .duration(0)
        .attr("width",function (d) {return d.y; });

    // remove old elements
    appending.exit().remove();

}

// generate initial legend
updateLegend(initialValues);

// handle on click event
d3.select('#opts')
  .on('change', function() {
    var newData = eval(d3.select(this).property('value'));
    updateLegend(newData);
});

Here is a working fiddle that demonstrates the data changing with a select (probably needs to be tweaked for your needs):

http://jsfiddle.net/spanndemic/5JRMt/

like image 148
stephenspann Avatar answered Nov 03 '22 10:11

stephenspann