Panels in Protovis support simple geometric transformations natively, allowing panning and zooming when coupled with the corresponding behaviors. Drag with the mouse to pan, and use the mousewheel to zoom, in the above scatterplot. This example uses the native transforms to update the scales’ domains dynamically.
Next: Brush + Link
<html>
<head>
<title>Pan + Zoom</title>
<link type="text/css" rel="stylesheet" href="ex.css?3.2"/>
<script type="text/javascript" src="../protovis-r3.2.js"></script>
<script type="text/javascript" src="transform.js"></script>
<style type="text/css">
#fig {
width: 860px;
height: 550px;
}
</style>
</head>
<body>
<script type="text/javascript+protovis">
/* Sizing parameters and scales. */
var w = 800,
h = 500,
kx = w / h,
ky = 1,
x = pv.Scale.linear(-kx, kx).range(0, w),
y = pv.Scale.linear(-ky, ky).range(0, h);
/* The root panel. */
var vis = new pv.Panel()
.width(w)
.height(h)
.top(30)
.left(40)
.right(20)
.bottom(20)
.strokeStyle("#aaa");
/* X-axis and ticks. */
vis.add(pv.Rule)
.data(function() x.ticks())
.strokeStyle(function(d) d ? "#ccc" : "#999")
.left(x)
.anchor("bottom").add(pv.Label)
.text(x.tickFormat);
/* Y-axis and ticks. */
vis.add(pv.Rule)
.data(function() y.ticks())
.strokeStyle(function(d) d ? "#ccc" : "#999")
.top(y)
.anchor("left").add(pv.Label)
.text(y.tickFormat);
/* The dot plot. */
vis.add(pv.Panel)
.overflow("hidden")
.add(pv.Dot)
.data(data)
.left(function(d) x(d.x))
.top(function(d) y(d.y))
.fillStyle(pv.rgb(121, 173, 210, .5))
.radius(function() 5 / this.scale);
/* Use an invisible panel to capture pan & zoom events. */
vis.add(pv.Panel)
.events("all")
.event("mousedown", pv.Behavior.pan())
.event("mousewheel", pv.Behavior.zoom())
.event("pan", transform)
.event("zoom", transform);
/** Update the x- and y-scale domains per the new transform. */
function transform() {
var t = this.transform().invert();
x.domain(t.x / w * 2 * kx - kx, (t.k + t.x / w) * 2 * kx - kx);
y.domain(t.y / h * 2 * ky - ky, (t.k + t.y / h) * 2 * ky - ky);
vis.render();
}
vis.render();
</script>
</body>
</html>
var data = pv.range(100).map(function(i) {
var r = .5 + .2 * Math.random(), a = Math.PI * i / 50;
return {x: r * Math.cos(a), y: r * Math.sin(a)};
});