D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
ohdebby
Full window
Github gist
Linked vis
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.min.js"></script> <style> .axis path, .axis line { stroke: #ccc; } .axis line { stroke-dasharray: 2; } .axis text { fill: #ccc; } .state text { font-weight: 600; } </style> </head> <body> <script> var width = 250; var height = 200; var margin = {top: 20, right: 30, bottom: 20, left: 30}; var xScale = d3.scaleLinear().range([0, width]); var yScale = d3.scaleLinear().range([height, 0]); var xAxis = d3.axisBottom() .scale(xScale) .ticks(5) .tickFormat(d => "'" + new String(d).slice(2)) .tickSizeInner(-height) .tickSizeOuter(0) .tickPadding(6); var yAxis = d3.axisLeft() .scale(yScale) .ticks(5) .tickFormat(d => d + '%') .tickSizeInner(-width) .tickSizeOuter(0) .tickPadding(6); var line = d3.line() .x(d => xScale(d.year)) .y(d => yScale(d.rate)); var red = '#d8472b'; var dispatch = d3.dispatch('load', 'yearchange'); d3.json('data.json', function(err, data) { var flatData = []; data.forEach(obj => { var year = +obj.date; for (key in obj) { if (key !== 'date' && key !== 'avg' && key !== 'D.C.') { var state = key; var rate = obj[key]; flatData.push({ year: year, state: state, rate: +rate, }); } } }); // get the domain for scales var xDomain = d3.extent(flatData, d => d.year); var yDomain = d3.extent(flatData, d => d.rate); xScale.domain(xDomain); yScale.domain(yDomain).nice(); var dataByState = d3.nest() .key(d => d.state) .entries(flatData); // create svg for each state var svg = d3.select('body') .selectAll('svg') .data(dataByState, d => d.state) .enter().append('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .append('g') .attr('transform', 'translate(' + [margin.left, margin.top] + ')'); dispatch.call('load', null, svg, dataByState); // default hovered year to 2016 dispatch.call('yearchange', null, 2016); }); // draw the static graph for each state dispatch.on('load.graph', (svg, dataByState) => { // draw axes svg.append('g') .classed('x axis', true) .attr('transform', 'translate(' + [0, height] + ')') .call(xAxis); svg.append('g') .classed('y axis', true) .call(yAxis); // draw lines svg.append('path') .datum(d => d.values) .attr('d', line) .attr('stroke', red) .attr('stroke-width', 2) .attr('fill', 'none'); svg.append('rect') .attr('width', width) .attr('height', height) .attr('opacity',0) .on('mousemove',function(){ var [x, y] = d3.mouse(this); var year = Math.round(xScale.invert(x)); dispatch.call('yearchange', null, year); }); }); dispatch.on('load.title', (svg) => { var title = svg.append('text'); dispatch.on('yearchange.title', year => { title.text(d => { var rate = d.values.find(d => d.year === year); rate = rate ? d3.format('.1f')(rate.rate) + '%' : 'N/A'; return d.key + ' (' + rate + ')'; }) }); }); dispatch.on('load.point', svg => { var g = svg.append('g'); g.append('circle') .attr('fill', red) .attr('r', 5); g.append('text') .attr('text-anchor', 'middle') .attr('font-size', 11); dispatch.on('yearchange.point', year => { g.attr('transform', d => { var rate = d.values.find(d => d.year === year); return 'translate(' + [xScale(rate.year), yScale(rate.rate)] + ')'; }); g.select('text') .text(d => { var rate = d.values.find(d => d.year === year); return rate.year + ' (' + d3.format('.1f')(rate.rate) + '%)'; }); }); }); </script> </body>
https://d3js.org/d3.v4.min.js