Skip to content

Instantly share code, notes, and snippets.

@veltman
Last active July 3, 2016 04:27
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 veltman/d0b033db45a7dc016094 to your computer and use it in GitHub Desktop.
Save veltman/d0b033db45a7dc016094 to your computer and use it in GitHub Desktop.
Smooth drag with linear interpolation

Using linear interpolation (lerping) to smooth d3.drag behavior.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
text-align: center;
font: 16px sans-serif;
}
circle {
stroke: #000;
stroke-width: 2px;
fill: #f0f;
cursor: -webkit-grab;
cursor: grab;
}
circle.dragging {
fill: lime;
}
.dragging {
cursor: -webkit-grabbing;
cursor: grabbing;
}
</style>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.14/d3.min.js"></script>
<script>
var margin = {top: 32, right: 32, bottom: 32, left: 32},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
alpha = 0.2;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var drag = d3.behavior.drag()
.origin(ƒ());
var dots = svg.selectAll("circle")
.data(d3.range(16).map(function(d){
return {
x: Math.random() * width,
y: Math.random() * height
};
}))
.enter()
.append("circle")
.attr("r",31)
.attr("cx",ƒ("x"))
.attr("cy",ƒ("y"))
.each(function(d){
d.x2 = d.x;
d.y2 = d.y;
})
.call(drag);
drag.on("dragstart",function(d,i){
this.parentNode.appendChild(this);
var dot = d3.select(this);
dot.classed("dragging",true);
d3.select("body").classed("dragging",true);
d3.timer(function(t){
return lerp(dot);
});
});
drag.on("drag",function(d){
var dragged = d3.select(this);
dragged.datum().x2 = d3.event.x;
dragged.datum().y2 = d3.event.y;
});
drag.on("dragend",function(){
d3.selectAll(".dragging").classed("dragging",false);
});
function lerp(dot) {
var d = dot.datum();
if (!dot.classed("dragging") && Math.abs(d.x2 - d.x) < 0.01 && Math.abs(d.y2 - d.y) < 0.01) {
// It's not being dragged and it's roughly caught up
return true;
}
// Constrain to bounds
d.x = Math.max(Math.min(width,d.x + (d.x2 - d.x) * alpha),0);
d.y = Math.max(Math.min(height,d.y + (d.y2 - d.y) * alpha),0);
dot.attr("cx",d.x)
.attr("cy",d.y);
return false;
}
function ƒ(key) {
return function (d){
return key ? d[key] : d;
};
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment