163 строки
3.6 KiB
HTML
163 строки
3.6 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
|
<title>Zoom</title>
|
|
<script type="text/javascript" src="../../d3.js"></script>
|
|
<script type="text/javascript" src="../../d3.csv.js"></script>
|
|
<script type="text/javascript" src="../../d3.time.js"></script>
|
|
<style type="text/css">
|
|
|
|
path {
|
|
fill: steelblue;
|
|
}
|
|
|
|
line {
|
|
stroke: #000;
|
|
shape-rendering: crispEdges;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<script type="text/javascript">
|
|
|
|
var w = 960,
|
|
h1 = 400,
|
|
h2 = 40,
|
|
p = 20,
|
|
x0, // start of focus region
|
|
x1, // end of focus region
|
|
xx, // drag state
|
|
time = d3.time.format("%Y-%m-%d"),
|
|
x = d3.scale.linear().range([0, w]),
|
|
y1 = d3.scale.linear().range([h1 - p, 0]),
|
|
y2 = d3.scale.linear().range([h2, 0]);
|
|
|
|
var svg = d3.select("body")
|
|
.append("svg:svg")
|
|
.attr("width", w)
|
|
.attr("height", h1 + h2);
|
|
|
|
// Focus view.
|
|
var focus = svg.append("svg:g");
|
|
|
|
// Context view.
|
|
var context = svg.append("svg:g")
|
|
.attr("transform", "translate(0," + h1 + ")");
|
|
|
|
d3.csv("dji.csv", function(csv) {
|
|
var minX,
|
|
maxX,
|
|
maxY = -Infinity;
|
|
|
|
// Compute x- and y-extent.
|
|
csv.reverse();
|
|
for (var i = 0, n = csv.length, o; i < n; i++) {
|
|
o = csv[i];
|
|
o = csv[i] = {x: +time.parse(o.Date), y: +o.Close};
|
|
if (o.y > maxY) maxY = o.y;
|
|
}
|
|
minX = csv[0].x;
|
|
maxX = csv[n - 1].x;
|
|
|
|
// Update x- and y-scales.
|
|
x.domain([minX, maxX]);
|
|
y1.domain([0, maxY]);
|
|
y2.domain([0, maxY]);
|
|
|
|
// Focus view.
|
|
focus.append("svg:path")
|
|
.data([csv])
|
|
.attr("d", d3.svg.area()
|
|
.x(function(d) { return x(d.x); })
|
|
.y0(y1(0))
|
|
.y1(function(d) { return y1(d.y); }));
|
|
|
|
focus.append("svg:line")
|
|
.attr("x1", 0)
|
|
.attr("x2", w)
|
|
.attr("y1", y1(0))
|
|
.attr("y2", y1(0));
|
|
|
|
// Context view.
|
|
context.append("svg:rect")
|
|
.attr("width", w)
|
|
.attr("height", h2)
|
|
.attr("fill", "none")
|
|
.attr("pointer-events", "all")
|
|
.attr("cursor", "crosshair")
|
|
.on("mousedown", mousedown);
|
|
|
|
context.append("svg:path")
|
|
.data([csv])
|
|
.attr("pointer-events", "none")
|
|
.attr("d", d3.svg.area()
|
|
.x(function(d) { return x(d.x); })
|
|
.y0(y2(0))
|
|
.y1(function(d) { return y2(d.y); }));
|
|
|
|
context.append("svg:line")
|
|
.attr("x1", 0)
|
|
.attr("x2", w)
|
|
.attr("y1", y2(0))
|
|
.attr("y2", y2(0));
|
|
|
|
// Active focus region.
|
|
active = context.append("svg:rect")
|
|
.attr("pointer-events", "none")
|
|
.attr("id", "active")
|
|
.attr("x", x(x0 = minX))
|
|
.attr("y", 0)
|
|
.attr("height", h2)
|
|
.attr("width", x(x1 = (minX + 1e11)) - x(x0))
|
|
.attr("fill", "lightcoral")
|
|
.attr("fill-opacity", .5);
|
|
});
|
|
|
|
d3.select(window)
|
|
.on("mousemove", mousemove)
|
|
.on("mouseup", mouseup);
|
|
|
|
function mousedown() {
|
|
xx = x.invert(d3.svg.mouse(this)[0]);
|
|
}
|
|
|
|
function mousemove() {
|
|
if (xx != null) {
|
|
|
|
// Compute the new (clamped) focus region.
|
|
var xy = x.invert(d3.svg.mouse(active[0][0])[0]);
|
|
if (xx < xy) { x0 = xx; x1 = xy; }
|
|
else if (xx > xy) { x0 = xy; x1 = xx; }
|
|
else return;
|
|
x0 = Math.max(x.domain()[0], x0);
|
|
x1 = Math.min(x.domain()[1], x1);
|
|
|
|
// Update the x-scale. TODO Recycle this scale?
|
|
var tx = d3.scale.linear()
|
|
.domain([x0, x1])
|
|
.range([0, w]);
|
|
|
|
// Recompute the focus path.
|
|
focus.select("path")
|
|
.attr("d", d3.svg.area()
|
|
.x(function(d) { return tx(d.x); })
|
|
.y0(y1(0))
|
|
.y1(function(d) { return y1(d.y); }));
|
|
|
|
// Reposition the active region rect.
|
|
active
|
|
.attr("x", x(x0))
|
|
.attr("width", x(x1) - x(x0));
|
|
}
|
|
}
|
|
|
|
function mouseup() {
|
|
xx = null;
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|