Apps Home
|
Create an App
Gestures.Core
Author:
kittens18
Description
Source Code
Launch App
Current Users
Created by:
Kittens18
function get() { navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; var settings = { framerate: 25, videoCompressionRate: 4, sensitivity: 80, skinFilter: false, debug: { state: false, canvas: null, context: null } }, gestIsInitialised = false, userHasAskedToStart = false, stream, video, canvas, context, gest = function() { if (gest.prototype._singletonInstance) { return gest.prototype._singletonInstance; } gest.prototype._singletonInstance = this; if (document.readyState === 'complete') { _DOMready.call(); } else { utils.addEventListener('DOMContentLoaded', document, _DOMready); utils.addEventListener('load', window, _DOMready); } function _DOMready() { utils.removeEventListener('DOMContentLoaded', document, _DOMready); utils.removeEventListener('load', window, _DOMready); if (init()) { gestIsInitialised = true; } if (userHasAskedToStart && gestIsInitialised) { return window.gest.start(); } return false; } return true; }, dispatchGestEvent = function(_gestEvent) { var eventObj = utils.createCustomEvent('gest', document); eventObj.direction = _gestEvent.direction || null; eventObj.up = _gestEvent.up || false; eventObj.down = _gestEvent.down || false; eventObj.left = _gestEvent.left || false; eventObj.right = _gestEvent.right || false; eventObj.error = _gestEvent.error || null; utils.fireEvent(eventObj); }, init = function() { video = document.createElement('video'); canvas = document.createElement('canvas'); if (!!video.canPlayType && !!(canvas.getContext && canvas.getContext('2d')) && !!navigator.getUserMedia) { video.width = 300; video.height = 225; video.setAttribute('style', 'visibility: hidden;'); document.body.appendChild(video); canvas.setAttribute('style', 'width: 300px; display: none;'); document.body.appendChild(canvas); context = canvas.getContext('2d'); } else { throwError(0); return false; } return true; }, throwError = function(_code, _obj) { var _error; switch (_code) { case 0: _error = { code: _code, message: 'gest.js can\'t run in your browser :(' }; break; case 1: _error = { code: _code, message: 'gest.js could not start.' }; break; case 2: _error = { code: _code, message: 'gest.js has already started.' }; break; case 10: _error = { code: _code, message: 'DEEENIED! gest.js needs webcam access.', obj: _obj }; break; case 11: _error = { code: _code, message: 'A constraint specified is not supported by the web-browser.', obj: _obj }; break; case 12: _error = { code: _code, message: 'No media tracks of the type specified in the constraints are found.', obj: _obj }; break; case 13: _error = { code: _code, message: 'Couldn\'t get access to webcam.', obj: _obj }; break; default: _error = null; break; } if (settings.debug.state) { console.error(_error.message); } dispatchGestEvent({ error: _error }); }, grabVideoFrame = function(width, height) { try { context.drawImage(video, 0, 0, width, height); var currentFrame = context.getImageData(0, 0, width, height); if (settings.skinFilter) { differenceMap.get(skinFilter.apply(currentFrame), settings.sensitivity, width, height); } else { differenceMap.get(currentFrame, settings.sensitivity, width, height); } } catch (e) { if (e.name === "NS_ERROR_NOT_AVAILABLE") { return false; } else { throw e; } } }, skinFilter = { huemin: 0.0, huemax: 0.1, satmin: 0.3, satmax: 1.0, valmin: 0.4, valmax: 1.0, rgb2hsv: function(r, g, b) { r = r / 255; g = g / 255; b = b / 255; var max = Math.max(r, g, b), min = Math.min(r, g, b), h, s, v = max, d = max - min; if (max === 0) { s = 0; } else { s = d / max; } if (max == min) { h = 0; } else { switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; default: break; } h /= 6; } return [h, s, v]; }, apply: function(currentFrame) { var totalPix = currentFrame.width * currentFrame.height, indexValue = totalPix * 4, countDataBigAry = 0; for (var y = 0; y < currentFrame.height; y++) { for (var x = 0; x < currentFrame.width; x++) { indexValue = x + y * currentFrame.width; var r = currentFrame.data[countDataBigAry], g = currentFrame.data[countDataBigAry + 1], b = currentFrame.data[countDataBigAry + 2], a = currentFrame.data[countDataBigAry + 3], hsv = this.rgb2hsv(r, g, b); if (((hsv[0] > this.huemin && hsv[0] < this.huemax) || (hsv[0] > 0.59 && hsv[0] < 1.0)) && (hsv[1] > this.satmin && hsv[1] < this.satmax) && (hsv[2] > this.valmin && hsv[2] < this.valmax)) { currentFrame[countDataBigAry] = r; currentFrame[countDataBigAry + 1] = g; currentFrame[countDataBigAry + 2] = b; currentFrame[countDataBigAry + 3] = a; } else { currentFrame.data[countDataBigAry] = 255; currentFrame.data[countDataBigAry + 1] = 255; currentFrame.data[countDataBigAry + 2] = 255; currentFrame.data[countDataBigAry + 3] = 0; } countDataBigAry = indexValue * 4; } } return currentFrame; } }, differenceMap = { priorFrame: false, get: function(currentFrame, sensitivity, width, height) { var delt = context.createImageData(width, height), totalx = 0, totaly = 0, totald = 0; if (this.priorFrame !== false) { var totaln = delt.width * delt.height, pix = totaln * 4, maxAssessableColorChange = 256 * 3; while ((pix -= 4) >= 0) { var d = Math.abs(currentFrame.data[pix] - this.priorFrame.data[pix]) + Math.abs(currentFrame.data[pix + 1] - this.priorFrame.data[pix + 1]) + Math.abs(currentFrame.data[pix + 2] - this.priorFrame.data[pix + 2]); if (d > maxAssessableColorChange * Math.abs((sensitivity - 100) / 100)) { //if there has been significant change in color, mark the changed pixel delt.data[pix] = 255; //R delt.data[pix + 1] = 0; //G delt.data[pix + 2] = 0; //B delt.data[pix + 3] = 255; //alpha totald += 1; totalx += ((pix / 4) % delt.width); totaly += (Math.floor((pix / 4) / delt.height)); } else { delt.data[pix] = currentFrame.data[pix]; delt.data[pix + 1] = currentFrame.data[pix + 1]; delt.data[pix + 2] = currentFrame.data[pix + 2]; delt.data[pix + 3] = currentFrame.data[pix + 3]; } } } if (totald > 0) { lookForGesture.search({ x: totalx, y: totaly, d: totald }); if (settings.debug.state && settings.debug.context.putImageData) { settings.debug.canvas.width = width; settings.debug.canvas.height = height; settings.debug.context.putImageData(delt, 0, 0); } } this.priorFrame = currentFrame; } }, lookForGesture = { prior: false, filteringFactor: 0.9, filteredTotal: 0, minTotalChange: 300, minDirChange: 2, longDirChange: 7, state: 0, search: function(_movement) { var movement = { x: _movement.x / _movement.d, y: _movement.y / _movement.d, d: _movement.d }; this.filteredTotal = (this.filteringFactor * this.filteredTotal) + ((1 - this.filteringFactor) * movement.d); var dfilteredTotal = movement.d - this.filteredTotal, good = dfilteredTotal > this.minTotalChange; switch (this.state) { case 0: if (good) { this.state = 1; lookForGesture.prior = movement; } break; case 1: this.state = 2; var dx = movement.x - lookForGesture.prior.x, dy = movement.y - lookForGesture.prior.y, dirx = Math.abs(dy) < Math.abs(dx); if (dx < -this.minDirChange && dirx) { dispatchGestEvent({ direction: 'Right', right: true }); } else if (dx > this.minDirChange && dirx) { dispatchGestEvent({ direction: 'Left', left: true }); } if (dy > this.minDirChange && !dirx) { if (Math.abs(dy) > this.longDirChange) { dispatchGestEvent({ direction: 'Long down', down: true }); } else { dispatchGestEvent({ direction: 'Down', down: true }); } } else if (dy < -this.minDirChange && !dirx) { if (Math.abs(dy) > this.longDirChange) { dispatchGestEvent({ direction: 'Long up', up: true }); } else { dispatchGestEvent({ direction: 'Up', up: true }); } } break; case 2: if (!good) { this.state = 0; } break; default: break; } } }, utils = { htmlEvents: { onload: 1, onunload: 1, onblur: 1, onchange: 1, onfocus: 1, onreset: 1, onselect: 1, onsubmit: 1, onabort: 1, onkeydown: 1, onkeypress: 1, onkeyup: 1, onclick: 1, ondblclick: 1, onmousedown: 1, onmousemove: 1, onmouseout: 1, onmouseover: 1, onmouseup: 1 }, addEventListener: function(evntName, elem, func) { if (elem.addEventListener) elem.addEventListener(evntName, func, false); else if (elem.attachEvent && this.htmlEvents['on' + evntName]) { elem.attachEvent('on' + evntName, func); } else { elem['on' + evntName] = func; } }, removeEventListener: function(evntName, elem, func) { if (elem.removeEventListener) elem.removeEventListener(evntName, func, false); else if (elem.detachEvent && this.htmlEvents['on' + evntName]) { elem.detachEvent('on' + evntName, func); } else { elem['on' + evntName] = null; } }, createCustomEvent: function(evntName, elem) { try { var evnt; if (elem.createEvent) { evnt = elem.createEvent('Event'); evnt.initEvent(evntName, true, true); } else if (elem.createEventObject) { evnt = elem.createEventObject(); evnt.eventType = evntName; } evnt.evntName = evntName; evnt.evntElement = elem; return evnt; } catch (e) { console.error(e); return false; } }, fireEvent: function(evntObj) { try { if (evntObj.evntElement.dispatchEvent) { evntObj.evntElement.dispatchEvent(evntObj); } else if (evntObj.evntElement.fireEvent && this.htmlEvents['on' + evntObj.evntName]) { evntObj.evntElement.fireEvent('on' + evntObj.eventType, evntObj); } else if (evntObj.evntElement[evntObj.evntName]) { evntObj.evntElement[evntObj.evntName](); } else if (evntObj.evntElement['on' + evntObj.evntName]) { evntObj.evntElement['on' + evntObj.evntName](); } } catch (e) { console.error(e); } } }; gest.prototype.start = function() { userHasAskedToStart = true; if (!gestIsInitialised) { return false; } if (!video || !(video.paused || video.ended || video.seeking || video.readyState < video.HAVE_FUTURE_DATA)) { throwError(2); return false; } navigator.getUserMedia( { audio: false, video: true }, function(_LocalMediaStream) { stream = _LocalMediaStream; window.URL = window.URL || window.webkitURL; video.src = window.URL.createObjectURL(stream); utils.addEventListener('canplaythrough', video, function() { video.play(); utils.addEventListener('playing', video, function() { var width = Math.floor(video.getBoundingClientRect().width / settings.videoCompressionRate), height = Math.floor(video.getBoundingClientRect().height / settings.videoCompressionRate); canvas.width = width; canvas.height = height; setInterval(function() { grabVideoFrame(width, height); }, 1000 / settings.framerate); } ); } ); }, // errorCallback function(error) { if (error.PERMISSION_DENIED || error.name === 'PERMISSION_DENIED') { throwError(10, error); } else if (error.NOT_SUPPORTED_ERROR || error.name === 'NOT_SUPPORTED_ERROR') { throwError(11, error); } else if (error.MANDATORY_UNSATISFIED_ERROR || error.name === 'MANDATORY_UNSATISFIED_ERROR') { throwError(12, error); } else { throwError(13, error); } }); return !!navigator.getUserMedia; }; /* @public */ gest.prototype.stop = function() { if (!gestIsInitialised || !userHasAskedToStart) { return false; } if (video) { video.src = ''; } return !!stream.stop(); }; /* @public */ gest.prototype.options = { subscribeWithCallback: function(callback) { if (callback) { utils.addEventListener('gest', document, function(gesture) { callback(gesture); }); } }, sensitivity: function(_value) { if (_value >= 100) { settings.sensitivity = 100; } else if (_value <= 0) { settings.sensitivity = 0; } else { settings.sensitivity = _value; } }, debug: function(_state) { settings.debug.state = _state; if (_state) { //for visualising the diff map settings.debug.canvas = document.createElement('canvas'); settings.debug.canvas.setAttribute('style', 'width: 100%; height: 100%; display: block; position: absolute; top: 0; left: 0;'); document.body.appendChild(settings.debug.canvas); settings.debug.context = settings.debug.canvas.getContext('2d'); //settings.debug.canvas.setAttribute('style', 'width: 300px; display: block;'); //video.setAttribute('style', 'visibility: visible'); //canvas.setAttribute('style', 'visibility: visible'); } else { settings.debug.canvas.setAttribute('style', 'display: none;'); settings.debug.canvas.parentNode.removeChild(settings.debug.canvas); // video.setAttribute('style', 'visibility: hidden'); // canvas.setAttribute('style', 'visibility: hidden'); } return settings.debug; }, skinFilter: function(_state) { settings.skinFilter = _state; } }; return new gest(); }
© Copyright Chaturbate 2011- 2025. All Rights Reserved.