D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
Brideau
Full window
Github gist
Canadian Income Tax Line Chart
A line chart of Canadian Income tax [work in progress].
<!DOCTYPE html> <meta charset="utf-8"> <html> <head> <title></title> <link href='https://fonts.googleapis.com/css?family=Anonymous+Pro:400,400italic,700,700italic' rel='stylesheet' type='text/css'> <style> html { width: 100%; height: 100%; margin: 0; padding: 0; } body { font: 12px sans-serif; margin-left: 5%; margin-right: 5%; } body { width: 90%; font-family: Arial, sans-serif;; } text { font-family: 'Anonymous Pro', Arial, sans-serif; font-size: 15px; font-weight: 700; } #menu { text-align: left; line-height: 1.5em; } #menu select { border: none; background-color: white; background-color: rgba(103, 103, 103, 0.09); } #menu, #menu select { font-size: 40px; } .axis path, .axis line { fill: none; stroke: #C2C2C2; stroke-width: .5px; stroke-linejoin: round; shape-rendering: crispEdges; } .line { fill: none; stroke: steelblue; stroke-width: 1.5px; stroke-linecap: round; } .line:hover { stroke-width: 2; stroke: steelblue; } .highlighted, .previous { stroke: #267129; stroke-width: 3; stroke-dasharray: 5,5; } .previous { stroke: red; } .highlighted { stroke: #267129; } .bgline { stroke: rgba(103, 103, 103, 0.09); } .ylabel { font-size: 1.5em; } .chart { width: 100%; height: 100%; } </style> <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script> <script src="d3kit.min.js" charset="utf-8"></script> <script src="kodama.js" charset="utf-8"></script> <script src="underscore-min.js" charset="utf-8"></script> </head> <body> <p id="menu"> How have income taxes in <select id="provMenu"> <option value="ab">Alberta</option> <option value="bc">British Columbia</option> <option value="mb">Manitoba</option> <option value="nb">New Brunswick</option> <option value="nl">Newfoundland and Labrador</option> <option value="nt">Northwest Territories</option> <option value="ns">Nova Scotia</option> <option value="nu">Nunavut</option> <option value="on">Ontario</option> <option value="pe">Prince Edward Island</option> <option value="qc">Quebec</option> <option value="sk">Saskatchewan</option> <option value="yt">Yukon</option> </select><br> changed since <select id="yearMenu"> <option value="2015">2015</option> <option value="2014">2014</option> </select> ? </p> <div class="chart"></div> <script> d3.json("avgTaxAll.json", function(error, data) { if (error) throw error; var provChange = function() { var prov = provMenu.property("value"); var currYear = yearMenu.property("value"); var singleProvHi = provinces["2016"].filter(function(d){ return d.name == prov; }); var singleProvPrev = provinces[currYear].filter(function(d){ return d.name == prov; }); chart.getRootG() .selectAll(".highlighted") .data(singleProvHi) .call(highlighted.update); chart.getRootG() .selectAll(".previous") .data(singleProvPrev) .call(previous.update); }; var provMenu = d3.select("#provMenu").on("change", provChange); var yearMenu = d3.select("#yearMenu").on("change", provChange); var onResize = function() { xScale.range([0, chart.getInnerWidth()]); yScale.range([chart.getInnerHeight(), 0]); chart.getRootG() .select(".x") .transition() .duration(1000) .attr("transform", "translate(0, " + chart.getInnerHeight() + ")") .call(xAxis); chart.getRootG() .select(".y") .transition() .duration(1000) .call(yAxis); chart.getRootG() .select(".ylabel") .transition() .duration(1000) .attr("x", -1 * chart.getInnerHeight() / 2 + 100); chart.getRootG().selectAll('.province') .call(lines.update); chart.getRootG().selectAll('.highlighted') .call(highlighted.update); chart.getRootG().selectAll('.previous') .call(previous.update); }; var onData = function(newData) { if (chart.hasData()) { var chartLines = chart.getRootG() .selectAll(".province") .data(newData) .enter() .append("g") .classed("province", true) .call(lines.enter); var prov = provMenu.property("value"); var currYear = yearMenu.property("value"); console.lo var singleProvHi = provinces["2016"].filter(function(d){ return d.name == prov; }); var singleProvPrev = provinces[currYear].filter(function(d){ return d.name == prov; }); var highlightProv = chart.getRootG() .selectAll(".highlightGroup") .data(singleProvHi) .enter() .append("g") .classed("highlightGroup", true) .call(highlighted.enter); var prevProv = chart.getRootG() .selectAll(".previousGroup") .data(singleProvPrev) .enter() .append("g") .classed("previousGroup", true) .call(previous.enter); onResize(); provChange(); } }; var DEFAULT_OPTIONS = { margin: {top: 50, right: 50, bottom: 50, left: 80}, initialHeight: 500, initialWidth: 1080 }; var chart = new d3Kit.Skeleton('.chart', DEFAULT_OPTIONS) .autoResize('full') .on('resize', onResize) .on('data', onData); var xScale = d3.scale.linear().range([0, chart.getInnerWidth()]); var yScale = d3.scale.linear().range([chart.getInnerHeight(), 0]); // Kodama theme var ccTheme = { frame: { padding: '4px', background: 'rgba(103, 103, 103, 0.09)', 'font-family': '"Anonymous Pro", Arial, sans-serif', 'border': 'none', color: 'black', 'border-radius': '4px', 'font-size': '26px', 'box-shadow': 'none' }, title: {'text-align': 'center', 'padding': '4px'}, item_title: {'text-align': 'right', 'color': 'rgb(220,200,120)'}, item_value: {'padding': '1px 2px 1px 10px', 'color': 'rgb(234, 224, 184)'}, options: null }; d3.kodama.themeRegistry('ccTheme', ccTheme); var xAxis = d3.svg.axis() .scale(xScale) .orient("bottom") .tickFormat(d3.format('$,.d')); var yAxis = d3.svg.axis() .scale(yScale) .orient("left") .tickFormat(d3.format('.0%')); var lineGen = d3.svg.line() .interpolate("monotone") .x(function(d) { return xScale(d.income); }) .y(function(d) { return yScale(d.avgTax); }); var taxLineChartlet = function() { var events = []; var chartlet = d3Kit.Chartlet(enter, update, events); function enter(selection, done) { selection.append("path") .classed("line", true) .classed("bgline", true) .attr("d", function(d) { return lineGen(d.values); }) .call(d3.kodama.tooltip()); done(selection); } function update(selection, done) { selection.select(".line") .transition() .duration(1000) .attr("d", function(d) { return lineGen(d.values); }) .each('end', done); } return chartlet; }; var highlightProv = function() { var events = []; var chartlet = d3Kit.Chartlet(enter, update, events); function enter(selection, done) { selection.append("path") .classed("line", true) .classed("highlighted", true) .attr("d", function(d) { return lineGen(d.values); }) .call(d3.kodama.tooltip()); done(selection); } function update(selection, done) { selection.transition() .duration(1000) .attr("d", function(d) { return lineGen(d.values); }) .each("end", done); } return chartlet; }; var previousProv = function() { var events = []; var chartlet = d3Kit.Chartlet(enter, update, events); function enter(selection, done) { selection.append("path") .classed("line", true) .classed("previous", true) .attr("d", function(d) { return lineGen(d.values); }) .call(d3.kodama.tooltip()); done(selection); } function update(selection, done) { selection.transition() .duration(1000) .attr("d", function(d) { return lineGen(d.values); }) .each("end", done); } return chartlet; }; // Create a nice data structue to work with. This // stores each province's data in a different array // element with all the data we need to plot it // Used to convert the longer names to keys for each access later var provinceLookup = { "Alberta": "ab", "British Columbia": "bc", "Manitoba": "mb", "New Brunswick": "nb", "Newfoundland and Labrador": "nl", "Northwest Territories": "nt", "Nova Scotia": "ns", "Nunavut": "nu", "Ontario": "on", "Prince Edward Island": "pe", "Quebec": "qc", "Saskatchewan": "sk", "Yukon": "yt" }; var transformData = function(year, data) { return data.map(function(each) { return { name: provinceLookup[each.key], values: each.values.map(function(d) { return {income: d.x, avgTax: d.y}; }), // These are all used for the Kodama tooltips title: each.key + " - " + year, distance: 10, theme: 'ccTheme' }; }); }; provinces = _.mapObject(data, function(value, key) { return transformData(key, value); }); // Get the max and min values of income xScale.domain(d3.extent(provinces["2016"][0].values, function(each) { return each.income; })); // Get the global max and min average tax rate from the nested object yMin = d3.min(provinces["2016"], function(prov) { return d3.min(prov.values, function(value) { return value.avgTax; }); }); yMax = d3.max(provinces["2016"], function(prov) { return d3.max(prov.values, function(value) { return value.avgTax; }); }); yScale.domain([yMin, yMax*1.1]); // Create the x-axis chart.getRootG() .append("g") .attr("class", "x axis") .attr("transform", "translate(0, " + chart.getInnerHeight() + ")") .call(xAxis); // Create the y-axis and label it chart.getRootG() .append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", -55) .attr("x", -1 * chart.getInnerHeight() / 2 + 100) .style("text-anchor", "end") .text("Average Tax Rate (%)") .attr("class", "ylabel"); var lines = taxLineChartlet(); var highlighted = highlightProv(); var previous = previousProv(); chart.data(provinces["2016"]); }); </script> </body> </html>
https://d3js.org/d3.v3.min.js