An example of setting x- and y-scale domains (zooming) by selecting a
rectangular region using the mouse. The original question required that it
work in tandem with d3.behavior.zoom
for panning, hence the checkbox for
switching on the “zoom by rectangle” mode.
forked from jasondavies's block: Zoom by Rectangle
xxxxxxxxxx
<meta charset="utf-8">
<title>Zoom by Rectangle</title>
<script src="https://d3js.org/d3.v2.min.js?2.10.1"></script>
<style>
body {
font-family: sans-serif;
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
svg {
font: 10px sans-serif;
shape-rendering: crispEdges;
}
rect {
fill: #ddd;
}
rect.zoom {
stroke: steelblue;
fill-opacity: 0.5;
}
.axis path, .axis line {
fill: none;
stroke: #fff;
}
</style>
<p><label for="zoom-rect"><input type="checkbox" id="zoom-rect"> zoom by rectangle</label>
<script>
var margin = {top: 0, right: 12, bottom: 12, left: 36},
width = 960 - margin.left - margin.right,
height = 430 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([-width / 2, width / 2])
.range([0, width]);
var y = d3.scale.linear()
.domain([-height / 2, height / 2])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickSize(-width);
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.on("zoom", refresh);
var zoomRect = false;
d3.select("#zoom-rect").on("change", function() {
zoomRect = this.checked;
});
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom)
.append("g")
.on("mousedown", function() {
if (!zoomRect) return;
var e = this,
origin = d3.mouse(e),
rect = svg.append("rect").attr("class", "zoom");
d3.select("body").classed("noselect", true);
origin[0] = Math.max(0, Math.min(width, origin[0]));
origin[1] = Math.max(0, Math.min(height, origin[1]));
d3.select(window)
.on("mousemove.zoomRect", function() {
var m = d3.mouse(e);
m[0] = Math.max(0, Math.min(width, m[0]));
m[1] = Math.max(0, Math.min(height, m[1]));
rect.attr("x", Math.min(origin[0], m[0]))
.attr("y", Math.min(origin[1], m[1]))
.attr("width", Math.abs(m[0] - origin[0]))
.attr("height", Math.abs(m[1] - origin[1]));
})
.on("mouseup.zoomRect", function() {
d3.select(window).on("mousemove.zoomRect", null).on("mouseup.zoomRect", null);
d3.select("body").classed("noselect", false);
var m = d3.mouse(e);
m[0] = Math.max(0, Math.min(width, m[0]));
m[1] = Math.max(0, Math.min(height, m[1]));
if (m[0] !== origin[0] && m[1] !== origin[1]) {
zoom.x(x.domain([origin[0], m[0]].map(x.invert).sort()))
.y(y.domain([origin[1], m[1]].map(y.invert).sort()));
}
rect.remove();
refresh();
}, true);
d3.event.stopPropagation();
});
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
function refresh() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
}
</script>
Modified http://d3js.org/d3.v2.min.js?2.10.1 to a secure url
https://d3js.org/d3.v2.min.js?2.10.1