D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
jadiehm
Full window
Github gist
Linked small multiple area charts with focus hovers
<!doctype html> <html lang='en-GB'> <head></head> <style> body { font-family: sans-serif; font-size: 16px; line-height: 1.4; display: block; margin: 0; padding: 0; color: #333; -webkit-font-smoothing: antialiased; } h5 { font-family: sans-serif; font-size: 16px; font-weight: 700; margin: 0; } p { font-family: sans-serif; font-size: 14px; } /*template styles*/ .gia-chart-wrapper { max-width: 960px; margin: 0 auto; } .g-chart-container { width:20%; display: inline-block; margin-top: 20px; } @media (max-width: 700px) { .g-chart-container { width:25%; margin: 0 auto; margin-top: 20px; } .g-name { margin-top: 10px; } } @media (max-width: 600px) { .g-chart-container { width:33.3%; margin: 0 auto; margin-top: 20px; } } @media (max-width: 400px) { .g-chart-container { width:50%; margin: 0 auto; margin-top: 20px; } } @media (max-width: 350px) { .g-chart-container { width:100%; margin: 0 auto; margin-top: 20px; } } .gia-source { border-top: 1px solid #ccc; margin-top: 25px; color: #bdbdbd; padding: 3px 0; font-size: 12px; font-family: 'Guardian Text Sans Web',Arial,sans-serif; } /*chart styles*/ .y.axis line { fill: none; stroke: #dcdcdc; stroke-dasharray: 1px 1px; shape-rendering: crispEdges; stroke-width: 1px; } .x.axis line { fill: none; stroke: #333333; shape-rendering: crispEdges; stroke-width: 1px; } .tick.g-baseline line { stroke: #333333; stroke-dasharray: 0; stroke-width: 1px; } .axis text { font-family: 'Guardian Text Sans Web',Arial,sans-serif; font-size: 12px; pointer-events: none; fill: #bdbdbd; } .y.axis text { text-anchor: end !important; font-size:12px; fill: #bdbdbd; } .domain { display: none; } .line { stroke: #4bc6df; stroke-width: 2px; fill: none; } .area { fill: #4bc6df; opacity: 0.1; } .g-name { font-weight: 700; } .g-label-no-show { display: none; } .g-label-text { font-family: 'Guardian Text Sans Web', Helvetica, sans-serif; font-weight: 700; font-size: 12px; color: #333333; } .g-label-circle { fill: #4bc6df; } .overlay { fill: none; pointer-events: all; } .focus { font-size: 14px; } .focus circle { fill: #4bc6df; } .focus text { font-family: 'Guardian Text Sans Web', Helvetica, sans-serif; font-size: 14px; } .startline { stroke: #333333; stroke-width: 1px; } </style> <body> <main> <div class='gia-chart-wrapper'> <div class='gia-chart'></div> </div> </main> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script> <script> //NBA names var allNames = ["Alonzo", "Anfernee", "Carmelo", "Chauncey", "Clyde", "Dirk", "Draymond", "Emeka", "Hakeem", "Isiah", "Jalen", "Julius", "Kareem", "Kawhi", "Kobe", "Latrell", "Lebron", "Manu", "Oscar", "Rajon", "Rasheed", "Reggie", "Serge", "Shaquille", "Tayshaun", "Yao"]; //Parses date for correct time format var parseDate = d3.time.format("%Y").parse; //Loads the data d3.csv("NBANames2.csv", ready); function ready(err, data) { if (err) throw "error loading data"; //FORMAT data data.forEach(function(d) { d.count = +d.count; d.year = parseDate(d.year) d.start = parseDate(d.start); }); //Organizes the data var maxY = d3.max(data, function(d) { return d.count; }); var maxX = d3.max(data, function(d) { return d.year; }); var minX = d3.min(data, function(d) { return d.year; }); //Map the property names to the data allNames = d3.set(data.map(function(d) { return d.name; })).values(); //Make a chart for each property var charts = allNames.map(makeChart); //Syncs all charts together function syncFocus (x0) { charts.forEach(function(chart) { chart.updateFocus(x0); }); } //RESPONSIVENESS d3.select(window).on("resize", function () { charts.forEach(function(chart) { chart.resize(); }) }); function makeChart(name, chartIndex) { //Append individual chart div var chartContainer = d3.select(".gia-chart").append("div") .attr("class", "g-chart-container"); //Margin conventions var margin = {top: 20, right: 20, bottom: 30, left: 32}; var widther = d3.select(".g-chart-container").node().clientWidth; var width = (widther) - margin.left - margin.right, height = 250 - margin.top - margin.bottom; //Creates the xScale var xScale = d3.time.scale() .range([0, width]); //Creates the yScale var yScale = d3.scale.linear() .range([height, 0]); //line function convention (feeds an array) var line = d3.svg.line() .x(function(d) { return xScale(d.year); }) .y(function(d) { return yScale(d.count); }); //area function var area = d3.svg.area() .x(function(d) {return xScale(d.year); }) .y0(height) .y1(function(d) {return yScale(d.count); }); //Defines the xScale max xScale.domain(d3.extent(data, function(d) { return d.year; })); //Defines the yScale max yScale.domain([0, maxY]); //Defines the y axis styles var yAxis = d3.svg.axis() .scale(yScale) .tickSize(-width) .tickPadding(8) .ticks(5) .orient("left"); //Defines the y axis styles var xAxis = d3.svg.axis() .scale(xScale) .tickPadding(8) .orient("bottom") .tickValues([minX, maxX]) .tickFormat(d3.time.format("%Y")); //Finds the data associated with each name var myCurrentName = name; var myNameData = data.filter(function(d) { return d.name === myCurrentName; }); //Sets value for ending dot on line var maxXdot = d3.max(myNameData, function(d) { return d.year; }); var maxXdot = d3.max(myNameData, function(d) { return d.start; }); //Appends the property name to the individual chart container var chartName = chartContainer.append("h5") .attr("class", "g-name"); //Appends the name chart to the individual chart container var chart = chartContainer.append("div") .attr("class", "g-chart"); //Assigns the property name chartName.text(myCurrentName); //Appends the svg to the chart-container div var svg = chart.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 + ")"); //Appends the y axis var yAxisGroup = svg.append("g") .attr("class", "y axis") .call(yAxis) .selectAll("g") .classed("g-baseline", function(d) {return d == 0}); //Appends the x axis var xAxisGroup = svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); //Binds the data to the area var drawarea = svg.append("path") .datum(myNameData) .attr("class", "area") .attr("d", area); //Binds the data to the line var drawline = svg.append("path") .datum(myNameData) .attr("class", "line") .attr("d", line) .selectAll("line"); //Adds vertical line var startline = svg.append("line") .datum(myNameData[0]) .attr("x1", function(d) {return xScale(d.start); }) .attr("y1", 5) .attr("x2", function(d) { return xScale(d.start); }) .attr("y2", 200) .attr("class", "startline"); var starttext = svg.append("text") .datum(myNameData[0]) .attr("transform", function(d) { return "translate(" + (xScale(d.start)+15) + "," + yScale(510) + ")"; } ) .attr("text-anchor", "end") .text(function(d) { return d.start.getFullYear();}) .attr("class", "g-label-text"); //LINKED INTERACTIVES //Divides date for tooltip placement var bisectDate = d3.bisector(function(d) { return d.year; }).left; //Tooltips var focus = svg.append("g") .attr("class", "focus") .style("display", "none"); //Adds circle to focus point on line focus.append("circle") .attr("r", 4); //Adds text to focus point on line focus.append("text") .attr("x", -10) .attr("y", -10) .attr("dy", ".35em"); //Creates larger area for tooltip var overlay = svg.append("rect") .attr("class", "overlay") .attr("width", width) .attr("height", height) .on("mouseover", function() { d3.selectAll('.focus') .style("display", null); }) .on("mouseout", function() { d3.selectAll('.focus') .style("display", "none"); }) .on("mousemove", mousemove); //Tooltip mouseovers function mousemove() { var x0 = xScale.invert(d3.mouse(this)[0]); syncFocus(x0); } return { updateFocus: function (x0) { var i = bisectDate(myNameData, x0, 1), d0 = myNameData[i - 1], d1 = myNameData[i], d = x0 - d0.year > d1.year - x0 ? d1 : d0; focus.attr("transform", "translate(" + xScale(d.year) + "," + yScale(d.count) + ")"); focus.select("text").text(d3.round(d.count, 1)); }, resize: function () { //new margin var newMargin = {top: 20, right: 20, bottom: 30, left: 32}; var newWidther = d3.select(".g-chart-container").node().clientWidth; var newWidth = (newWidther) - newMargin.left - newMargin.right; //Change the width of the svg d3.selectAll("svg") .attr("width", newWidth + newMargin.left + newMargin.right); //Change the xScale xScale .range([0, newWidth]); //Update the line line = d3.svg.line() .x(function(d) { return xScale(d.year); }) .y(function(d) { return yScale(d.count); }); d3.selectAll('.line') .attr("d", line); //Update the area area = d3.svg.area() .x(function(d) {return xScale(d.year); }) .y0(height) .y1(function(d) {return yScale(d.count); }); d3.selectAll('.area') .attr("d", area); //Updates label d3.selectAll('.g-label-element0') .attr("transform", function(d) { return "translate(" + xScale(d.year) + "," + yScale(d.count) + ")"; } ); //Updates xAxis d3.selectAll(".x.axis") .call(xAxis); xAxis .scale(xScale); //Updates yAxis d3.selectAll(".y.axis") .call(yAxis); yAxis .tickSize(-newWidth); //Updates overlay d3.selectAll(".overlay") .attr("width", newWidth); //Updates vertical line d3.selectAll(".startline") .attr("x1", function(d) {return xScale(d.start); }) .attr("x2", function(d) { return xScale(d.start); }) d3.selectAll(".g-label-text") .attr("transform", function(d) { return "translate(" + (xScale(d.start)+15) + "," + yScale(510) + ")"; } ) } }; } } </script> </body> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js