[76] | 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 | } |
---|