Skip to content

Instantly share code, notes, and snippets.

@sampathweb
Last active September 19, 2016 18:27
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 sampathweb/842d0945d9002ade5fd62457357318e3 to your computer and use it in GitHub Desktop.
Save sampathweb/842d0945d9002ade5fd62457357318e3 to your computer and use it in GitHub Desktop.
HR_alarm
license: mit

This example is the second of three in the Path Transitions tutorial; see the previous example for context.

The desired pairing of numbers for path interpolation is like this:

M x0, y0 L x1, y1 L x2, y2 L x3, y3 L xR, y4
   ↓   ↓    ↓   ↓    ↓   ↓    ↓   ↓
M xl, y0 L x0, y1 L x1, y2 L x2, y3 L x3, y4

Where xl is some negative value off the left side, and xr is some positive value off the right side. This way, the first point ⟨x0,y0⟩ is interpolated to ⟨xl,y0⟩; meaning, the x-coordinate is interpolated rather than the y-coordinate, and so the path appears to slide off to the left. Likewise, the incoming point ⟨xr,y4⟩ is interpolated to ⟨x3,y4⟩.

While you could write a custom interpolator and use transition.attrTween to achieve this, a much simpler solution is to interpolate the transform attribute rather than the path. This way, the shape of the path remains static while the it translates left during the transition.

Immediately prior to the transition, the path is redrawn as follows:

M x0, y0 L x1, y1 L x2, y2 L x3, y3 L xr, y4

Then, a transform transition is applied:

translate(0,0)
          ↓
translate(xl,0)

This causes the path to slide left. A clip path is used so the path is not visible outside of the chart body.

Note that for charts with spline interpolation, you’ll need to crop the visible part of the line by an extra point, so that the change in tangent is not visible; see the next example.

forked from mbostock's block: HR_alarm

forked from anonymous's block: HR_alarm

forked from ssaleh2's block: HR_alarm

Time Heart_Rate
0 2200.0 74.0
1 2202.0 74.0
2 2204.0 73.0
3 2206.0 72.0
4 2208.0 72.0
5 2210.0 72.0
6 2212.0 72.0
7 2214.0 72.0
8 2216.0 72.0
9 2218.0 81.0
10 2220.0 80.0
11 2222.0 79.0
12 2224.0 74.0
13 2226.0 69.0
14 2228.0 69.0
15 2230.0 69.0
16 2232.0 69.0
17 2234.0 69.0
18 2236.0 70.0
19 2238.0 70.0
20 2240.0 70.0
21 2242.0 70.0
22 2244.0 71.0
23 2246.0 72.0
24 2248.0 73.0
25 2250.0 73.0
26 2252.0 74.0
27 2254.0 74.0
28 2256.0 75.0
29 2258.0 75.0
30 2260.0 74.0
31 2262.0 74.0
32 2264.0 74.0
33 2266.0 65.0
34 2268.0 53.0
35 2270.0 53.0
36 2272.0 48.0
37 2274.0 42.0
38 2276.0 42.0
39 2278.0 45.0
40 2280.0 45.0
41 2282.0 60.0
42 2284.0 60.0
43 2286.0 75.0
44 2288.0 75.0
45 2290.0 75.0
46 2292.0 75.0
47 2294.0 75.0
48 2296.0 75.0
49 2298.0 75.0
50 2300.0 75.0
51 2302.0 75.0
52 2304.0 75.0
53 2306.0 75.0
54 2308.0 75.0
55 2310.0 75.0
56 2312.0 75.0
57 2314.0 75.0
58 2316.0 76.0
59 2318.0 76.0
60 2320.0 76.0
61 2322.0 75.0
62 2324.0 67.0
63 2326.0 67.0
64 2328.0 67.0
65 2330.0 61.0
66 2332.0 51.0
67 2334.0 47.0
68 2336.0 47.0
69 2338.0 51.0
70 2340.0 57.0
71 2342.0 87.0
72 2344.0 87.0
73 2346.0 90.0
74 2348.0 90.0
75 2350.0 100.0
76 2352.0 84.0
77 2354.0 73.0
78 2356.0 73.0
79 2358.0 81.0
80 2360.0 78.0
81 2362.0 77.0
82 2364.0 70.0
83 2366.0 69.0
84 2368.0 70.0
85 2370.0 71.0
86 2372.0 74.0
87 2374.0 77.0
88 2376.0 74.0
89 2378.0 80.0
90 2380.0 79.0
91 2382.0 78.0
92 2384.0 78.0
93 2386.0 88.0
94 2388.0 83.0
95 2390.0 77.0
96 2392.0 87.0
97 2394.0 86.0
98 2396.0 86.0
99 2398.0 75.0
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.line {
fill: none;
stroke: #1ED760;
stroke-width: 2.5px;
shape-rendering: crispEdges;
}
</style>
<svg width="960" height="480"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
//var n = 40,
//random = d3.randomNormal(100, 150),
//data = d3.range(n).map(random);
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 20, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleLinear()
// .domain([1, n - 2])
.range([0, width]);
var y = d3.scaleLinear()
//.domain([20, 180])
.range([height, 0]);
var maxIndex = 10;
var minIndex = 0;
var fullData;
var subset;
d3.csv("data.csv", function(error, data) {
if (error) throw error;
fullData = data;
data.forEach(function(d) {
d.index = +d.index;
d.Time = +d.Time;
d.Heart_Rate = +d.Heart_Rate;
});
subset = data.slice(minIndex, maxIndex);
console.log(subset);
x.domain(d3.extent(subset, function(d) { return d.Time; })).nice();
y.domain([0, d3.max(data, function(d) {return d.Heart_Rate; })]).nice();
var line = d3.line()
.curve(d3.curveBasis)
.x(function(d, i) { return x(d.Time); })
.y(function(d, i) { return y(d.Heart_Rate); });
console.log(line)
// var alarm_top = d3.line()
// .x(function(d, i) { return x(i+10); })
// .y(function(d, i) { return y(d+10); });
// var alarm_bottom = d3.line()
// .x(function(d, i) { return x(i+10); })
// .y(function(d, i) { return y(d+10); });
g.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y));
g.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.datum(subset)
.attr("class", "line")
.attr("d", line)
.transition()
.duration(500)
.ease(d3.easeLinear)
.on("start", tick);
//console.log(data.Time)
//console.log(data)
//console.log("you are now rocking with d3", d3);
function tick() {
// Push a new data point onto the back.
// subset.pop();
// subset.push(fullData.slice(maxIndex, maxIndex+1));
subset.push(fullData.slice(maxIndex, maxIndex+1)[0])
maxIndex += 1;
console.log(subset);
// Redraw the line.
d3.select(this)
.attr("d", line)
.attr("transform", null);
// Slide it to the left.
d3.active(this)
.attr("transform", function(d) { return "translate(" + x(d.Time) + ",0)"})
.transition()
.on("start", tick);
// Pop the old data point off the front.
subset.shift();
x.domain(d3.extent(subset, function(d) { return d.Time; })).nice();
d3.select("g.axis--x")
.transition()
.call(d3.axisBottom(x));
}
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment