Skip to content

Instantly share code, notes, and snippets.

@cartoda
Last active March 3, 2016 09:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cartoda/de0664ca59ff7277a12c to your computer and use it in GitHub Desktop.
Save cartoda/de0664ca59ff7277a12c to your computer and use it in GitHub Desktop.
Zoom and drag-and-drop with D3.js library

This example shows the use of the D3.js library to:

  • create simple objects and set the drag-and-drop on them
  • grouping all the objects and make both the zoom and moving effects on the entire draw
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Example of use of the D3.js library" />
<meta charset="utf-8">
<title>D3.js library example</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg id="map" width="960" height="450"></svg>
<br/>
<script>
var MAX_ZOOM_IN = 2.0;
var MAX_ZOOM_OUT = 0.2;
var zoomStep = 0.2;
var actualZoomLevel = 1.0;
var MOVE_STEP = 100;
var nodes, nodes_data, zoomable_layer, zoom;
var map = d3.select("#map")
.attr("width", 960)
.attr("height", 450);
var container = map.append("g");
//Get the background image from the server and set the viewport size
var mapImage = container.append("image")
.attr("xlink:href","http://wafi.iit.cnr.it/webvis/tmp/tiger.svg")
.attr("width", 960)
.attr("height", 450);
//Draw two circles and one rectangle
var circle1 = container.append("circle")
.attr("cx", 50)
.attr("cy", 50)
.attr("r", 50)
.style("fill", "#ff0")
.classed('draggable', true);
var circle2 = container.append("circle")
.attr("cx", 50)
.attr("cy", 50)
.attr("r", 50)
.style("fill", "#ae2")
.classed('draggable', true);
var rectangle = container.append("rect")
.attr("x", 50)
.attr("y", 50)
.attr("width", 100)
.attr("height", 50)
.attr("stroke", "#C1272D")
.attr("stroke-width", 5)
.style("fill", "#F7931E")
.classed('draggable', true);
//Create the zoom behavior to set for the draw
zoom = d3.behavior.zoom().scaleExtent([MAX_ZOOM_OUT, MAX_ZOOM_IN]).on('zoom', zoomed);
//Function called on the zoom event. It translate the draw on the zoommed point and scale with a certain factor
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
//Create the drag and drop behavior to set for the objects crated
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged);
//Called when drag event starts. It stop the propagation of the click event
function dragstarted(d){
d3.event.sourceEvent.stopPropagation();
}
//Called when the drag event occurs (object should be moved)
function dragged(d){
d.x = d3.event.x;
d.y = d3.event.y;
//Translate the object on the actual moved point
d3.select(this).attr({
transform: "translate(" + d.x + "," + d.y + ")"
});
}
//Set the zoom behavior on the container variable (the draw), disable mousedown event for the zoom and set the function to call on the double click event
container.call(zoom).on("mousedown.zoom", null).on("dblclick.zoom", zoomIn);
//Matrix containing the x and y coordinates of the created objects (used for draggable events)
nodes_data = [
{
x: 0,
y: 0
}, {
x: 0,
y: 0
}, {
x: 0,
y: 0
}
];
//Set the drag behavior on the objects having the "draggable" class and set their position on the viewport (by the "node_data" matrix)
nodes = container.selectAll(".draggable").call(drag).data(nodes_data);
function zoomIn(){
//Calculate and set the new zoom level
actualZoomLevel = roundFloat(parseFloat(actualZoomLevel) + parseFloat(zoomStep));
zoom.scale(actualZoomLevel);
//Get the actual position of the container
var xPosition = d3.transform(container.attr("transform")).translate[0];
var yPosition = d3.transform(container.attr("transform")).translate[1];
//Esecute the transformation setting the actual position and the new zoom level
container.attr("transform", "translate(" + xPosition + ", " + yPosition + ")scale(" + zoom.scale() + ")");
}
function zoomOut(){
actualZoomLevel = roundFloat(parseFloat(actualZoomLevel) - parseFloat(zoomStep));
zoom.scale(actualZoomLevel);
var xPosition = d3.transform(container.attr("transform")).translate[0];
var yPosition = d3.transform(container.attr("transform")).translate[1];
container.attr("transform", "translate(" + xPosition + ", " + yPosition + ")scale(" + zoom.scale() + ")");
}
function moveDrawLeft(){
var xPosition = d3.transform(container.attr("transform")).translate[0];
var yPosition = d3.transform(container.attr("transform")).translate[1];
container.attr("transform", "translate(" + (xPosition - MOVE_STEP) + ", " + yPosition + ")scale(" + zoom.scale() + ")");
}
function moveDrawRight(){
var xPosition = d3.transform(container.attr("transform")).translate[0];
var yPosition = d3.transform(container.attr("transform")).translate[1];
container.attr("transform", "translate(" + (xPosition + MOVE_STEP) + ", " + yPosition + ")scale(" + zoom.scale() + ")");
}
function moveDrawTop(){
var xPosition = d3.transform(container.attr("transform")).translate[0];
var yPosition = d3.transform(container.attr("transform")).translate[1];
container.attr("transform", "translate(" + xPosition + ", " + (yPosition - MOVE_STEP) + ")scale(" + zoom.scale() + ")");
}
function moveDrawBottom(){
var xPosition = d3.transform(container.attr("transform")).translate[0];
var yPosition = d3.transform(container.attr("transform")).translate[1];
container.attr("transform", "translate(" + xPosition + ", " +(yPosition + MOVE_STEP) + ")scale(" + zoom.scale() + ")");
}
function roundFloat(value){
return value.toFixed(2);
}
</script>
<br/>
<button id="zoomIn" onclick="zoomIn()">Zoom In</button>
<button id="zoomOut" onclick="zoomOut()">Zoom Out</button>
<button id="moveLeft" onclick="moveDrawLeft()">Move left</button>
<button id="moveRight" onclick="moveDrawRight()">Move right</button>
<button id="moveTop" onclick="moveDrawTop()">Move top</button>
<button id="moveBottom" onclick="moveDrawBottom()">Move bottom</button>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment