Skip to content

Instantly share code, notes, and snippets.

@TheMcMurder
Last active September 25, 2015 00:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheMcMurder/10335129 to your computer and use it in GitHub Desktop.
Save TheMcMurder/10335129 to your computer and use it in GitHub Desktop.
Simple Line Chart

Part of the d3presentaion James Stewart and I did on BYU campus for the Information Systems department.

<!DOCTYPE html>
<html>
<style type="text/css">
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 5px;
}
</style>
<head>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
<title>D3js line chart</title>
</head>
<body>
</body>
<script type='text/javascript'>
//**********************************************************************************
// Sample Data
//**********************************************************************************
var data =
[
['1-Jan-14', 50],
['1-Feb-14', 60],
['1-Mar-14', 70],
['1-Apr-14', 80],
['1-May-14', 90],
['1-Jun-14', 70],
['1-Jul-14', 50],
['1-Aug-14', 40],
['1-Sep-14', 80],
['1-Oct-14', 90],
['1-Nov-14', 20],
['1-Dec-14', 50]
]
//**********************************************************************************
// General use variables for later use
//**********************************************************************************
var width = 600, height = 600, chart_width = width - 100, chart_height = height - 100;
//**********************************************************************************
// Appending the SVG to the body
//**********************************************************************************
var svg = d3.select('body').append('svg')
.attr({'width': width, 'height' : height})
//**********************************************************************************
// appending a group to the svg. Note You could append everthing directly to the
// svg. It is good practice to append things to groups so you can manipulate them
// as a group instead of translating, scaling, or rotating them all independantly
// use a group when you want to manipulate clusters of items together.
//**********************************************************************************
var group = svg.append('g')
.attr("transform", "translate(50, 50)")
//**********************************************************************************
// D3 parse function. This ParseObject can parse our custom time format into date
// objects
//**********************************************************************************
var parseDate = d3.time.format('%d-%b-%y').parse;
//**********************************************************************************
// Setting up the x axis scale we'll add the min and max later
//**********************************************************************************
var x = d3.time.scale()
.range([0, chart_width]);
//**********************************************************************************
// Setting up the y axis scale again we'll ad the min and max later
//**********************************************************************************
var y = d3.scale.linear()
.range([chart_height, 0]);
//**********************************************************************************
// Creating the x and y Axes, notice that we apply the the scale below by chaining
// it and we use on orientation to place it on the chart.
//
// On the xAxis we're adding a tickformater function using the same d3.time.format
// only this time we're parsing a date object into the desired format.
//**********************************************************************************
var xAxis = d3.svg.axis()
.scale(x)
.orient('bottom')
.tickFormat(d3.time.format('%b'));
var yAxis = d3.svg.axis()
.scale(y)
.orient('left');
//**********************************************************************************
// SVG line generator. We define how we want the line to generate by specifying
// values for the x and the y. In this case we have a 2D array so we are instructing
// which value in the array we want for each data point via an annoymous function
//**********************************************************************************
var line = d3.svg.line()
.x(function(d) {return x(d[0]); })
.y(function(d) {return y(d[1]); });
//**********************************************************************************
// Data manipulation: Parsing the time string into a date object for d3 to utilize
//**********************************************************************************
data.forEach(function(d){
d[0] = parseDate(d[0])
})
//**********************************************************************************
// Setting the domain on the x and y scales for their appropriate axes. This could
// be done during the defintion I'm placing them outside to show you how d3 hasn't
// utilized them yet.
//**********************************************************************************
x.domain(d3.extent(data, function(d) { return d[0]; }));
y.domain(d3.extent(data, function(d) { return d[1]; }));
//**********************************************************************************
// Creating a group and appending it to the group we've previously created.
// We're transforming this group the height of the chart down (relative to the group
// that it is already in) so it ends up at the bottom of the chart.
// Then we apply the xAxis upon this group and now the xAxis is implemented on the
// SVG group we've created
//**********************************************************************************
group.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + chart_height + ")")
.call(xAxis);
//**********************************************************************************
// Similar to above except this time with the y axis and it doesn't need a
// translation
//**********************************************************************************
group.append("g")
.attr("class", "y axis")
.call(yAxis)
//**********************************************************************************
// Here is where the magic of d3 happens
// 1. We create a new path element on the svg group
// 2. We bind the data to it (data is in brackets because we only want one item)
// unlike when we utilize a .enter() on databind but more on that in another
// chart
// 3. We apply the class line to get our styling
// 4. d is the attribute on the line that defines it's shape. Here we're setting
// that attribute to the value of our svg line generator above. (Magic)
// 5. Setting the fill to none so only the line is visible
// 6. Setting the stroke-width
// 7. Giving the stroke a color
//
// Note: 6 and 7 are redundant because we've set them in our class
//**********************************************************************************
var path = group.append("path")
.data([data])
.attr("class", "line")
.attr("d", line)
.style("fill", 'none')
.attr('stroke-width', 1)
.attr('stroke', 'black')
//**********************************************************************************
// Getting the total length of the line for the animation
// The animation utilizes a stroke dash array and sets the gap equal to the entire
// length of the line (so nothing shows up) then iterates linearly moving the blank
// area equal to nothing (so the line fills in slowly and beatifully)
//**********************************************************************************
var totalLength = path.node().getTotalLength();
path.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0);
//**********************************************************************************
// Appending the hover effects
//**********************************************************************************
var reformat = d3.time.format('%d-%b-%y')
var hoverGroup = svg.append('g')
var tooltip = hoverGroup.append('path')
.attr('d', 'M0,0l-5 -5h-40a5,5 0 0 1 -5,-5v-40a5,5 0 0 1 5,-5h90a5,5 0 0 1 5,5v40a5,5 0 0 1 -5,5h-40l-5 5z')
.style('fill', 'steelblue')
var hoverText = hoverGroup.append('text')
.text('hello')
.style("text-anchor", "middle")
.style("font-family", "Open Sans")
.attr("transform", "translate(" + 0 + "," + (-33) + ")")
.style("fill", "white")
.style("font-size", 14)
var hoverText2 = hoverGroup.append('text')
.text('hello')
.style("text-anchor", "middle")
.style("font-family", "Open Sans")
.attr("transform", "translate(" + 0 + "," + (-18) + ")")
.style("fill", "white")
.style("font-size", 14)
path.on('mouseover', function (d){
tooltip.attr('d', 'M0,0l-5 -5h-40a5,5 0 0 1 -5,-5v-40a5,5 0 0 1 5,-5h90a5,5 0 0 1 5,5v40a5,5 0 0 1 -5,5h-40l-5 5z')
var mousex, mousey, chartx, charty;
mousex = d3.mouse(svg.node())[0]
mousey = d3.mouse(svg.node())[1]
charty = y.invert(mousey);
chartx = x.invert(mousex);
charty = charty * 1000
charty = Math.floor(charty)
charty = charty/1000
hoverText.text('' + reformat(chartx))
hoverText2.text('' + charty)
hoverGroup.attr('transform', 'translate('+ mousex + ',' + (mousey - 15) + ')')
})
path.on('mousemove', function (d){
mousex = d3.mouse(svg.node())[0]
mousey = d3.mouse(svg.node())[1]
charty = y.invert(mousey);
chartx = x.invert(mousex);
charty = charty * 1000
charty = Math.floor(charty)
charty = charty/1000
hoverText.text('' + reformat(chartx))
hoverText2.text('' + charty)
hoverGroup.attr('transform', 'translate('+ mousex + ',' + (mousey - 15) + ')')
})
svg.on('mouseout', function (d){
hoverText2.text('')
hoverText.text('')
tooltip.attr('d', 'M0,0')
})
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment