D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
veritas1uxmea
Full window
Github gist
4
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> <title>D3: Linked charts</title> <style type="text/css"> body { background-color: white; } #buttonContainer { margin-bottom: 10px; } button { padding: 15px; } svg { display: block; margin-bottom: 10px; background-color: white; } svg text { font-family: sans-serif; font-size: 16px; fill: black; font-style: bold; } g.bar { fill: #000775; } g.bar text { font-family: sans-serif; font-size: 14px; fill: black; font-style: bold; text-anchor: middle; opacity: 0; } g.bar.highlight text { opacity: 1; } g.bar.highlight rect { fill: #8ec1ff; } .axis path, .axis line { fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: sans-serif; font-size: 11px; } </style> </head> <body> <div id="buttonContainer"> <button id="sort">Sort Giving</button> <button id="sortDescending">Sort Receiving</button> <button id="sortRank">Sort Rank</button> <button id="sortOxytocin">Sort Oxytocin</button> </div> <script type="text/javascript"> //Width, height, padding var w = 600; var h = 350; var padding = 50; //glicko data var dataset = [ {"name":"A","sales":569,"bonus":190,"oxytocin":69}, {"name":"B","sales":408,"bonus":21,"oxytocin":152}, {"name":"C","sales":259,"bonus":245,"oxytocin":148}, {"name":"D","sales":82,"bonus":81,"oxytocin":0}, {"name":"E","sales":47,"bonus":131,"oxytocin":0}, {"name":"F","sales":3,"bonus":96,"oxytocin":0}, {"name":"G","sales":180,"bonus":271,"oxytocin":0}, {"name":"H","sales":24,"bonus":159,"oxytocin":0}, {"name":"I","sales":3,"bonus":94,"oxytocin":0}, {"name":"J","sales":3,"bonus":96,"oxytocin":170}, {"name":"K","sales":1,"bonus":111,"oxytocin":118}, {"name":"L","sales":1,"bonus":85,"oxytocin":197}] ; //Configure x and y scale functions var xScale = d3.scale.ordinal() .domain(d3.range(dataset.length)) .rangeRoundBands([ padding, w - padding ], 0.1); //Now using two different y scales for two different charts var salesScale = d3.scale.linear() .domain([ 0, d3.max(dataset, function(d) { return d.sales; }) ]) .rangeRound([ h - padding, padding ]); var bonusScale = d3.scale.linear() .domain([ 0, d3.max(dataset, function(d) { return d.bonus; }) ]) .rangeRound([ h - padding, padding ]); var oxytocinScale = d3.scale.linear() .domain([ 0, d3.max(dataset, function(d) { return d.oxytocin }) ]) .rangeRound([ h - padding, padding ]); //Now using two different y axes var salesAxis = d3.svg.axis() .scale(salesScale) .orient("left") .ticks(5) .outerTickSize(0); // remove outer tick mark on axis var bonusAxis = d3.svg.axis() .scale(bonusScale) .orient("left") .ticks(5) .outerTickSize(0); var oxytocinAxis = d3.svg.axis() .scale(oxytocinScale) .orient("left") .ticks(5) .outerTickSize(0); // // Make the first chart (sales data) // //Create SVG element var svg = d3.select("body") .append("svg") .attr("id", "salesChart") .attr("width", w) .attr("height", h); //Create groups var groups = svg.selectAll("g") .data(dataset) .enter() .append("g") .attr("class", "bar") .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); //Add bar to each group var rects = groups.append("rect") .attr("x", 0) .attr("y", function(d) { return h - padding; }) .attr("width", xScale.rangeBand()) .attr("height", 0) // .attr("fill", "SteelBlue") ; //Add label to each group groups.append("text") .attr("x", xScale.rangeBand() / 2) .attr("y", function(d) { return salesScale(d.sales) - 12; }) .text(function(d) { return d.name + ": " + d.sales; }) //Add second piece of text - remove css opacity directly // height is related to height-padding of svg groups.append("text") .attr("x", xScale.rangeBand() / 2) .attr("y", [h - padding/1.6]) .text(function(d) { return d.name; }) .style("opacity", 1) //Transition rects into place rects.transition() .delay(function(d, i) { return i * 100; }) .duration(1500) .attr("y", function(d) { return salesScale(d.sales); }) .attr("height", function(d) { return h - padding - salesScale(d.sales); }); //Create y axis svg.append("g") .attr("class", "axis") .attr("transform", "translate(" + padding + ",0)") .attr("opacity", 0) .call(salesAxis) .transition() .delay(2000) .duration(1500) .attr("opacity", 1.0); // Title for chart 1 svg.append("text") .attr("x", padding/2) .attr("y", padding/2.5) .text("Giving") .style("text-anchor", "start"); // // Make the second chart (bonus data) // //Create SVG element svg = d3.select("body") .append("svg") .attr("id", "bonusChart") .attr("width", w) .attr("height", h); //Create groups groups = svg.selectAll("g") .data(dataset) .enter() .append("g") .attr("class", "bar") .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); //Add bar to each group rects = groups.append("rect") .attr("x", 0) .attr("y", function(d) { return h - padding; }) .attr("width", xScale.rangeBand()) .attr("height", 0) // .attr("fill", "SteelBlue") ; //Add label to each group groups.append("text") .attr("x", xScale.rangeBand() / 2) .attr("y", function(d) { return bonusScale(d.bonus) - 10; }) .text(function(d) { return d.name + ": " + d.bonus; }) //Add second piece of text - remove css opacity directly // height is related to height-padding of svg groups.append("text") .attr("x", xScale.rangeBand() / 2) .attr("y", [h - padding/1.6]) .text(function(d) { return d.name; }) .style("opacity", 1) //Transition rects into place rects.transition() .delay(function(d, i) { return i * 100; }) .duration(1500) .attr("y", function(d) { return bonusScale(d.bonus); }) .attr("height", function(d) { return h - padding - bonusScale(d.bonus); }); //Create y axis svg.append("g") .attr("class", "axis") .attr("transform", "translate(" + padding + ",0)") .attr("opacity", 0) .call(bonusAxis) .transition() .delay(2000) .duration(1500) .attr("opacity", 1.0); //New functionality for interaction for ALL groups //in BOTH charts d3.selectAll("g.bar") .on("mouseover", function(d) { //Instead of d3.select(this), now we want to //select ALL groups that match the same //criteria as this one, i.e. this group //and the corresponding one in the other chart. // //We begin by selecting all groups, then //filtering to exclude those that don't match. // //We'll use each person's "name" as a unique //identifier. (With a real-world data set, you'd //probably use an ID number here.) var thisName = d.name; d3.selectAll("g.bar") .filter(function(d) { //If the name from the original group on //which mouseover was triggered matches the //name on the group we're evaluating right now… if (thisName == d.name) { return true; //…then it's a match } }) .classed("highlight", true); }) .on("mouseout", function() { //We could be selective, using the same filtering //criteria above, or, for simplicity, just //de-highlight all the groups. d3.selectAll("g.bar") .classed("highlight", false); }) // Title for chart 2 svg.append("text") .attr("x", padding/2) .attr("y", padding/2.5) .text("Receiving") .style("text-anchor", "start"); // Make the third chart (oxytocin data) // //Create SVG element svg = d3.select("body") .append("svg") .attr("id", "oxytocinChart") .attr("width", w) .attr("height", h); //Create groups groups = svg.selectAll("g") .data(dataset) .enter() .append("g") .attr("class", "bar") .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); //Add bar to each group rects = groups.append("rect") .attr("x", 0) .attr("y", function(d) { return h - padding; }) .attr("width", xScale.rangeBand()) .attr("height", 0) // .attr("fill", "SteelBlue") ; //Add label to each group groups.append("text") .attr("x", xScale.rangeBand() / 2) .attr("y", function(d) { return oxytocinScale(d.oxytocin) - 10; }) .text(function(d) { return d.name + ": " + d.oxytocin; }) //Add second piece of text - remove css opacity directly // height is related to height-padding of svg groups.append("text") .attr("x", xScale.rangeBand() / 2) .attr("y", [h - padding/1.6]) .text(function(d) { return d.name; }) .style("opacity", 1) //Transition rects into place rects.transition() .delay(function(d, i) { return i * 100; }) .duration(1500) .attr("y", function(d) { return oxytocinScale(d.oxytocin); }) .attr("height", function(d) { return h - padding - oxytocinScale(d.oxytocin); }); //Create y axis svg.append("g") .attr("class", "axis") .attr("transform", "translate(" + padding + ",0)") .attr("opacity", 0) .call(oxytocinAxis) .transition() .delay(2000) .duration(1500) .attr("opacity", 1.0); //New functionality for interaction for ALL groups //in BOTH charts d3.selectAll("g.bar") .on("mouseover", function(d) { //Instead of d3.select(this), now we want to //select ALL groups that match the same //criteria as this one, i.e. this group //and the corresponding one in the other chart. // //We begin by selecting all groups, then //filtering to exclude those that don't match. // //We'll use each person's "name" as a unique //identifier. (With a real-world data set, you'd //probably use an ID number here.) var thisName = d.name; d3.selectAll("g.bar") .filter(function(d) { //If the name from the original group on //which mouseover was triggered matches the //name on the group we're evaluating right now… if (thisName == d.name) { return true; //…then it's a match } }) .classed("highlight", true); }) .on("mouseout", function() { //We could be selective, using the same filtering //criteria above, or, for simplicity, just //de-highlight all the groups. d3.selectAll("g.bar") .classed("highlight", false); }) // Title for chart 3 oxytocin svg.append("text") .attr("x", padding/2) .attr("y", padding/2.5) .text("Oxytocin") .style("text-anchor", "start"); //Sort Ascending button - keep both graphs but link.================================ d3.select("#sort") .on("click", function() { //Need to reselect all groups in each chart d3.selectAll("#salesChart g.bar").sort(function(a, b) { return d3.descending(a.sales, b.sales); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#bonusChart g.bar").sort(function(a, b) { return d3.descending(a.sales, b.sales); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#oxytocinChart g.bar").sort(function(a, b) { return d3.descending(a.sales, b.sales); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); }) ; /// Descending Button - sort both graphs but keep linked d3.select("#sortDescending") .on("click", function() { //Need to reselect all groups in each chart d3.selectAll("#salesChart g.bar").sort(function(a, b) { return d3.descending(a.bonus, b.bonus); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#bonusChart g.bar").sort(function(a, b) { return d3.descending(a.bonus, b.bonus); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#oxytocinChart g.bar").sort(function(a, b) { return d3.descending(a.bonus, b.bonus); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); }); /// Descending Button - sort both graphs but keep linked d3.select("#sortRank") .on("click", function() { //Need to reselect all groups in each chart d3.selectAll("#salesChart g.bar").sort(function(a, b) { return d3.ascending(a.name, b.name); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#bonusChart g.bar").sort(function(a, b) { return d3.ascending(a.name, b.name); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#oxytocinChart g.bar").sort(function(a, b) { return d3.ascending(a.name, b.name); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); }); // I am trying Oxytocin d3.select("#sortOxytocin") .on("click", function() { //Need to reselect all groups in each chart d3.selectAll("#salesChart g.bar").sort(function(a, b) { return d3.descending(a.oxytocin, b.oxytocin); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#bonusChart g.bar").sort(function(a, b) { return d3.descending(a.oxytocin, b.oxytocin); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); d3.selectAll("#oxytocinChart g.bar").sort(function(a, b) { return d3.descending(a.oxytocin, b.oxytocin); }) .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("transform", function(d, i) { return "translate(" + xScale(i) + ",0)"; }); }); </script> </body> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js