Skip to content

Instantly share code, notes, and snippets.

@puzzler10
Last active April 18, 2017 22:32
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save puzzler10/49f13307e818ea9a909ba5adba5b6ed9 to your computer and use it in GitHub Desktop.
d3v4 - zoom and drag circles - drag adjusted for zoom

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.

<!DOCTYPE html>
<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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment