Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nitaku/9cba6c39cc335725f09f to your computer and use it in GitHub Desktop.
Save nitaku/9cba6c39cc335725f09f to your computer and use it in GitHub Desktop.
Zoom + drag

This example combines the previous two about zooming and dragging. Care must be taken on avoiding the unwanted propagation of drag events from shapes to the whole SVG.

# data
nodes_data = [
{x: 0, y: 0},
{x: 80, y: 80},
{x: -80, y: 80},
{x: -80, y: -80},
{x: 80, y: -80}
]
svg = d3.select('svg')
width = svg.node().getBoundingClientRect().width
height = svg.node().getBoundingClientRect().height
# translate the viewBox to have (0,0) at the center of the vis
svg
.attr
viewBox: "#{-width/2} #{-height/2} #{width} #{height}"
# append a group for zoomable content
zoomable_layer = svg.append('g')
# define a zoom behavior
zoom = d3.behavior.zoom()
.scaleExtent([0.5,4]) # min-max zoom
.on 'zoom', () ->
# GEOMETRIC ZOOM
zoomable_layer
.attr
transform: "translate(#{zoom.translate()})scale(#{zoom.scale()})"
# bind the zoom behavior to the main SVG
svg.call(zoom)
# define a drag behavior
drag = d3.behavior.drag()
.origin((d) -> d)
drag.on 'dragstart', () ->
# silence other listeners (disbale pan when dragging)
# see https://github.com/mbostock/d3/wiki/Drag-Behavior
d3.event.sourceEvent.stopPropagation()
drag.on 'drag', (d) ->
# update the datum of the dragged node
d.x = d3.event.x
d.y = d3.event.y
# translate the representation
d3.select(this)
.attr
transform: "translate(#{d.x},#{d.y})"
# add draggable nodes
nodes = zoomable_layer.selectAll('.node')
.data(nodes_data)
nodes.enter().append('circle')
.call(drag) # enable dragging for nodes
.attr
class: 'node'
r: 20
fill: 'orange'
transform: (d) -> "translate(#{d.x},#{d.y})"
svg {
background: white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="Zoom + drag" />
<title>Zoom + drag</title>
<link type="text/css" href="index.css" rel="stylesheet"/>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg height="500" width="960"></svg>
<script src="index.js"></script>
</body>
</html>
(function() {
var drag, height, nodes, nodes_data, svg, width, zoom, zoomable_layer;
nodes_data = [
{
x: 0,
y: 0
}, {
x: 80,
y: 80
}, {
x: -80,
y: 80
}, {
x: -80,
y: -80
}, {
x: 80,
y: -80
}
];
svg = d3.select('svg');
width = svg.node().getBoundingClientRect().width;
height = svg.node().getBoundingClientRect().height;
svg.attr({
viewBox: "" + (-width / 2) + " " + (-height / 2) + " " + width + " " + height
});
zoomable_layer = svg.append('g');
zoom = d3.behavior.zoom().scaleExtent([0.5, 4]).on('zoom', function() {
return zoomable_layer.attr({
transform: "translate(" + (zoom.translate()) + ")scale(" + (zoom.scale()) + ")"
});
});
svg.call(zoom);
drag = d3.behavior.drag().origin(function(d) {
return d;
});
drag.on('dragstart', function() {
return d3.event.sourceEvent.stopPropagation();
});
drag.on('drag', function(d) {
d.x = d3.event.x;
d.y = d3.event.y;
return d3.select(this).attr({
transform: "translate(" + d.x + "," + d.y + ")"
});
});
nodes = zoomable_layer.selectAll('.node').data(nodes_data);
nodes.enter().append('circle').call(drag).attr({
"class": 'node',
r: 20,
fill: 'orange',
transform: function(d) {
return "translate(" + d.x + "," + d.y + ")";
}
});
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment