Tangent to a graph
by dm89
HTML
<body>
<figure id="graph"></figure>
CSS
#line path {
stroke: black;
fill: none;
}
#line path.overlay {
stroke: white;
stroke-opacity: 0;
stroke-width: 10;
fill: none;
}
#tangent {
stroke: red;
stroke-width: 2;
}
}
JavaScript
// compute data
function f(x) {
return x * x;
};
var X_MIN = -5,
X_MAX = 5,
data = [];
for (var x = X_MIN; x <= X_MAX; x = x + 0.01) {
data.push({
x: x,
y: f(x)
});
};
// set up graph environment
var WIDTH = 500,
HEIGHT = 350;
var svg = d3.select('#graph')
.append('svg')
.attr('width', WIDTH)
.attr('height', HEIGHT);
// the x and y scales
var x_scale = d3.scale.linear()
.range([10, WIDTH - 10])
.domain([X_MIN, X_MAX])
var y_scale = d3.scale.linear()
.range([HEIGHT - 10, 10])
.domain([0, f(X_MAX)]);
// make a graph line
var line = d3.svg.line()
.x(function (d) {
return x_scale(d.x);
})
.y(function (d) {
return y_scale(d.y);
})
.interpolate('cardinal')
.tension(0);
// draw it
var g = svg.append('g')
.attr('id', 'line')
g.append('path')
.attr('d', line(data));
// make a transparant overlay to capture mousemovements
g.append('path')
.classed('overlay', true)
.attr('d', line(data))
.on('mouseover', function () {
var line_path = d3.select('#line path.overlay')[0][0];
var length_at_point = 0,
total_length = line_path.getTotalLength(),
mouse = d3.mouse(line_path);
// find point on the line to draw tangent on,
var INTERVAL = 100;
while (line_path.getPointAtLength(length_at_point).x < mouse[0] && length_at_point < total_length)
length_at_point += INTERVAL
length_at_point -= INTERVAL
while (line_path.getPointAtLength(length_at_point).x < mouse[0] && length_at_point < total_length) {
length_at_point++;
};
var point = line_path.getPointAtLength(length_at_point),
prev = {},
next = {},
delta = {};
if (length_at_point > 1 && length_at_point < (total_length - 1)) {
prev = line_path.getPointAtLength(length_at_point - 1);
next = line_path.getPointAtLength(length_at_point + 1);
delta = {
x: next.x - prev.x,
y:...