d3 zoom not centering on mouse position with radial tree
var dragListener = d3.behavior.drag()
.on("drag", function() {
dragX = d3.event.dx;
dragY = d3.event.dy;
});
mainSvg.call(dragListener);
var dragging = 0;
var dragX = 0, dragY = 0;
dragListener.on("dragstart", function() {
dragging = 1;
});
dragListener.on("dragend", function() {
dragging = 0;
dragX = 0;
dragY = 0;
});
function zoomHandler() {
var pos = d3.mouse(this);
var scale = d3.event.scale;
var trans = d3.transform(childGroupZoom.attr("transform"));
var tpos = trans.translate;
var tscale = trans.scale;
var tx = tpos[0];
var ty = tpos[1];
var mx = pos[0] - w/2;
var my = pos[1] - h/2;
var dx = (mx - tx - dragX)/tscale[0];
var dy = (my - ty - dragY)/tscale[1];
var dx2 = (mx - dx)/scale - dx;
var dy2 = (my - dy)/scale - dy;
var tform = "translate(" + dx + "," + dy + ")scale(" + scale + ")translate(" + dx2 + "," + dy2 + ")"
childGroupZoom.attr("transform", tform);
}
var w = 1200;
var h = 1000;
var data = [{
'parent_id': '1',
'items_count': '2'
}, {
'parent_id': '2',
'items_count': '4'
}, {
'parent_id': '3',
'items_count': '3'
}, {
'parent_id': '4',
'items_count': '2'
}, {
'parent_id': '5',
'items_count': '1'
}, {
'parent_id': '6',
'items_count': '6'
}, {
'parent_id': '7',
'items_count': '2'
}, {
'parent_id': '8',
'items_count': '4'
}, {
'parent_id': '9',
'items_count': '5'
}, {
'parent_id': '10',
'items_count': '7'
}];
var treeRadius = 300;
var searchCircleRadius = 60;
var circleRadiusScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) {
return d.items_count;
})])
.range([10, 40]);
var dataTree = {
children: data.map(function(d) {
return {
parent_id: d.parent_id,
items_count: d.items_count
};
})
};
var tree = d3.layout.tree()
.size([360, treeRadius]);
var mainSvg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var svg = mainSvg
.append("g")
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
var childGroupZoom = svg.append("g");
var zoomListener = d3.behavior.zoom()
.scaleExtent([0.1, 1.75])
.on("zoom", zoomHandler);
zoomListener(mainSvg);
var nodes = tree.nodes(dataTree);
var basicNode = childGroupZoom.selectAll(".node");
var node = basicNode
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "rotate(" + (d.x - 90) + ") translate(" + d.y + ")";
});
var outlineCircles = node.append("circle")
.attr("r", function(d, i) {
if (i < 1) {
return searchCircleRadius;
} else {
return circleRadiusScale(d.items_count);
}
})
.attr("stroke", "#0099FF")
.attr("stroke-width", "3")
.attr("transform", function(d) {
return "rotate(" + (-d.x + 90) + ")";
});
var dragListener = d3.behavior.drag()
.on("drag", function() {
dragX = d3.event.dx;
dragY = d3.event.dy;
});
mainSvg.call(dragListener);
var dragging = 0;
var dragX = 0,
dragY = 0;
dragListener.on("dragstart", function() {
dragging = 1;
});
dragListener.on("dragend", function() {
dragging = 0;
dragX = 0;
dragY = 0;
});
function zoomHandler() {
var pos = d3.mouse(this);
var scale = d3.event.scale;
var trans = d3.transform(childGroupZoom.attr("transform"));
var tpos = trans.translate;
var tscale = trans.scale;
var tx = tpos[0];
var ty = tpos[1];
var mx = pos[0] - w / 2;
var my = pos[1] - h / 2;
var dx = (mx - tx - dragX) / tscale[0];
var dy = (my - ty - dragY) / tscale[1];
var dx2 = (mx - dx) / scale - dx;
var dy2 = (my - dy) / scale - dy;
var tform = "translate(" + dx + "," + dy + ")scale(" + scale + ")translate(" + dx2 + "," + dy2 + ")"
childGroupZoom.attr("transform", tform);
}
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
</body>
</html>
Note: The zoom handler is also being called by the framework on drag operations which is facilitating object movement by virtue of dragX and dragY.