Skip to content

Instantly share code, notes, and snippets.

@eweitnauer
Last active December 25, 2015 17:19
Show Gist options
  • Save eweitnauer/7012501 to your computer and use it in GitHub Desktop.
Save eweitnauer/7012501 to your computer and use it in GitHub Desktop.
Indirect Animated Dragging

Series of examples:

The examples explore different dragging implementations along two dimensions: First, direct vs. indirect where in the former case the dragged element is determined automatically by the DOM event, while in the latter case, the hit tests on the elements are done manually. This allows, e.g., for moving several elements at once, or moving elements that are not under the mouse when the user started dragging. The second dimension is immediate position update as new mouse positions come in as dragging events or positions updates using transitions. The latter may give the feeling of a slightly smoother interaction.

<!DOCTYPE html>
<meta charset="utf-8">
<title>Indirect Animated Dragging</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
.overlay {
fill: none;
pointer-events: all;
}
</style>
<body>
<script>
var width = 960
,height = 500;
var objs = d3.range(25).map(function () {
return {width: Math.random()*80+20,
height: Math.random()*80+20,
x: Math.random() * width,
y: Math.random() * height } });
var drag = d3.behavior.drag()
.on("drag", dragmove)
.on("dragend", dragend);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.style('margin', '10px')
var g = svg.selectAll("g")
.data(objs)
.enter()
.append("g")
.classed("draggable", true)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
svg.append("rect")
.datum({})
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.call(drag);
g.append('rect')
.attr('x', function (d) { return -d.width/2 })
.attr('y', function (d) { return -d.height/2 })
.attr('width', function (d) { return d.width })
.attr('height', function (d) { return d.height })
.style({stroke: 'lightgray', fill: 'none'});
g.append("text")
.text('x')
.style('text-anchor', 'middle')
.style('dominant-baseline', 'middle')
.style('font-size', function (d) { return Math.min(d.width, d.height)+'px' })
.style('font-style', 'italic');
function dragmove(d) {
if (!d.targets || d.targets.empty()) {
d.targets = get_element_at(d3.event.x, d3.event.y);
if (d.targets.empty()) return;
}
d.targets.each(function(d) { d.x += d3.event.dx; d.y += d3.event.dy})
.transition()
.duration(250)
.ease('circle-out')
.attr('transform', function(d) {return "translate(" + d.x + "," + d.y + ")"});
}
function dragend(d) {
delete d.targets;
}
function get_element_at(x,y) {
//d3.select('svg').append('circle').attr({cx: x, cy: y, r:3});
var hits = d3.selectAll('.draggable')
.filter(function (d) { return x>=d.x-d.width/2 && x <= d.x+d.width/2 && y>= d.y-d.height/2 && y<=d.y+d.height/2 });
return hits;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment