Skip to content

Instantly share code, notes, and snippets.

@JMStewart
Last active December 22, 2015 11:38
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 JMStewart/6466497 to your computer and use it in GitHub Desktop.
Save JMStewart/6466497 to your computer and use it in GitHub Desktop.
LEAP: Pinch grab

This example uses two fingers to move the cursor, and a pinch motion to grab objects. Using your pointer and middle fingers like chopsticks seems to work a bit better than pinching with your thumb and pointer finger.

<!DOCTYPE html>
<html>
<head>
<script src="//js.leapmotion.com/0.2.0/leap.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<div id="canvas">
<svg height="100%" width="100%">
</svg>
</div>
<div id="data"></div>
<script>
var circleCount = 5;
var minR = 50;
var maxR = 150;
var svg = d3.select("svg");
var height = svg.node().offsetHeight;
var width = svg.node().offsetWidth;
var minX = -90;
var maxX = 90;
var minY = 230;
var maxY = 70;
var xScale = d3.scale.linear()
.domain([minX, maxX])
.range([0,width]);
var yScale = d3.scale.linear()
.domain([minY, maxY])
.range([0,height]);
var circleGroup = svg.append("g")
.attr("id", "circleGroup");
var crosshair = svg.append("g");
crosshair.append("path")
.attr("d", "M-7,0h14M0,-7v14")
.style("stroke", "gray")
.attr("stroke-width", "3");
var circles = [];
var circleIdCounter = 0;
function addCircle(circle){
var circleBox = circle.node().getBoundingClientRect();
// circles.push({
// x : +circleBox.left + circleBox.width/2,
// y : +circleBox.top + circleBox.height/2,
// r : +circleBox.width/2,
// id : circle.attr("id")
// });
circles.push(circle);
}
function createCircle(){
var newR = Math.random() * (maxR - minR) + minR;
var newX = Math.random() * (width - (2 * newR)) + newR;
var newY = Math.random() * (height - (2 * newR)) + newR;
var circle = circleGroup.append("g")
.attr("id", "circle" + circleIdCounter)
.datum({});
circle.selectAll("circle")
.data([3,2,1])
.enter()
.append("circle")
.attr("cx", newX)
.attr("cy", newY)
.attr("r", "0")
.style("fill", function(d){return d%2 ? "red" : "white" ;});
var grow = circle.transition()
.duration(500)
.each("end", function(){addCircle(d3.select(this));});
grow.selectAll("circle")
.attr("r", function(d){ return d * newR / 3;});
circleIdCounter++;
}
for(var i=0;i<circleCount;i++){
createCircle();
}
</script>
</body>
<script>
var pausedFrame = null;
var latestFrame = null;
var oldFrame = null;
var draggingCircle = null;
window.onkeypress = function(e) {
if (e.charCode == 32) {
if (pausedFrame == null) {
pausedFrame = latestFrame;
} else {
pausedFrame = null;
}
}
};
var controller = new Leap.Controller({enableGestures: true});
controller.loop(function(frame) {
oldFrame = latestFrame;
latestFrame = frame;
//if(!pausedFrame)
//document.getElementById('data').innerHTML = (pausedFrame ? "<p><b>PAUSED</b></p>" : "") + "<div>"+(pausedFrame || latestFrame).dump()+"</div>";
var pointableCount = latestFrame.pointables.length;
var handCount = latestFrame.hands.length;
if(!pausedFrame && handCount == 1 && pointableCount == 2){
draggingCircle = null;
crosshair.style("opacity", "1");
var position = latestFrame.pointables[0].stabilizedTipPosition;
var x = xScale(position[0]);
var y = yScale(position[1]);
crosshair.attr("transform", "translate(" + x + "," + y + ")");
}
if(!pausedFrame && oldFrame && oldFrame.pointables.length > 0 && handCount == 1 && pointableCount == 1){
crosshair.style("opacity", "0");
var finger = latestFrame.pointables[0];
var position = finger.stabilizedTipPosition;
var x = xScale(position[0]);
var y = yScale(position[1]);
crosshair.attr("transform", "translate(" + x + "," + y + ")");
var oldX = xScale(oldFrame.pointables[0].stabilizedTipPosition[0]);
var oldY = yScale(oldFrame.pointables[0].stabilizedTipPosition[1]);
// var oldX = xScale(oldFrame.finger(finger.id).stabilizedTipPosition[0]);
// var oldY = yScale(oldFrame.finger(finger.id).stabilizedTipPosition[1]);
if(oldFrame.pointables.length == 2){
grab(x,y);
}
if(draggingCircle){
draggingCircle
.each(function(d){
console.log(d);
d3.select(this).selectAll("circle")
.attr("cx", x + d.xOffset)
.attr("cy", y + d.yOffset);
})
}
}
});
function grab(x,y){
for(var i=0;i<circles.length;i++){
var c = circles[i];
// if(distance(x,y,c.x,c.y) < c.r){
if(circleContainsPoint(c, x, y)){
draggingCircle = c//svg.select("#"+c.id);
draggingCircle.each(function(d){
d.xOffset = d3.select(this).select("circle").attr("cx") - x;
d.yOffset = d3.select(this).select("circle").attr("cy") - y;
console.log(d);
})
console.log("GRAB");
}
}
}
function circleContainsPoint(circle, x, y){
var cx = circle.select("circle").attr("cx");
var cy = circle.select("circle").attr("cy");
var r = circle.select("circle").attr("r");
console.log(distance(x,y,cx,cy) < r);
return distance(x,y,cx,cy) < r;
}
function distance(x1,y1,x2,y2){
d = Math.sqrt(Math.pow(x1-x2,2) + Math.pow(y1-y2,2));
return d;
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment