Example of zoom and drag in d3 v4.
This example has a modified drag function so that when you zoom in, you're still able to drag the circles to the correct mouse location. Here's an example of the drag problem.
It's not an easy way to do this task. Read this for an easier and better way, as well as an explanation of this code.
xxxxxxxxxx
<meta charset="utf-8">
<style>
</style>
<svg width="800" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
//used to capture drag position
var start_x, start_y;
//create some circles at random points on the screen
//create 50 circles of radius 20
//specify centre points randomly through the map function
var radius = 20;
var circle_data = d3.range(50).map(function() {
return{
x : Math.round(Math.random() * (width - radius*2 ) + radius),
y : Math.round(Math.random() * (height - radius*2 ) + radius)
};
});
//stylish black rectangle for sexy looks
var rect = svg.append("g")
.attr("class", "rect")
.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "black")
;
//funky yellow circles
var circles = d3.select("svg")
.append("g")
.attr("class", "circles")
.selectAll("circle")
.data(circle_data)
.enter()
.append("circle")
.attr("cx", function(d) {return(d.x)})
.attr("cy", function(d) {return(d.y)})
.attr("r", radius)
.attr("fill", "yellow");
/*
* DRAG BEHAVIOUR
*/
//create drag handler with d3.drag()
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag);
function drag_start(){
// get starting location of the drag
// used to offset the circle
start_x = +d3.event.x;
start_y = +d3.event.y;
}
function drag_drag(d) {
//Get the current scale of the circle
//case where we haven't scaled the circle yet
if (this.getAttribute("transform") === null)
{
current_scale = 1;
}
//case where we have transformed the circle
else {
current_scale_string = this.getAttribute("transform").split(' ')[1];
current_scale = +current_scale_string.substring(6,current_scale_string.length-1);
}
d3.select(this)
.attr("cx", d.x = start_x + ((d3.event.x - start_x) / current_scale) )
.attr("cy", d.y = start_y + ((d3.event.y - start_y) / current_scale));
}
//apply the drag_handler to our circles
drag_handler(circles);
/*
* ZOOM BEHAVIOUR
*/
//create zoom handler
var zoom_handler = d3.zoom()
.on("zoom", zoom_actions);
//specify what to do when zoom event listener is triggered
function zoom_actions(){
circles.attr("transform", d3.event.transform);
}
//add zoom behaviour to the svg element backing our graph.
//same thing as svg.call(zoom_handler);
zoom_handler(svg);
</script>
https://d3js.org/d3.v4.min.js