Reputation: 6196
This is my current code
<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoom by Rectangle</title>
<script src="http://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>
<script>
var margin = {
top : 20,
right : 20,
bottom : 30,
left : 40
}, width = 960 - margin.left - margin.right, height = 500 - margin.top
- margin.bottom;
var x = d3.scale.linear().range([ 0, width ]);
var y = d3.scale.linear().range([ height, 0 ]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var zoom = d3.behavior.zoom().x(x).y(y).on("zoom", refresh);
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() {
console.log("Mouse down");
var e = this;
var origin = d3.mouse(e);
var 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() {
console.log("Mouse moving");
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]));
console.log(m[0]);
console.log(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() {
console.log("Mouse up");
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();
});
var data = [ {
"x" : 30,
"y" : 30,
"r" : 20,
"c" : "green",
"s" : "s1"
}, {
"x" : 70,
"y" : 70,
"r" : 20,
"c" : "purple",
"s" : "s2"
}, {
"x" : 110,
"y" : 100,
"r" : 20,
"c" : "red",
"s" : "s3"
} ];
var data1 = [ {
"x" : 30,
"y" : 30
}, {
"x" : 70,
"y" : 70
}, {
"x" : 90,
"y" :90
} ];
x.domain(d3.extent(data, function(d) {
return d.x;
})).nice();
y.domain(d3.extent(data, function(d) {
return d.y;
})).nice();
svg.append("rect").attr("width", width).attr("height", height);
svg.append("g").attr("class", "x axis").attr("transform",
"translate(0," + height + ")").call(xAxis).append("text").attr(
"class", "label").attr("x", width).attr("y", -6).style(
"text-anchor", "end").text("Yield");
svg.append("g").attr("class", "y axis").call(yAxis).append("text")
.attr("class", "label").attr("transform", "rotate(-90)").attr(
"y", 6).attr("dy", ".71em").style("text-anchor", "end")
.text("Skew")
var line = d3.svg.line().x(function(d) {
return x(d.x);
}).y(function(d) {
return y(d.y);
});
svg.append("path").datum(data1).attr("class", "line").attr("stroke",
"steelblue").attr("stroke-width", 1.5).attr("d", line).attr(
"fill", "none");
svg.selectAll(".dot").data(data).enter().append("circle").attr("class",
"dot").attr("r", 3.5).attr("cx", function(d) {
return x(d.x);
}).attr("cy", function(d) {
return y(d.y);
}).style("fill", function(d) {
return color(d.c);
});
var legend = svg.selectAll(".legend").data(color.domain()).enter()
.append("g").attr("class", "legend").attr("transform",
function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect").attr("x", width - 18).attr("width", 18).attr(
"height", 18).style("fill", color);
legend.append("text").attr("x", width - 24).attr("y", 9).attr("dy",
".35em").style("text-anchor", "end").text(function(d) {
return d;
});
function refresh() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
}
</script>
The issue is when zoom in with the mouse, the x axis and y axis get updated with the zoomed in range but the actual data is not zooming, looks like i am missing something in the refresh method but i have no clue. ( still learning d3 )
Upvotes: 0
Views: 1177
Reputation: 58662
I have done Zoom few days back, and also assumed I just needed to update the axis and the zoom will applied to the entire visualization. But, that wasn't the case. You have to explicitly call the rendering (where you draw the rectangles) again. Then, to prevent it adding duplicate rectangles, you have to handle update
and exit
sections correctly. I saw you are not using it. Please search for tutorials on enter, update, exit sections. Also, there are tutorials on D3 Wiki (about updating barchart etc). Good luck.
Upvotes: 1