Skip to content

Instantly share code, notes, and snippets.

@jodaka
Created January 25, 2013 09:48
Show Gist options
  • Save jodaka/4633169 to your computer and use it in GitHub Desktop.
Save jodaka/4633169 to your computer and use it in GitHub Desktop.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<title></title>
<style>
body {
color: #fff;
background: url(http://farm9.staticflickr.com/8498/8396766891_3f169dccff_b.jpg);
min-height: 3000px;
}
.__av-touchOverlay, .__av-touchCanvasOverlay
{
opacity: 0.5;
height: 100%;
background-color: #FFF;
width: 100%;
z-index: 2147483646;
position: fixed;
top:0;
bottom: 0;
right: 0;
left: 0;
}
.__av-touchCanvasOverlay
{
opacity: 1;
background-color: transparent;
z-index: 2147483647;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var touchCanvasOverlay = ( function () {
"use strict";
var tco = {};
tco.canvas = null;
tco.context = null;
tco.points = [];
tco.events = {};
tco.selecting = false;
tco.overlapLimit = 25;
tco.selectionColor = "#DF4B26";
tco.range = {
x0:0,
x1:0,
y0:0,
y1:0
};
/**
* [createTouchOverlay description]
* @return {[type]} [description]
*/
tco.createTouchOverlay = function ( ) {
tco.overlay = document.createElement('div');
tco.overlay.className = '__av-touchOverlay';
document.documentElement.appendChild( tco.overlay );
tco.canvas = document.createElement('canvas');
tco.canvas.className = '__av-touchCanvasOverlay';
tco.context = tco.canvas.getContext("2d");
document.documentElement.appendChild( tco.canvas );
tco.canvas.width = tco.canvas.clientWidth;
tco.canvas.height = tco.canvas.clientHeight;
tco.addEvent( tco.canvas, "touchstart touchmove touchend touchcancel", tco.handleTouchEvents );
tco.startAnimation();
};
/**
* [startAnimation description]
* @return {[type]} [description]
*/
tco.startAnimation = function () {
/**
* [drawPoint description]
* @param {[type]} tco [description]
* @param {[type]} i [description]
* @param {[type]} size [description]
*/
var drawPoint = function ( tco, i, size ) {
tco.context.lineWidth = Math.round( size * 3 / 10 );
tco.context.lineJoin = "round";
tco.context.strokeStyle = tco.selectionColor;
tco.context.beginPath();
if ( i ) {
tco.context.moveTo( tco.points[ i - 1 ][0], tco.points[ i - 1 ][1] );
}
tco.context.lineTo( tco.points[ i ][0], tco.points[ i ][1] );
tco.context.closePath();
tco.context.stroke();
};
/**
* [render description]
* @param {[type]} tco [description]
* @return {[type]} [description]
*/
var render = function ( tco ) {
if ( ! tco.context ) {
return;
}
tco.canvas.width = tco.canvas.width; // Clears the canvas
for ( var i = 0, len = tco.points.length; i < len; i++ ) {
drawPoint( tco, i, len - i );
}
};
// animation
( function animloop() {
tco.animationFrame = window.webkitRequestAnimationFrame( animloop );
render( tco );
}());
tco.inactivityTimeout = setTimeout( function () {
tco.removeOverlay( true );
}, 5000 );
};
/**
* [returnSelectionRegion description]
* @return {[type]} [description]
*/
tco.returnSelectionRegion = function () {
if ( tco.points.length === 0 ) {
return false;
}
var min = { x: tco.points[0][0], y: tco.points[0][1] };
var max = { x: 0, y: 0 };
for ( var i = 0, len = tco.points.length; i < len; i++ ) {
// min
if ( min.x > tco.points[i][0] ) {
min.x = tco.points[i][0];
}
if ( min.y > tco.points[i][1] ) {
min.y = tco.points[i][1];
}
// max
if ( max.x < tco.points[i][0] ) {
max.x = tco.points[i][0];
}
if ( max.y < tco.points[i][1] ) {
max.y = tco.points[i][1];
}
}
tco.region = {
x0: min.x,
y0: min.y,
x1: max.x,
y1: max.y
};
};
/**
* [returnSelectedElements description]
* @return {[type]} [description]
*/
tco.returnSelectedElements = function () {
/**
* Get element scroll data considering parent elements
*
* @param {Node} element
* @return {Number}
*/
var scrolls = function( element ) {
element = element.parentNode;
var position = {
x: 0,
y: 0
};
while ( element && element !== document.body ) {
position.x += element.scrollLeft;
position.y += element.scrollTop;
element = element.parentNode;
}
return position;
};
/**
* [offsets description]
* @param {[type]} element [description]
* @return {[type]} [description]
*/
var offsets = function ( element ) {
var bound = element.getBoundingClientRect();
var elemScroll = scrolls( element );
var fixed = document.defaultView.getComputedStyle( element, null )['position'] === 'fixed';
var bodyScroll = {
x: document.body.scrollLeft,
y: document.body.scrollTop
};
return {
x: parseInt( bound.left, 10 ) + elemScroll.x + ( fixed ? 0 : bodyScroll.x ) - document.documentElement.clientLeft,
y: parseInt( bound.top, 10 ) + elemScroll.y + ( fixed ? 0 : bodyScroll.y ) - document.documentElement.clientTop,
w: element.offsetWidth,
h: element.offsetHeight
};
};
/**
* [isNotIn description]
* @param {[type]} elem [description]
* @param {[type]} collection [description]
* @return {Boolean} [description]
*/
var isNotIn = function ( elem, collection ) {
var length;
while ( elem && elem !== document.body ) {
elem = elem.parentNode;
length = collection.length;
while ( length-- ) {
if ( elem === collection[length] ) {
return false;
}
}
}
return true;
};
/**
* [overlaps description]
* @return {[type]} [description]
*/
var overlaps = function( elem ) {
var earea;
var sarea;
var e = offsets( elem );
var s = tco.region;
var percent = 0;
e.x0 = e.x;
e.y0 = e.y;
e.x1 = e.x + e.w;
e.y1 = e.y + e.h;
if ( e.x1 - e.x0 === 0 || e.y1 - e.y0 === 0 ) {
// zero width or height
percent = 0;
} else if ( e.x0 >= s.x0 && e.y0 >= s.y0 && e.x1 <= s.x1 && e.y1 <= s.y1 ) {
// element fit entirely in selection
percent = 100;
} else if ( e.x0 < s.x0 && e.y0 < s.y0 && e.x1 > s.x1 && e.y1 > s.y1 ) {
// selection fit entirely in element bounds
earea = ( e.x1 - e.x0 ) * ( e.y1 - e.y0 );
sarea = ( s.x1 - s.x0 ) * ( s.y1 - s.y0 );
percent = 100 * sarea / earea;
} else if ( !( ( s.x0 >= e.x1 ) || ( s.y1 <= e.y0 ) || ( s.x1 <= e.x0 ) || ( s.y0 >= e.y1 ) ) ) {
// edge intersection
earea = ( e.x1 - e.x0 ) * ( e.y1 - e.y0 );
var arrx = [ e.x0, e.x1, s.x0, s.x1 ];
var arry = [ e.y0, e.y1, s.y0, s.y1 ];
var sorter = function ( a, b ) { return a > b; };
arrx.sort( sorter );
arry.sort( sorter );
percent = 100 * ( Math.abs( arrx[1] - arrx[2] ) * Math.abs( arry[1] - arry[2] ) ) / earea;
}
return Math.round( percent );
};
/**
* [filterElements description]
* @return {[type]} [description]
*/
var filterElements = function() {
var elems = document.body.getElementsByTagName('*');
var length = elems.length;
var filteredBO = [];
var filteredBD = [];
// filter by overlap
while ( length-- ) {
if ( overlaps( elems[length] ) > tco.overlapLimit ) {
filteredBO.push( elems[length] );
}
}
// filter by decendants
length = filteredBO.length;
while ( length-- ) {
if ( isNotIn( filteredBO[length], filteredBO ) ) {
filteredBD.push( filteredBO[length] );
}
}
return filteredBD;
};
//
var nodes = filterElements();
if ( typeof tco._callback === "function" ) {
tco._callback({ nodes: nodes, coords: tco.region });
}
};
/**
* [addEvent description]
* @param {[type]} element [description]
* @param {[type]} types [description]
* @param {Function} callback [description]
*/
tco.addEvent = function ( element, types, callback ) {
types = types.split(" ");
for ( var t = 0, len = types.length; t < len; t++ ) {
element.addEventListener( types[t], callback, false );
// saving events data
tco.events[ types[t] ] = {
el : element,
type: types[t],
cb : callback
};
}
};
/**
* [addPoint description]
* @param {[type]} evt [description]
*/
tco.addPoint = function ( evt, selecting ) {
// tco.points.push([
// Math.round( ( evt.targetTouches[0].clientX + evt.targetTouches[1].clientX ) / 2 ),
// Math.round( ( evt.targetTouches[0].clientY + evt.targetTouches[1].clientY ) / 2 ),
// selecting || false
// ]);
console.log( evt.targetTouches[0].pageY, evt.targetTouches[0].clientY, evt.targetTouches[0] )
tco.points.push([
Math.round( ( evt.targetTouches[0].pageX + evt.targetTouches[1].pageX ) / 2 ),
Math.round( ( evt.targetTouches[0].pageY + evt.targetTouches[1].pageY ) / 2 ),
selecting || false
]);
tco.points.splice( 200 );
};
/**
* [handleTouchEvents description]
* @param {[type]} evt [description]
* @return {[type]} [description]
*/
tco.handleTouchEvents = function ( evt ) {
evt.preventDefault();
evt.stopPropagation();
if ( evt.type === "touchstart" && evt.touches.length === 2) {
tco.addPoint( evt );
if ( tco.touchEndTimeout ) {
clearTimeout( tco.touchEndTimeout );
return;
}
clearTimeout( tco.inactivityTimeout );
tco.selecting = true;
tco.touchStarted = Date.now();
}
if ( evt.type === "touchmove" && evt.touches.length === 2 ) {
tco.addPoint( evt, true );
}
if (( evt.type === "touchend" || evt.type === "touchcancel" ) && evt.touches.length === 1 && tco.selecting) {
tco.touchEndTimeout = setTimeout( function() {
tco.selecting = false;
tco.touches = [];
tco.removeOverlay();
tco.touchEndTimeout = null;
}, 700 );
}
};
/**
* [removeOverlay description]
* @return {[type]} [description]
*/
tco.removeOverlay = function ( canceled ) {
// stopping all animations
if ( tco.animationFrame ) {
window.webkitCancelAnimationFrame( tco.animationFrame );
}
return 1;
// removing events
for ( var evt in tco.events ) {
if ( tco.events.hasOwnProperty( evt ) ) {
tco.events[ evt ].el.removeEventListener( tco.events[ evt ].type, tco.events[ evt ].cb, false );
}
}
tco.overlay.parentNode.removeChild( tco.overlay );
tco.canvas.parentNode.removeChild( tco.canvas );
if ( canceled && typeof tco._callback === "function" ) {
tco._callback( { nodes: [], coords: tco.region } );
} else {
tco.returnSelectionRegion();
tco.returnSelectedElements();
}
};
return {
init: function ( callback ) {
if ( typeof callback === "function" ) {
tco._callback = callback;
}
tco.createTouchOverlay();
}
};
}());
touchCanvasOverlay.init( function( region ) { console.log( region ); });
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment