// select the moon using 'select'. 'select' returns only one element
var moon = d3.select("#moon");
// calculate the co-ordinates
// x = somevalue; y = somevalue;
// now update the position using our selection
moon.attr("cx", x).attr("cy", y);
// ------------------------------------------------------------------
// With 'selectAll' we can select all the elements for the selection
// Here there are 2 timer elements in the page; returns both
var timer = d3.selectAll(".phase.timer");
// calculate the time
// time = somevalue;
// now update 'all' the elements from the 'selectAll'.
timer.text( time );
Data Joins helps us to associate some data (which is given as an array) with html elements. If the data array changes, corresponding html elements can be easily associated or disassociated with the data.
Data Joins involve the following
// our data array containing star co-ordinates; initially it will be empty
var starData = [];
// lets fill the starData with sets of 10 random co-ordinates; Each co-ordinate represent a star position.
// [ {x: 1, y: 1}, {x: 34, y: 56}, {x: 32, y: 8}, {x: 22, y: 48} ....... ] // total of 10 sets
// the holder that will contain all the stars
var canvas = d3.select("#starCanvas");
canvas.selectAll("circle") // select the circle elements (0 elements currently)
.data( starData ); // bind the data to the circles (10 co-ordinates)
If we had initially 5 circle elements, the previous statement would have bound the first 5 co-ordinates to the 5 circle elements.
If we see the above statement, we have 0 circle elements. But we have 10 co-ordinates. There are no circles to associate the co-ordinate data. In other words, we have 10 extra co-ordinate data for which we need circle elements to associate with.
canvas.selectAll("circle") // select the circle elements (0 elements currently)
.data( starData ); // bind the data to the circles (10 co-ordinates)
.enter() // gets the new data without elements associated
.append("circle") // add the new elements for the new data
canvas.selectAll("circle") // select the circle elements (0 elements currently)
.data( starData ); // bind the data to the circles (10 co-ordinates)
.enter() // gets the new data without elements associated
.append("circle") // add the new elements for the new data
.attr("r", 1); // static radius value is used for all elements
.attr("cx", function (d) { return d.x; } ) // dynamically takes x position from bound data for this element
.attr("cy", function (d) { return d.y; } ) // dynamically takes y position from bound data for this element
d3.js has attr() methods, that takes a value or a function as second argument. If a value is used, it is used directly. This is done for the r attribute. All the stars have a default radius of one. But for the (x,y) positions we need values from our co-ordinates which we associated with the circle. d3.js allows us to use a function as second argument, with our bound data as the argument. So we return our (x, y) value from our co-ordinate object for (cx, cy) attributes respectively.
// let us remove 3 stars from the data Array
starData = starData.slice(0, starData.length - 3);
canvas.selectAll("circle") // select the circle elements (10 elements currently)
.data( starData ); // bind the new data to the circles (7 co-ordinates)
.exit() // gets the extra circle elements not bound to new data, in this case last 3
// let us change their color to red for 2 seconds before removing them
.transition().duration(2000).style("stroke", "red").style("fill", "red")
// only now the extra html elements are removed.
.remove();
// let us add 3 stars to our data array
starData.push( {x: 23, y: 44} );
starData.push( {x: 33, y: 54} );
starData.push( {x: 43, y: 24} );
canvas.selectAll("circle") // select the circle elements (7 elements currently)
.data( starData ); // bind the new data to the circles (10 co-ordinates)
.enter() // gets the extra data without bound html elements (last 3 co-ordinates)
.append("circle") // add the new elements for the new data
.attr("r", 1); // static radius value is used for all elements
.attr("cx", function (d) { return d.x; } ) // dynamically takes x position from bound data for this element
.attr("cy", function (d) { return d.y; } ) // dynamically takes y position from bound data for this element
.style("stroke", "blue").style("fill", "blue") // initial star color
// let us change their color back to white from blue after 2 seconds
.transition().duration(2000).style("stroke", "white").style("fill", "white");
canvas.selectAll("circle") // select the circle elements (10 elements currently)
.data( starData ); // bind the current data to the circles (10 co-ordinates)
// now we have got our existing stars; do whatever we want to do to them
.style("stroke", "silver").style("fill", "silver");
Every time Data Join is done, the data is updated with the corresponding html element. For example, if we have changed some of the stars' co-ordinates, previous data join would have updated them. To reflect that change, we need to update their position. Expanding on the previous statement,
// we have updated some of the stars' co-ordinates; So update to their new positions
canvas.selectAll("circle") // select the circle elements
.data( starData ); // bind the current data to the circles (changed co-ordinates will be updated now)
// update the circle elements to new position
.attr("cx", function (d) { return d.x; } ) // all stars gets their new x co-ordinate
.attr("cy", function (d) { return d.y; } ) // all stars gets their new y co-ordinate