Reputation: 4427
I would like to use zoom behaviour in a simple d3 graph. The thing is that whenever I zoom in, the "main" group elements take up the whole svg space, which causes other existing elements such as axes and texts to get overlapped. I have read that clipping can be used to solve this problem but I didn't manage to get it working properly.
The following image (zoom in was applied) shows the problem:
Related example with what I have tried so far can be found here.
Upvotes: 0
Views: 1271
Reputation: 4427
I was finally able to solve this problem. Key points were:
rect
does the job with corresponding width/height (same as your "drawing" area).In code (omitting irrelevant parts), the result is:
// Scales, axis, etc.
...
// Zoom behaviour & event handler
let zoomed = function () {
let e = d3.event;
let tx = Math.min(0, Math.max(e.translate[0], width - width*e.scale));
let ty = Math.min(0, Math.max(e.translate[1], height - height*e.scale));
zoom.translate([tx,ty]);
main.selectAll('.circle').attr('transform', 'translate(' + [tx,ty] + ')scale(' + e.scale + ')');
svg.select('.x.axis').call(xAxis);
svg.select('.y.axis').call(yAxis);
}
let zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1,8])
.on('zoom', zoomed);
const svg = d3.select('body').append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.attr('pointer-events', 'all')
.call(zoom);
const g = svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Set clip region, rect with same width/height as "drawing" area, where we will be able to zoom in
g.append('defs')
.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
const main = g.append('g')
.attr('class', 'main')
.attr('clip-path', 'url(#clip)');
let circles = main.selectAll('.circle').data(data).enter();
Upvotes: 2