Created
January 25, 2013 09:48
-
-
Save jodaka/4633169 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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