D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
jadiehm
Full window
Github gist
Line area chart with swoopy drag annotations
<!doctype html> <html lang='en-GB'> <head> <meta charset='utf-8'> </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; } p { font-family: sans-serif; font-size: 14px; margin: 5px 0 0 0; } /*template styles*/ .gia-chart-wrapper { max-width: 960px; margin: 0 auto; } /*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: 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-label-circle { fill: #4bc6df; } .g-label-text, .g-label-text-bold { font-family: sans-serif; font-size: 14px; text-align: left; } .g-label-text-bold { font-weight: 700; } .annotations path{ fill: none; stroke: black; } .annotations g:hover circle{ stroke: red; } .annotations g:hover text{ fill: red; } .swoopy-drag-lines path { fill: none; stroke: #333333; } .swoopy-drag-lines text { font-family: sans-serif; font-size: 14px; text-align: left; fill: #333333; } .swoopy-drag-lines tspan:first-child { font-weight: 700; } @media (max-width: 575px) { .label-group1, .label-group3, .label-group4, .label-group5 { display: none; } } @media (max-width: 475px) { .label-group1, .label-group2, .label-group3, .label-group4, .label-group5 { display: none; } } @media (max-width: 375px) { .label-group1, .label-group2, .label-group3, .label-group4, .label-group5, .label-group6, .label-group7 { display: none; } } </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 src='d3-jetpack.js'></script> <script src='swoopy-drag.js'></script> <script> //Margin conventions var margin = {top: 50, right: 5, bottom: 30, left: 25}; var widther = d3.select(".gia-chart").node().clientWidth; var width = widther - margin.left - margin.right, height = 430 - margin.top - margin.bottom; //Parses date for correct time format var parseDate = d3.time.format("%e-%b-%y").parse; var monthArr = ['Jan.', 'Feb.', 'March', 'Apr.', 'May', 'June', 'July', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.']; //Appends the svg to the chart-container div var svg = d3.select(".gia-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 + ")"); //Creates the xScale var xScale = d3.time.scale() .range([0, width]); //Creates the yScale var yScale = d3.scale.linear() .range([height, 0]); //Defines the y axis styles var yAxis = d3.svg.axis() .scale(yScale) .tickSize(-width) .tickPadding(8) .orient("left"); //Defines the y axis styles var xAxis = d3.svg.axis() .scale(xScale) .tickPadding(8) .orient("bottom") .ticks(6) .tickFormat(d3.time.format("%Y")); //line function convention (feeds an array) var line = d3.svg.line() .x(function(d) { return xScale(d.date); }) .y(function(d) { return yScale(d.close); }); //area function var area = d3.svg.area() .x(function(d) {return xScale(d.date); }) .y0(height) .y1(function(d) {return yScale(d.close); }); //Loads the data d3.csv("swhc.csv", ready); function ready(err, data) { if (err) throw "error loading data"; //FORMAT data data.forEach(function(d) { d.close = +d.close; d.date = parseDate(d.date); }); //Organizes the data data.sort(function(a,b) { return a.date - b.date; }); var maxY = d3.max(data, function(d) { return d.close; }); //Defines the xScale max xScale.domain(d3.extent(data, function(d) { return d.date; })); //Defines the yScale max yScale.domain([0, 30]); //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 line var drawarea = svg.append("path") .datum(data) .attr("class", "area") .attr("d", area); //Binds the data to the line var drawline = svg.append("path") .datum(data) .attr("class", "line") .attr("d", line); //Adding labels var labelElements = svg.append("g") .attr("class", "fiddly-bits") var label = labelElements.selectAll(".g-label-element") .data(data.filter(function(d) { return d.event == "yes"; })) .enter().append("g") .attr("class", "g-label-element") .attr("transform", function(d) { return "translate(" + xScale(d.date) + "," + yScale(d.close) + ")"; } ); label.append("circle") .attr("r", 3) .attr("class", "g-label-circle"); /* label.append("text") .attr("x", 0) .attr("y", function(d) { if (d.position == "down") { return 30; } else { return -26; } }) .text(function(d) { return monthArr[d.date.getMonth()] + " " + d.date.getDate() + ", " + d.date.getFullYear() ; }) .style("text-anchor","end") .attr("class", "g-label-text-bold"); label.append("text") .attr("x", 0) .attr("y", function(d) { if (d.position == "down") { return 46; } else { return -10; } }) .text(function(d) { return d.desc_info; }) .style("text-anchor","end") .attr("class", "g-label-text"); */ //Swoopy-drag var annotations = [ { "xVal": 1467864000000, "yVal": 28.04, "path": "M0,-36L0,-9", "text": "July 7, 2016 Dallas police shooting", "textOffset": [ -76, -61 ] }, { "xVal": 1465704000000, "yVal": 22.5, "path": "M-113,-81C-62,-103,-6,-89,-1,-11", "text": "June 12, 2016 Orlando nightclub shooting", "textOffset": [ -172, -67 ] }, { "xVal": 1449032400000, "yVal": 18.18, "path": "M0,60L0,3", "text": "Dec. 2, 2015 San Bernardino terrorist attack", "textOffset": [ -23, 80 ] }, { "xVal": 1434513600000, "yVal": 15.75, "path": "M0,85L0,5", "text": "June 17, 2015 Charleston church shooting", "textOffset": [ -58, 102 ] }, { "xVal": 1403928000000, "yVal": 13.55, "path": "M50,-67C14,-65,0,-34,14,-6", "text": "July 28, 2014 S&W charged with bribing foreign officials", "textOffset": [ 53, -93 ] }, { "xVal": 1400817600000, "yVal": 15.08, "path": "M-80,-92C-27,-93,9,-58,-1,-8", "text": "May 23, 2014 Isla Vista shooting", "textOffset": [ -144, -117 ] }, { "xVal": 1379304000000, "yVal": 10.94, "path": "M0,41L0,4", "text": "Sept. 16, 2013 Washington, DC Navy Yard shooting", "textOffset": [ -25, 57 ] }, { "xVal": 1355461200000, "yVal": 9.05, "path": "M-20,-79C13,-66,27,-27,3,-7", "text": "Dec. 14, 2012 Sandy Hook school shooting", "textOffset": [ -71, -102 ] } ] var swoopy = d3.swoopyDrag() .x(function(d){ return xScale(d.xVal) }) .y(function(d){ return yScale(d.yVal) }) .draggable(false) .annotations(annotations) var swoopySel = svg.append('g').call(swoopy) .attr("class", "swoopy-drag-lines"); swoopySel.selectAll('text') .each(function(d){ d3.select(this) .text('') //clear existing text .tspans(d3.wordwrap(d.text, 12)) //wrap after 20 char }); swoopySel.selectAll('g') .attr("class", function(d, i) { return 'label-group'+i; }); //RESPONSIVENESS d3.select(window).on("resize", resized); function resized() { //new margin var newMargin = {top: 30, right: 5, bottom: 30, left: 25}; var newWidther = d3.select(".gia-chart").node().clientWidth; var newWidth = newWidther - newMargin.left - newMargin.right; //Change the width of the svg d3.select("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.date); }) .y(function(d) { return yScale(d.close); }); d3.selectAll('.line') .attr("d", line); //Updates circle labels d3.selectAll('.g-label-element') .attr("transform", function(d) { return "translate(" + xScale(d.date) + "," + yScale(d.close) + ")"; } ); //Update the area area = d3.svg.area() .x(function(d) {return xScale(d.date); }) .y0(height) .y1(function(d) {return yScale(d.close); }); d3.selectAll('.area') .attr("d", area); //Updates xAxis d3.selectAll(".x.axis") .call(xAxis); //Updates ticks xAxis .scale(xScale); //Updates yAxis d3.selectAll(".y.axis") .call(yAxis); yAxis .tickSize(-newWidth); swoopySel.remove(); swoopySel = svg.append('g').call(swoopy) .attr("class", "swoopy-drag-lines"); swoopySel.selectAll('g') .attr("class", function(d, i) { return 'label-group'+i; }); swoopySel.selectAll('text') .each(function(d){ d3.select(this) .text('') //clear existing text .tspans(d3.wordwrap(d.text, 12)) //wrap after 20 char }) }; } </script> </body> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js