1 | var w = 960, |
---|
2 | h = 500, |
---|
3 | line = d3.svg.line(), |
---|
4 | points = d3.range(1, 5).map(function(i) { return [i * w / 5, 50 + Math.random() * (h - 100)]; }), |
---|
5 | dragged = null, |
---|
6 | selected = points[0]; |
---|
7 | |
---|
8 | var vis = d3.select("#chart").append("svg:svg") |
---|
9 | .attr("width", w) |
---|
10 | .attr("height", h); |
---|
11 | |
---|
12 | vis.append("svg:rect") |
---|
13 | .attr("width", w) |
---|
14 | .attr("height", h) |
---|
15 | .on("mousedown", function() { |
---|
16 | points.push(selected = dragged = d3.svg.mouse(vis.node())); |
---|
17 | update(); |
---|
18 | }); |
---|
19 | |
---|
20 | vis.append("svg:path") |
---|
21 | .data([points]) |
---|
22 | .attr("class", "line") |
---|
23 | .call(update); |
---|
24 | |
---|
25 | d3.select(window) |
---|
26 | .on("mousemove", mousemove) |
---|
27 | .on("mouseup", mouseup) |
---|
28 | .on("keydown", keydown); |
---|
29 | |
---|
30 | // Add interpolator dropdown |
---|
31 | d3.select("#interpolate") |
---|
32 | .on("change", function() { |
---|
33 | line.interpolate(this.value); |
---|
34 | update(); |
---|
35 | }) |
---|
36 | .selectAll("option") |
---|
37 | .data([ |
---|
38 | "linear", |
---|
39 | "step-before", |
---|
40 | "step-after", |
---|
41 | "basis", |
---|
42 | "basis-open", |
---|
43 | "basis-closed", |
---|
44 | "cardinal", |
---|
45 | "cardinal-open", |
---|
46 | "cardinal-closed", |
---|
47 | "monotone" |
---|
48 | ]) |
---|
49 | .enter().append("option") |
---|
50 | .attr("value", String) |
---|
51 | .text(String); |
---|
52 | |
---|
53 | function update() { |
---|
54 | vis.select("path").attr("d", line); |
---|
55 | |
---|
56 | var circle = vis.selectAll("circle") |
---|
57 | .data(points, function(d) { return d; }); |
---|
58 | |
---|
59 | circle.enter().append("svg:circle") |
---|
60 | .attr("class", function(d) { return d === selected ? "selected" : null; }) |
---|
61 | .attr("cx", function(d) { return d[0]; }) |
---|
62 | .attr("cy", function(d) { return d[1]; }) |
---|
63 | .attr("r", 1e-6) |
---|
64 | .on("mousedown", function(d) { |
---|
65 | selected = dragged = d; |
---|
66 | update(); |
---|
67 | }) |
---|
68 | .transition() |
---|
69 | .duration(750) |
---|
70 | .ease("elastic") |
---|
71 | .attr("r", 6.5); |
---|
72 | |
---|
73 | circle |
---|
74 | .attr("class", function(d) { return d === selected ? "selected" : null; }) |
---|
75 | .attr("cx", function(d) { return d[0]; }) |
---|
76 | .attr("cy", function(d) { return d[1]; }); |
---|
77 | |
---|
78 | circle.exit().remove(); |
---|
79 | |
---|
80 | if (d3.event) { |
---|
81 | d3.event.preventDefault(); |
---|
82 | d3.event.stopPropagation(); |
---|
83 | } |
---|
84 | } |
---|
85 | |
---|
86 | |
---|
87 | function mousemove() { |
---|
88 | if (!dragged) return; |
---|
89 | var m = d3.svg.mouse(vis.node()); |
---|
90 | dragged[0] = Math.max(0, Math.min(w, m[0])); |
---|
91 | dragged[1] = Math.max(0, Math.min(h, m[1])); |
---|
92 | update(); |
---|
93 | } |
---|
94 | |
---|
95 | function mouseup() { |
---|
96 | if (!dragged) return; |
---|
97 | mousemove(); |
---|
98 | dragged = null; |
---|
99 | } |
---|
100 | |
---|
101 | function keydown() { |
---|
102 | if (!selected) return; |
---|
103 | switch (d3.event.keyCode) { |
---|
104 | case 8: // backspace |
---|
105 | case 46: { // delete |
---|
106 | var i = points.indexOf(selected); |
---|
107 | points.splice(i, 1); |
---|
108 | selected = points.length ? points[i > 0 ? i - 1 : 0] : null; |
---|
109 | update(); |
---|
110 | break; |
---|
111 | } |
---|
112 | } |
---|
113 | } |
---|