|
var randomData = [] |
|
|
|
// create a bunch of values for the graph |
|
function createrandomData() { |
|
var now = Date.now() |
|
for(var i = 0; i < 120; i++) { |
|
randomData[i] = { |
|
yValue: (Math.random() - 0.5) * 200, |
|
time: now + (i * 1000) |
|
} |
|
} |
|
} |
|
|
|
function createGraph() { |
|
createrandomData() |
|
// define plot boundaries |
|
var width = 300, |
|
height = 60 |
|
var margin = { |
|
top: 0, |
|
right: 50, |
|
bottom: 5, |
|
left: 50 |
|
} |
|
var plot = { |
|
width: width - margin.right - margin.left, |
|
height: height - margin.top - margin.bottom |
|
} |
|
// x-axis is time |
|
var x = d3.time.scale() |
|
.range([0, plot.width]) |
|
// y-axis is numerical |
|
var y = d3.scale.linear() |
|
.range([plot.height, 0]) |
|
// set axis scales |
|
var xAxis = d3.svg.axis() |
|
.scale(x) |
|
.orient('bottom') |
|
.tickFormat(d3.time.format('%M:%S')) |
|
.tickSize(0, 0).ticks(6) |
|
|
|
var yAxis = d3.svg.axis() |
|
.scale(y) |
|
.orient('left') |
|
.tickSize(0, 0).ticks(3) |
|
|
|
x.domain([randomData[0].time, randomData[randomData.length - 1].time]) |
|
y.domain([-100, 100]) |
|
|
|
var line = d3.svg.line() |
|
.x(function(d) { return x(parseInt(d.time)) }) |
|
.y(function(d) { return y(d.yValue) }) |
|
// make the graph |
|
var svg = d3.select('#graph') |
|
var graph = undefined |
|
|
|
if (d3.select('.graph-g').empty()) { |
|
graph = svg.append('g') |
|
.attr('class', 'graph-g') |
|
.attr('width', plot.width) |
|
.attr('height', plot.height) |
|
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') |
|
//add axes |
|
graph.append('g') |
|
.attr('class', 'x axis') |
|
.attr('transform', 'translate(0,' + plot.height + ')') |
|
.call(xAxis) |
|
|
|
graph.append('g') |
|
.attr('class', 'y axis') |
|
.call(yAxis) |
|
.append('text') |
|
.attr('transform', 'rotate(-90)') |
|
.attr('dx', (0 - plot.height / 2)) |
|
.attr('dy', '-2.8em') |
|
.style('text-anchor', 'middle') |
|
.text('Value') |
|
} else { |
|
graph = d3.select('.graph-g') |
|
} |
|
|
|
//add data line |
|
graph.append('path') |
|
.datum(randomData) |
|
.attr('class', 'line') |
|
.attr('d', line) |
|
|
|
// Tooltip for yValue value at point of hover on line. |
|
// create tooltip |
|
var tip = graph.append('g') |
|
.attr('class', 'tool-tip') |
|
.style('visibility', 'hidden') |
|
|
|
var tipBg = tip.append('rect') |
|
.attr('class', 'tool-tipBG') |
|
|
|
var tipTitle = tip.append('text') |
|
.attr('x', '0') |
|
.attr('y', '0') |
|
.attr('class', 'tip-title') |
|
.text('00:00') |
|
|
|
var titleBB = tipTitle.node().getBBox() |
|
|
|
var tipVal = tip.append('text') |
|
.attr('x', '0') |
|
.attr('y', '0') |
|
.attr('class', 'tip-number') |
|
.text('+100') |
|
tipVal |
|
.attr('y', tipVal.node().getBBox().height - 2) |
|
.attr('x', tipVal.node().getBBox().width - 3) |
|
|
|
var valBB = tipVal.node().getBBox() |
|
|
|
var tipText = tip.append('text') |
|
.attr('x', valBB.width) |
|
.attr('y', valBB.height - 2) |
|
.attr('class', 'tip-text') |
|
.text('sprokets') |
|
|
|
var textBB = tipText.node().getBBox() |
|
|
|
tipBg |
|
.attr('x', '0') |
|
.attr('y', -titleBB.height - 3) |
|
.attr('dx', '-3') |
|
.attr('rx', '4') |
|
.attr('ry', '4') |
|
.attr('width', |
|
Math.max(valBB.width + textBB.width + 7, titleBB.width + 7) |
|
) |
|
.attr('height', titleBB.height + valBB.height + 6) |
|
|
|
var bgBB = tipBg.node().getBBox() |
|
|
|
tipTitle.attr('dx', bgBB.width/2) |
|
tipTitle.attr('dy', -2) |
|
tipVal.attr('dx', (bgBB.width - valBB.width - textBB.width)/2 ) |
|
tipText.attr('dx', (bgBB.width - valBB.width - textBB.width)/2 - 2) |
|
|
|
tip.append('path') |
|
.attr('class', 'tool-tipPoint') |
|
.attr('d', 'M-6,0L6,0L0,8Z') |
|
.attr('transform', 'translate('+bgBB.width/2+', '+(valBB.height+2.8)+')') |
|
|
|
// set bisection data |
|
var bisect = d3.bisector(function(d) { return d.time }).left |
|
// show/hide tooltip |
|
|
|
function updateTipData() { |
|
var x0 = x.invert(d3.mouse(this)[0]) |
|
var i = bisect(randomData, x0, 1) |
|
// find the closest value to the mouse |
|
var dPre = randomData[i - 1], |
|
dPost = randomData[i] |
|
if (typeof dPost === 'undefined') { |
|
return false |
|
} |
|
var d = x0 - dPre.time < dPost.time - x0 |
|
? dPre |
|
: dPost |
|
// apply value to tip text (with + for pos, - for neg, and null for 0) |
|
tipVal.text(function() { |
|
return (d.yValue > 0 |
|
? '+'+Math.round(d.yValue) |
|
: Math.round(d.yValue) |
|
) |
|
}) |
|
tipTitle.text(function() { |
|
var time = new Date(d.time) |
|
return ('0'+time.getMinutes()).slice(-2)+':'+('0'+time.getSeconds()).slice(-2) |
|
}) |
|
// show tip at nearest data point |
|
tip.attr('transform', 'translate('+( x(d.time) - bgBB.width/2)+','+( y(d.yValue) - bgBB.height/2 - 9 )+')') |
|
} |
|
|
|
graph.on('mouseover', function() { tip.style('visibility', 'visible') }) |
|
|
|
d3.select('.line').on('mousemove', updateTipData) |
|
|
|
svg.on('mouseout', function() { tip.style('visibility', 'hidden') }) |
|
} |
|
|
|
// make it so |
|
createGraph() |