Icard/angular-clarity-master(work.../node_modules/fabric/lib/event.js

1964 lines
59 KiB
JavaScript

/*:
----------------------------------------------------
event.js : 1.1.5 : 2014/02/12 : MIT License
----------------------------------------------------
https://github.com/mudcube/Event.js
----------------------------------------------------
1 : click, dblclick, dbltap
1+ : tap, longpress, drag, swipe
2+ : pinch, rotate
: mousewheel, devicemotion, shake
----------------------------------------------------
Ideas for the future
----------------------------------------------------
* GamePad, and other input abstractions.
* Event batching - i.e. for every x fingers down a new gesture is created.
----------------------------------------------------
http://www.w3.org/TR/2011/WD-touch-events-20110505/
----------------------------------------------------
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
(function(root) { "use strict";
// Add custom *EventListener commands to HTMLElements (set false to prevent funkiness).
root.modifyEventListener = false;
// Add bulk *EventListener commands on NodeLists from querySelectorAll and others (set false to prevent funkiness).
root.modifySelectors = false;
root.configure = function(conf) {
if (isFinite(conf.modifyEventListener)) root.modifyEventListener = conf.modifyEventListener;
if (isFinite(conf.modifySelectors)) root.modifySelectors = conf.modifySelectors;
/// Augment event listeners
if (eventListenersAgumented === false && root.modifyEventListener) {
augmentEventListeners();
}
if (selectorsAugmented === false && root.modifySelectors) {
augmentSelectors();
}
};
// Event maintenance.
root.add = function(target, type, listener, configure) {
return eventManager(target, type, listener, configure, "add");
};
root.remove = function(target, type, listener, configure) {
return eventManager(target, type, listener, configure, "remove");
};
root.returnFalse = function(event) {
return false;
};
root.stop = function(event) {
if (!event) return;
if (event.stopPropagation) event.stopPropagation();
event.cancelBubble = true; // <= IE8
event.cancelBubbleCount = 0;
};
root.prevent = function(event) {
if (!event) return;
if (event.preventDefault) {
event.preventDefault();
} else if (event.preventManipulation) {
event.preventManipulation(); // MS
} else {
event.returnValue = false; // <= IE8
}
};
root.cancel = function(event) {
root.stop(event);
root.prevent(event);
};
root.blur = function() { // Blurs the focused element. Useful when using eventjs.cancel as canceling will prevent focused elements from being blurred.
var node = document.activeElement;
if (!node) return;
var nodeName = document.activeElement.nodeName;
if (nodeName === "INPUT" || nodeName === "TEXTAREA" || node.contentEditable === "true") {
if (node.blur) node.blur();
}
};
// Check whether event is natively supported (via @kangax)
root.getEventSupport = function (target, type) {
if (typeof(target) === "string") {
type = target;
target = window;
}
type = "on" + type;
if (type in target) return true;
if (!target.setAttribute) target = document.createElement("div");
if (target.setAttribute && target.removeAttribute) {
target.setAttribute(type, "");
var isSupported = typeof target[type] === "function";
if (typeof target[type] !== "undefined") target[type] = null;
target.removeAttribute(type);
return isSupported;
}
};
var clone = function (obj) {
if (!obj || typeof (obj) !== 'object') return obj;
var temp = new obj.constructor();
for (var key in obj) {
if (!obj[key] || typeof (obj[key]) !== 'object') {
temp[key] = obj[key];
} else { // clone sub-object
temp[key] = clone(obj[key]);
}
}
return temp;
};
/// Handle custom *EventListener commands.
var eventManager = function(target, type, listener, configure, trigger, fromOverwrite) {
configure = configure || {};
// Check whether target is a configuration variable;
if (String(target) === "[object Object]") {
var data = target;
target = data.target; delete data.target;
///
if (data.type && data.listener) {
type = data.type; delete data.type;
listener = data.listener; delete data.listener;
for (var key in data) {
configure[key] = data[key];
}
} else { // specialness
for (var param in data) {
var value = data[param];
if (typeof(value) === "function") continue;
configure[param] = value;
}
///
var ret = {};
for (var key in data) {
var param = key.split(",");
var o = data[key];
var conf = {};
for (var k in configure) { // clone base configuration
conf[k] = configure[k];
}
///
if (typeof(o) === "function") { // without configuration
var listener = o;
} else if (typeof(o.listener) === "function") { // with configuration
var listener = o.listener;
for (var k in o) { // merge configure into base configuration
if (typeof(o[k]) === "function") continue;
conf[k] = o[k];
}
} else { // not a listener
continue;
}
///
for (var n = 0; n < param.length; n ++) {
ret[key] = eventjs.add(target, param[n], listener, conf, trigger);
}
}
return ret;
}
}
///
if (!target || !type || !listener) return;
// Check for element to load on interval (before onload).
if (typeof(target) === "string" && type === "ready") {
if (window.eventjs_stallOnReady) { /// force stall for scripts to load
type = "load";
target = window;
} else { //
var time = (new Date()).getTime();
var timeout = configure.timeout;
var ms = configure.interval || 1000 / 60;
var interval = window.setInterval(function() {
if ((new Date()).getTime() - time > timeout) {
window.clearInterval(interval);
}
if (document.querySelector(target)) {
window.clearInterval(interval);
setTimeout(listener, 1);
}
}, ms);
return;
}
}
// Get DOM element from Query Selector.
if (typeof(target) === "string") {
target = document.querySelectorAll(target);
if (target.length === 0) return createError("Missing target on listener!", arguments); // No results.
if (target.length === 1) { // Single target.
target = target[0];
}
}
/// Handle multiple targets.
var event;
var events = {};
if (target.length > 0 && target !== window) {
for (var n0 = 0, length0 = target.length; n0 < length0; n0 ++) {
event = eventManager(target[n0], type, listener, clone(configure), trigger);
if (event) events[n0] = event;
}
return createBatchCommands(events);
}
/// Check for multiple events in one string.
if (typeof(type) === "string") {
type = type.toLowerCase();
if (type.indexOf(" ") !== -1) {
type = type.split(" ");
} else if (type.indexOf(",") !== -1) {
type = type.split(",");
}
}
/// Attach or remove multiple events associated with a target.
if (typeof(type) !== "string") { // Has multiple events.
if (typeof(type.length) === "number") { // Handle multiple listeners glued together.
for (var n1 = 0, length1 = type.length; n1 < length1; n1 ++) { // Array [type]
event = eventManager(target, type[n1], listener, clone(configure), trigger);
if (event) events[type[n1]] = event;
}
} else { // Handle multiple listeners.
for (var key in type) { // Object {type}
if (typeof(type[key]) === "function") { // without configuration.
event = eventManager(target, key, type[key], clone(configure), trigger);
} else { // with configuration.
event = eventManager(target, key, type[key].listener, clone(type[key]), trigger);
}
if (event) events[key] = event;
}
}
return createBatchCommands(events);
} else if (type.indexOf("on") === 0) { // to support things like "onclick" instead of "click"
type = type.slice(2);
}
// Ensure listener is a function.
if (typeof(target) !== "object") return createError("Target is not defined!", arguments);
if (typeof(listener) !== "function") return createError("Listener is not a function!", arguments);
// Generate a unique wrapper identifier.
var useCapture = configure.useCapture || false;
var id = getID(target) + "." + getID(listener) + "." + (useCapture ? 1 : 0);
// Handle the event.
if (root.Gesture && root.Gesture._gestureHandlers[type]) { // Fire custom event.
id = type + id;
if (trigger === "remove") { // Remove event listener.
if (!wrappers[id]) return; // Already removed.
wrappers[id].remove();
delete wrappers[id];
} else if (trigger === "add") { // Attach event listener.
if (wrappers[id]) {
wrappers[id].add();
return wrappers[id]; // Already attached.
}
// Retains "this" orientation.
if (configure.useCall && !root.modifyEventListener) {
var tmp = listener;
listener = function(event, self) {
for (var key in self) event[key] = self[key];
return tmp.call(target, event);
};
}
// Create listener proxy.
configure.gesture = type;
configure.target = target;
configure.listener = listener;
configure.fromOverwrite = fromOverwrite;
// Record wrapper.
wrappers[id] = root.proxy[type](configure);
}
return wrappers[id];
} else { // Fire native event.
var eventList = getEventList(type);
for (var n = 0, eventId; n < eventList.length; n ++) {
type = eventList[n];
eventId = type + "." + id;
if (trigger === "remove") { // Remove event listener.
if (!wrappers[eventId]) continue; // Already removed.
target[remove](type, listener, useCapture);
delete wrappers[eventId];
} else if (trigger === "add") { // Attach event listener.
if (wrappers[eventId]) return wrappers[eventId]; // Already attached.
target[add](type, listener, useCapture);
// Record wrapper.
wrappers[eventId] = {
id: eventId,
type: type,
target: target,
listener: listener,
remove: function() {
for (var n = 0; n < eventList.length; n ++) {
root.remove(target, eventList[n], listener, configure);
}
}
};
}
}
return wrappers[eventId];
}
};
/// Perform batch actions on multiple events.
var createBatchCommands = function(events) {
return {
remove: function() { // Remove multiple events.
for (var key in events) {
events[key].remove();
}
},
add: function() { // Add multiple events.
for (var key in events) {
events[key].add();
}
}
};
};
/// Display error message in console.
var createError = function(message, data) {
if (typeof(console) === "undefined") return;
if (typeof(console.error) === "undefined") return;
console.error(message, data);
};
/// Handle naming discrepancies between platforms.
var pointerDefs = {
"msPointer": [ "MSPointerDown", "MSPointerMove", "MSPointerUp" ],
"touch": [ "touchstart", "touchmove", "touchend" ],
"mouse": [ "mousedown", "mousemove", "mouseup" ]
};
var pointerDetect = {
// MSPointer
"MSPointerDown": 0,
"MSPointerMove": 1,
"MSPointerUp": 2,
// Touch
"touchstart": 0,
"touchmove": 1,
"touchend": 2,
// Mouse
"mousedown": 0,
"mousemove": 1,
"mouseup": 2
};
var getEventSupport = (function() {
root.supports = {};
if (window.navigator.msPointerEnabled) {
root.supports.msPointer = true;
}
if (root.getEventSupport("touchstart")) {
root.supports.touch = true;
}
if (root.getEventSupport("mousedown")) {
root.supports.mouse = true;
}
})();
var getEventList = (function() {
return function(type) {
var prefix = document.addEventListener ? "" : "on"; // IE
var idx = pointerDetect[type];
if (isFinite(idx)) {
var types = [];
for (var key in root.supports) {
types.push(prefix + pointerDefs[key][idx]);
}
return types;
} else {
return [ prefix + type ];
}
};
})();
/// Event wrappers to keep track of all events placed in the window.
var wrappers = {};
var counter = 0;
var getID = function(object) {
if (object === window) return "#window";
if (object === document) return "#document";
if (!object.uniqueID) object.uniqueID = "e" + counter ++;
return object.uniqueID;
};
/// Detect platforms native *EventListener command.
var add = document.addEventListener ? "addEventListener" : "attachEvent";
var remove = document.removeEventListener ? "removeEventListener" : "detachEvent";
/*
Pointer.js
----------------------------------------
Modified from; https://github.com/borismus/pointer.js
*/
root.createPointerEvent = function (event, self, preventRecord) {
var eventName = self.gesture;
var target = self.target;
var pts = event.changedTouches || root.proxy.getCoords(event);
if (pts.length) {
var pt = pts[0];
self.pointers = preventRecord ? [] : pts;
self.pageX = pt.pageX;
self.pageY = pt.pageY;
self.x = self.pageX;
self.y = self.pageY;
}
///
var newEvent = document.createEvent("Event");
newEvent.initEvent(eventName, true, true);
newEvent.originalEvent = event;
for (var k in self) {
if (k === "target") continue;
newEvent[k] = self[k];
}
///
var type = newEvent.type;
if (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events.
// target.dispatchEvent(newEvent);
self.oldListener.call(target, newEvent, self, false);
}
};
var eventListenersAgumented = false;
var augmentEventListeners = function() {
/// Allows *EventListener to use custom event proxies.
if (!window.HTMLElement) return;
var augmentEventListener = function(proto) {
var recall = function(trigger) { // overwrite native *EventListener's
var handle = trigger + "EventListener";
var handler = proto[handle];
proto[handle] = function (type, listener, useCapture) {
if (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events.
var configure = useCapture;
if (typeof(useCapture) === "object") {
configure.useCall = true;
} else { // convert to configuration object.
configure = {
useCall: true,
useCapture: useCapture
};
}
eventManager(this, type, listener, configure, trigger, true);
// handler.call(this, type, listener, useCapture);
} else { // use native function.
var types = getEventList(type);
for (var n = 0; n < types.length; n ++) {
handler.call(this, types[n], listener, useCapture);
}
}
};
};
recall("add");
recall("remove");
};
// NOTE: overwriting HTMLElement doesn't do anything in Firefox.
if (navigator.userAgent.match(/Firefox/)) {
// TODO: fix Firefox for the general case.
augmentEventListener(HTMLDivElement.prototype);
augmentEventListener(HTMLCanvasElement.prototype);
} else {
augmentEventListener(HTMLElement.prototype);
}
augmentEventListener(document);
augmentEventListener(window);
};
var selectorsAugmented = false;
var augmentSelectors = function() {
/// Allows querySelectorAll and other NodeLists to perform *EventListener commands in bulk.
var proto = NodeList.prototype;
proto.removeEventListener = function(type, listener, useCapture) {
for (var n = 0, length = this.length; n < length; n ++) {
this[n].removeEventListener(type, listener, useCapture);
}
};
proto.addEventListener = function(type, listener, useCapture) {
for (var n = 0, length = this.length; n < length; n ++) {
this[n].addEventListener(type, listener, useCapture);
}
};
};
return root;
})(eventjs);
/*:
----------------------------------------------------
eventjs.proxy : 0.4.2 : 2013/07/17 : MIT License
----------------------------------------------------
https://github.com/mudcube/eventjs.js
----------------------------------------------------
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
/*
Create a new pointer gesture instance.
*/
root.pointerSetup = function(conf, self) {
/// Configure.
conf.target = conf.target || window;
conf.doc = conf.target.ownerDocument || conf.target; // Associated document.
conf.minFingers = conf.minFingers || conf.fingers || 1; // Minimum required fingers.
conf.maxFingers = conf.maxFingers || conf.fingers || Infinity; // Maximum allowed fingers.
conf.position = conf.position || "relative"; // Determines what coordinate system points are returned.
delete conf.fingers; //-
/// Convenience data.
self = self || {};
self.enabled = true;
self.gesture = conf.gesture;
self.target = conf.target;
self.env = conf.env;
///
if (eventjs.modifyEventListener && conf.fromOverwrite) {
conf.oldListener = conf.listener;
conf.listener = eventjs.createPointerEvent;
}
/// Convenience commands.
var fingers = 0;
var type = self.gesture.indexOf("pointer") === 0 && eventjs.modifyEventListener ? "pointer" : "mouse";
if (conf.oldListener) self.oldListener = conf.oldListener;
///
self.listener = conf.listener;
self.proxy = function(listener) {
self.defaultListener = conf.listener;
conf.listener = listener;
listener(conf.event, self);
};
self.add = function() {
if (self.enabled === true) return;
if (conf.onPointerDown) eventjs.add(conf.target, type + "down", conf.onPointerDown);
if (conf.onPointerMove) eventjs.add(conf.doc, type + "move", conf.onPointerMove);
if (conf.onPointerUp) eventjs.add(conf.doc, type + "up", conf.onPointerUp);
self.enabled = true;
};
self.remove = function() {
if (self.enabled === false) return;
if (conf.onPointerDown) eventjs.remove(conf.target, type + "down", conf.onPointerDown);
if (conf.onPointerMove) eventjs.remove(conf.doc, type + "move", conf.onPointerMove);
if (conf.onPointerUp) eventjs.remove(conf.doc, type + "up", conf.onPointerUp);
self.reset();
self.enabled = false;
};
self.pause = function(opt) {
if (conf.onPointerMove && (!opt || opt.move)) eventjs.remove(conf.doc, type + "move", conf.onPointerMove);
if (conf.onPointerUp && (!opt || opt.up)) eventjs.remove(conf.doc, type + "up", conf.onPointerUp);
fingers = conf.fingers;
conf.fingers = 0;
};
self.resume = function(opt) {
if (conf.onPointerMove && (!opt || opt.move)) eventjs.add(conf.doc, type + "move", conf.onPointerMove);
if (conf.onPointerUp && (!opt || opt.up)) eventjs.add(conf.doc, type + "up", conf.onPointerUp);
conf.fingers = fingers;
};
self.reset = function() {
conf.tracker = {};
conf.fingers = 0;
};
///
return self;
};
/*
Begin proxied pointer command.
*/
var sp = eventjs.supports; // Default pointerType
///
eventjs.isMouse = !!sp.mouse;
eventjs.isMSPointer = !!sp.touch;
eventjs.isTouch = !!sp.msPointer;
///
root.pointerStart = function(event, self, conf) {
/// tracks multiple inputs
var type = (event.type || "mousedown").toUpperCase();
if (type.indexOf("MOUSE") === 0) {
eventjs.isMouse = true;
eventjs.isTouch = false;
eventjs.isMSPointer = false;
} else if (type.indexOf("TOUCH") === 0) {
eventjs.isMouse = false;
eventjs.isTouch = true;
eventjs.isMSPointer = false;
} else if (type.indexOf("MSPOINTER") === 0) {
eventjs.isMouse = false;
eventjs.isTouch = false;
eventjs.isMSPointer = true;
}
///
var addTouchStart = function(touch, sid) {
var bbox = conf.bbox;
var pt = track[sid] = {};
///
switch(conf.position) {
case "absolute": // Absolute from within window.
pt.offsetX = 0;
pt.offsetY = 0;
break;
case "differenceFromLast": // Since last coordinate recorded.
pt.offsetX = touch.pageX;
pt.offsetY = touch.pageY;
break;
case "difference": // Relative from origin.
pt.offsetX = touch.pageX;
pt.offsetY = touch.pageY;
break;
case "move": // Move target element.
pt.offsetX = touch.pageX - bbox.x1;
pt.offsetY = touch.pageY - bbox.y1;
break;
default: // Relative from within target.
pt.offsetX = bbox.x1 - bbox.scrollLeft;
pt.offsetY = bbox.y1 - bbox.scrollTop;
break;
}
///
var x = touch.pageX - pt.offsetX;
var y = touch.pageY - pt.offsetY;
///
pt.rotation = 0;
pt.scale = 1;
pt.startTime = pt.moveTime = (new Date()).getTime();
pt.move = { x: x, y: y };
pt.start = { x: x, y: y };
///
conf.fingers ++;
};
///
conf.event = event;
if (self.defaultListener) {
conf.listener = self.defaultListener;
delete self.defaultListener;
}
///
var isTouchStart = !conf.fingers;
var track = conf.tracker;
var touches = event.changedTouches || root.getCoords(event);
var length = touches.length;
// Adding touch events to tracking.
for (var i = 0; i < length; i ++) {
var touch = touches[i];
var sid = touch.identifier || Infinity; // Touch ID.
// Track the current state of the touches.
if (conf.fingers) {
if (conf.fingers >= conf.maxFingers) {
var ids = [];
for (var sid in conf.tracker) ids.push(sid);
self.identifier = ids.join(",");
return isTouchStart;
}
var fingers = 0; // Finger ID.
for (var rid in track) {
// Replace removed finger.
if (track[rid].up) {
delete track[rid];
addTouchStart(touch, sid);
conf.cancel = true;
break;
}
fingers ++;
}
// Add additional finger.
if (track[sid]) continue;
addTouchStart(touch, sid);
} else { // Start tracking fingers.
track = conf.tracker = {};
self.bbox = conf.bbox = root.getBoundingBox(conf.target);
conf.fingers = 0;
conf.cancel = false;
addTouchStart(touch, sid);
}
}
///
var ids = [];
for (var sid in conf.tracker) ids.push(sid);
self.identifier = ids.join(",");
///
return isTouchStart;
};
/*
End proxied pointer command.
*/
root.pointerEnd = function(event, self, conf, onPointerUp) {
// Record changed touches have ended (iOS changedTouches is not reliable).
var touches = event.touches || [];
var length = touches.length;
var exists = {};
for (var i = 0; i < length; i ++) {
var touch = touches[i];
var sid = touch.identifier;
exists[sid || Infinity] = true;
}
for (var sid in conf.tracker) {
var track = conf.tracker[sid];
if (exists[sid] || track.up) continue;
if (onPointerUp) { // add changedTouches to mouse.
onPointerUp({
pageX: track.pageX,
pageY: track.pageY,
changedTouches: [{
pageX: track.pageX,
pageY: track.pageY,
identifier: sid === "Infinity" ? Infinity : sid
}]
}, "up");
}
track.up = true;
conf.fingers --;
}
/* // This should work but fails in Safari on iOS4 so not using it.
var touches = event.changedTouches || root.getCoords(event);
var length = touches.length;
// Record changed touches have ended (this should work).
for (var i = 0; i < length; i ++) {
var touch = touches[i];
var sid = touch.identifier || Infinity;
var track = conf.tracker[sid];
if (track && !track.up) {
if (onPointerUp) { // add changedTouches to mouse.
onPointerUp({
changedTouches: [{
pageX: track.pageX,
pageY: track.pageY,
identifier: sid === "Infinity" ? Infinity : sid
}]
}, "up");
}
track.up = true;
conf.fingers --;
}
} */
// Wait for all fingers to be released.
if (conf.fingers !== 0) return false;
// Record total number of fingers gesture used.
var ids = [];
conf.gestureFingers = 0;
for (var sid in conf.tracker) {
conf.gestureFingers ++;
ids.push(sid);
}
self.identifier = ids.join(",");
// Our pointer gesture has ended.
return true;
};
/*
Returns mouse coords in an array to match event.*Touches
------------------------------------------------------------
var touch = event.changedTouches || root.getCoords(event);
*/
root.getCoords = function(event) {
if (typeof(event.pageX) !== "undefined") { // Desktop browsers.
root.getCoords = function(event) {
return Array({
type: "mouse",
x: event.pageX,
y: event.pageY,
pageX: event.pageX,
pageY: event.pageY,
identifier: event.pointerId || Infinity // pointerId is MS
});
};
} else { // Internet Explorer <= 8.0
root.getCoords = function(event) {
var doc = document.documentElement;
event = event || window.event;
return Array({
type: "mouse",
x: event.clientX + doc.scrollLeft,
y: event.clientY + doc.scrollTop,
pageX: event.clientX + doc.scrollLeft,
pageY: event.clientY + doc.scrollTop,
identifier: Infinity
});
};
}
return root.getCoords(event);
};
/*
Returns single coords in an object.
------------------------------------------------------------
var mouse = root.getCoord(event);
*/
root.getCoord = function(event) {
if ("ontouchstart" in window) { // Mobile browsers.
var pX = 0;
var pY = 0;
root.getCoord = function(event) {
var touches = event.changedTouches;
if (touches && touches.length) { // ontouchstart + ontouchmove
return {
x: pX = touches[0].pageX,
y: pY = touches[0].pageY
};
} else { // ontouchend
return {
x: pX,
y: pY
};
}
};
} else if(typeof(event.pageX) !== "undefined" && typeof(event.pageY) !== "undefined") { // Desktop browsers.
root.getCoord = function(event) {
return {
x: event.pageX,
y: event.pageY
};
};
} else { // Internet Explorer <=8.0
root.getCoord = function(event) {
var doc = document.documentElement;
event = event || window.event;
return {
x: event.clientX + doc.scrollLeft,
y: event.clientY + doc.scrollTop
};
};
}
return root.getCoord(event);
};
/*
Get target scale and position in space.
*/
var getPropertyAsFloat = function(o, type) {
var n = parseFloat(o.getPropertyValue(type), 10);
return isFinite(n) ? n : 0;
};
root.getBoundingBox = function(o) {
if (o === window || o === document) o = document.body;
///
var bbox = {};
var bcr = o.getBoundingClientRect();
bbox.width = bcr.width;
bbox.height = bcr.height;
bbox.x1 = bcr.left;
bbox.y1 = bcr.top;
bbox.scaleX = bcr.width / o.offsetWidth || 1;
bbox.scaleY = bcr.height / o.offsetHeight || 1;
bbox.scrollLeft = 0;
bbox.scrollTop = 0;
///
var style = window.getComputedStyle(o);
var borderBox = style.getPropertyValue("box-sizing") === "border-box";
///
if (borderBox === false) {
var left = getPropertyAsFloat(style, "border-left-width");
var right = getPropertyAsFloat(style, "border-right-width");
var bottom = getPropertyAsFloat(style, "border-bottom-width");
var top = getPropertyAsFloat(style, "border-top-width");
bbox.border = [ left, right, top, bottom ];
bbox.x1 += left;
bbox.y1 += top;
bbox.width -= right + left;
bbox.height -= bottom + top;
}
/* var left = getPropertyAsFloat(style, "padding-left");
var right = getPropertyAsFloat(style, "padding-right");
var bottom = getPropertyAsFloat(style, "padding-bottom");
var top = getPropertyAsFloat(style, "padding-top");
bbox.padding = [ left, right, top, bottom ];*/
///
bbox.x2 = bbox.x1 + bbox.width;
bbox.y2 = bbox.y1 + bbox.height;
/// Get the scroll of container element.
var position = style.getPropertyValue("position");
var tmp = position === "fixed" ? o : o.parentNode;
while (tmp !== null) {
if (tmp === document.body) break;
if (tmp.scrollTop === undefined) break;
var style = window.getComputedStyle(tmp);
var position = style.getPropertyValue("position");
if (position === "absolute") {
} else if (position === "fixed") {
// bbox.scrollTop += document.body.scrollTop;
// bbox.scrollLeft += document.body.scrollLeft;
bbox.scrollTop -= tmp.parentNode.scrollTop;
bbox.scrollLeft -= tmp.parentNode.scrollLeft;
break;
} else {
bbox.scrollLeft += tmp.scrollLeft;
bbox.scrollTop += tmp.scrollTop;
}
///
tmp = tmp.parentNode;
};
///
bbox.scrollBodyLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
bbox.scrollBodyTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
///
bbox.scrollLeft -= bbox.scrollBodyLeft;
bbox.scrollTop -= bbox.scrollBodyTop;
///
return bbox;
};
/*
Keep track of metaKey, the proper ctrlKey for users platform.
----------------------------------------------------
http://www.quirksmode.org/js/keys.html
-----------------------------------
http://unixpapa.com/js/key.html
*/
(function() {
var agent = navigator.userAgent.toLowerCase();
var mac = agent.indexOf("macintosh") !== -1;
var metaKeys;
if (mac && agent.indexOf("khtml") !== -1) { // chrome, safari.
metaKeys = { 91: true, 93: true };
} else if (mac && agent.indexOf("firefox") !== -1) { // mac firefox.
metaKeys = { 224: true };
} else { // windows, linux, or mac opera.
metaKeys = { 17: true };
}
(root.metaTrackerReset = function() {
eventjs.fnKey = root.fnKey = false;
eventjs.metaKey = root.metaKey = false;
eventjs.escKey = root.escKey = false;
eventjs.ctrlKey = root.ctrlKey = false;
eventjs.shiftKey = root.shiftKey = false;
eventjs.altKey = root.altKey = false;
})();
root.metaTracker = function(event) {
var isKeyDown = event.type === "keydown";
if (event.keyCode === 27) eventjs.escKey = root.escKey = isKeyDown;
if (metaKeys[event.keyCode]) eventjs.metaKey = root.metaKey = isKeyDown;
eventjs.ctrlKey = root.ctrlKey = event.ctrlKey;
eventjs.shiftKey = root.shiftKey = event.shiftKey;
eventjs.altKey = root.altKey = event.altKey;
};
})();
return root;
})(eventjs.proxy);
/*:
----------------------------------------------------
"MutationObserver" event proxy.
----------------------------------------------------
author: Selvakumar Arumugam - MIT LICENSE
src: http://stackoverflow.com/questions/10868104/can-you-have-a-javascript-hook-trigger-after-a-dom-elements-style-object-change
----------------------------------------------------
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
eventjs.MutationObserver = (function() {
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
var DOMAttrModifiedSupported = !MutationObserver && (function() {
var p = document.createElement("p");
var flag = false;
var fn = function() { flag = true };
if (p.addEventListener) {
p.addEventListener("DOMAttrModified", fn, false);
} else if (p.attachEvent) {
p.attachEvent("onDOMAttrModified", fn);
} else {
return false;
}
///
p.setAttribute("id", "target");
///
return flag;
})();
///
return function(container, callback) {
if (MutationObserver) {
var options = {
subtree: false,
attributes: true
};
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(e) {
callback.call(e.target, e.attributeName);
});
});
observer.observe(container, options)
} else if (DOMAttrModifiedSupported) {
eventjs.add(container, "DOMAttrModified", function(e) {
callback.call(container, e.attrName);
});
} else if ("onpropertychange" in document.body) {
eventjs.add(container, "propertychange", function(e) {
callback.call(container, window.event.propertyName);
});
}
}
})();
/*:
"Click" event proxy.
----------------------------------------------------
eventjs.add(window, "click", function(event, self) {});
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
root.click = function(conf) {
conf.gesture = conf.gesture || "click";
conf.maxFingers = conf.maxFingers || conf.fingers || 1;
/// Tracking the events.
conf.onPointerDown = function (event) {
if (root.pointerStart(event, self, conf)) {
eventjs.add(conf.target, "mouseup", conf.onPointerUp);
}
};
conf.onPointerUp = function(event) {
if (root.pointerEnd(event, self, conf)) {
eventjs.remove(conf.target, "mouseup", conf.onPointerUp);
var pointers = event.changedTouches || root.getCoords(event);
var pointer = pointers[0];
var bbox = conf.bbox;
var newbbox = root.getBoundingBox(conf.target);
var y = pointer.pageY - newbbox.scrollBodyTop;
var x = pointer.pageX - newbbox.scrollBodyLeft;
////
if (x > bbox.x1 && y > bbox.y1 &&
x < bbox.x2 && y < bbox.y2 &&
bbox.scrollTop === newbbox.scrollTop) { // has not been scrolled
///
for (var key in conf.tracker) break; //- should be modularized? in dblclick too
var point = conf.tracker[key];
self.x = point.start.x;
self.y = point.start.y;
///
conf.listener(event, self);
}
}
};
// Generate maintenance commands, and other configurations.
var self = root.pointerSetup(conf);
self.state = "click";
// Attach events.
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.click = root.click;
return root;
})(eventjs.proxy);
/*:
"Double-Click" aka "Double-Tap" event proxy.
----------------------------------------------------
eventjs.add(window, "dblclick", function(event, self) {});
----------------------------------------------------
Touch an target twice for <= 700ms, with less than 25 pixel drift.
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
root.dbltap =
root.dblclick = function(conf) {
conf.gesture = conf.gesture || "dbltap";
conf.maxFingers = conf.maxFingers || conf.fingers || 1;
// Setting up local variables.
var delay = 700; // in milliseconds
var time0, time1, timeout;
var pointer0, pointer1;
// Tracking the events.
conf.onPointerDown = function (event) {
var pointers = event.changedTouches || root.getCoords(event);
if (time0 && !time1) { // Click #2
pointer1 = pointers[0];
time1 = (new Date()).getTime() - time0;
} else { // Click #1
pointer0 = pointers[0];
time0 = (new Date()).getTime();
time1 = 0;
clearTimeout(timeout);
timeout = setTimeout(function() {
time0 = 0;
}, delay);
}
if (root.pointerStart(event, self, conf)) {
eventjs.add(conf.target, "mousemove", conf.onPointerMove).listener(event);
eventjs.add(conf.target, "mouseup", conf.onPointerUp);
}
};
conf.onPointerMove = function (event) {
if (time0 && !time1) {
var pointers = event.changedTouches || root.getCoords(event);
pointer1 = pointers[0];
}
var bbox = conf.bbox;
var ax = (pointer1.pageX - bbox.x1);
var ay = (pointer1.pageY - bbox.y1);
if (!(ax > 0 && ax < bbox.width && // Within target coordinates..
ay > 0 && ay < bbox.height &&
Math.abs(pointer1.pageX - pointer0.pageX) <= 25 && // Within drift deviance.
Math.abs(pointer1.pageY - pointer0.pageY) <= 25)) {
// Cancel out this listener.
eventjs.remove(conf.target, "mousemove", conf.onPointerMove);
clearTimeout(timeout);
time0 = time1 = 0;
}
};
conf.onPointerUp = function(event) {
if (root.pointerEnd(event, self, conf)) {
eventjs.remove(conf.target, "mousemove", conf.onPointerMove);
eventjs.remove(conf.target, "mouseup", conf.onPointerUp);
}
if (time0 && time1) {
if (time1 <= delay) { // && !(event.cancelBubble && ++event.cancelBubbleCount > 1)) {
self.state = conf.gesture;
for (var key in conf.tracker) break;
var point = conf.tracker[key];
self.x = point.start.x;
self.y = point.start.y;
conf.listener(event, self);
}
clearTimeout(timeout);
time0 = time1 = 0;
}
};
// Generate maintenance commands, and other configurations.
var self = root.pointerSetup(conf);
self.state = "dblclick";
// Attach events.
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.dbltap = root.dbltap;
eventjs.Gesture._gestureHandlers.dblclick = root.dblclick;
return root;
})(eventjs.proxy);
/*:
"Drag" event proxy (1+ fingers).
----------------------------------------------------
CONFIGURE: maxFingers, position.
----------------------------------------------------
eventjs.add(window, "drag", function(event, self) {
console.log(self.gesture, self.state, self.start, self.x, self.y, self.bbox);
});
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
root.dragElement = function(that, event) {
root.drag({
event: event,
target: that,
position: "move",
listener: function(event, self) {
that.style.left = self.x + "px";
that.style.top = self.y + "px";
eventjs.prevent(event);
}
});
};
root.drag = function(conf) {
conf.gesture = "drag";
conf.onPointerDown = function (event) {
if (root.pointerStart(event, self, conf)) {
if (!conf.monitor) {
eventjs.add(conf.doc, "mousemove", conf.onPointerMove);
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
}
}
// Process event listener.
conf.onPointerMove(event, "down");
};
conf.onPointerMove = function (event, state) {
if (!conf.tracker) return conf.onPointerDown(event);
var bbox = conf.bbox;
var touches = event.changedTouches || root.getCoords(event);
var length = touches.length;
for (var i = 0; i < length; i ++) {
var touch = touches[i];
var identifier = touch.identifier || Infinity;
var pt = conf.tracker[identifier];
// Identifier defined outside of listener.
if (!pt) continue;
pt.pageX = touch.pageX;
pt.pageY = touch.pageY;
// Record data.
self.state = state || "move";
self.identifier = identifier;
self.start = pt.start;
self.fingers = conf.fingers;
if (conf.position === "differenceFromLast") {
self.x = (pt.pageX - pt.offsetX);
self.y = (pt.pageY - pt.offsetY);
pt.offsetX = pt.pageX;
pt.offsetY = pt.pageY;
} else {
self.x = (pt.pageX - pt.offsetX);
self.y = (pt.pageY - pt.offsetY);
}
///
conf.listener(event, self);
}
};
conf.onPointerUp = function(event) {
// Remove tracking for touch.
if (root.pointerEnd(event, self, conf, conf.onPointerMove)) {
if (!conf.monitor) {
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
}
}
};
// Generate maintenance commands, and other configurations.
var self = root.pointerSetup(conf);
// Attach events.
if (conf.event) {
conf.onPointerDown(conf.event);
} else { //
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
if (conf.monitor) {
eventjs.add(conf.doc, "mousemove", conf.onPointerMove);
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
}
}
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.drag = root.drag;
return root;
})(eventjs.proxy);
/*:
"Gesture" event proxy (2+ fingers).
----------------------------------------------------
CONFIGURE: minFingers, maxFingers.
----------------------------------------------------
eventjs.add(window, "gesture", function(event, self) {
console.log(
self.x, // centroid
self.y,
self.rotation,
self.scale,
self.fingers,
self.state
);
});
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
var RAD_DEG = Math.PI / 180;
var getCentroid = function(self, points) {
var centroidx = 0;
var centroidy = 0;
var length = 0;
for (var sid in points) {
var touch = points[sid];
if (touch.up) continue;
centroidx += touch.move.x;
centroidy += touch.move.y;
length ++;
}
self.x = centroidx /= length;
self.y = centroidy /= length;
return self;
};
root.gesture = function(conf) {
conf.gesture = conf.gesture || "gesture";
conf.minFingers = conf.minFingers || conf.fingers || 2;
// Tracking the events.
conf.onPointerDown = function (event) {
var fingers = conf.fingers;
if (root.pointerStart(event, self, conf)) {
eventjs.add(conf.doc, "mousemove", conf.onPointerMove);
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
}
// Record gesture start.
if (conf.fingers === conf.minFingers && fingers !== conf.fingers) {
self.fingers = conf.minFingers;
self.scale = 1;
self.rotation = 0;
self.state = "start";
var sids = ""; //- FIXME(mud): can generate duplicate IDs.
for (var key in conf.tracker) sids += key;
self.identifier = parseInt(sids);
getCentroid(self, conf.tracker);
conf.listener(event, self);
}
};
///
conf.onPointerMove = function (event, state) {
var bbox = conf.bbox;
var points = conf.tracker;
var touches = event.changedTouches || root.getCoords(event);
var length = touches.length;
// Update tracker coordinates.
for (var i = 0; i < length; i ++) {
var touch = touches[i];
var sid = touch.identifier || Infinity;
var pt = points[sid];
// Check whether "pt" is used by another gesture.
if (!pt) continue;
// Find the actual coordinates.
pt.move.x = (touch.pageX - bbox.x1);
pt.move.y = (touch.pageY - bbox.y1);
}
///
if (conf.fingers < conf.minFingers) return;
///
var touches = [];
var scale = 0;
var rotation = 0;
/// Calculate centroid of gesture.
getCentroid(self, points);
///
for (var sid in points) {
var touch = points[sid];
if (touch.up) continue;
var start = touch.start;
if (!start.distance) {
var dx = start.x - self.x;
var dy = start.y - self.y;
start.distance = Math.sqrt(dx * dx + dy * dy);
start.angle = Math.atan2(dx, dy) / RAD_DEG;
}
// Calculate scale.
var dx = touch.move.x - self.x;
var dy = touch.move.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If touch start.distance from centroid is 0, scale should not be updated.
// This prevents dividing by 0 in cases where start.distance is oddly 0.
if (start.distance !== 0) {
scale += distance / start.distance;
}
// Calculate rotation.
var angle = Math.atan2(dx, dy) / RAD_DEG;
var rotate = (start.angle - angle + 360) % 360 - 180;
touch.DEG2 = touch.DEG1; // Previous degree.
touch.DEG1 = rotate > 0 ? rotate : -rotate; // Current degree.
if (typeof(touch.DEG2) !== "undefined") {
if (rotate > 0) {
touch.rotation += touch.DEG1 - touch.DEG2;
} else {
touch.rotation -= touch.DEG1 - touch.DEG2;
}
rotation += touch.rotation;
}
// Attach current points to self.
touches.push(touch.move);
}
///
self.touches = touches;
self.fingers = conf.fingers;
self.scale = scale / conf.fingers;
self.rotation = rotation / conf.fingers;
self.state = "change";
conf.listener(event, self);
};
conf.onPointerUp = function(event) {
// Remove tracking for touch.
var fingers = conf.fingers;
if (root.pointerEnd(event, self, conf)) {
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
}
// Check whether fingers has dropped below minFingers.
if (fingers === conf.minFingers && conf.fingers < conf.minFingers) {
self.fingers = conf.fingers;
self.state = "end";
conf.listener(event, self);
}
};
// Generate maintenance commands, and other configurations.
var self = root.pointerSetup(conf);
// Attach events.
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.gesture = root.gesture;
return root;
})(eventjs.proxy);
/*:
"Pointer" event proxy (1+ fingers).
----------------------------------------------------
CONFIGURE: minFingers, maxFingers.
----------------------------------------------------
eventjs.add(window, "gesture", function(event, self) {
console.log(self.rotation, self.scale, self.fingers, self.state);
});
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
root.pointerdown =
root.pointermove =
root.pointerup = function(conf) {
conf.gesture = conf.gesture || "pointer";
if (conf.target.isPointerEmitter) return;
// Tracking the events.
var isDown = true;
conf.onPointerDown = function (event) {
isDown = false;
self.gesture = "pointerdown";
conf.listener(event, self);
};
conf.onPointerMove = function (event) {
self.gesture = "pointermove";
conf.listener(event, self, isDown);
};
conf.onPointerUp = function (event) {
isDown = true;
self.gesture = "pointerup";
conf.listener(event, self, true);
};
// Generate maintenance commands, and other configurations.
var self = root.pointerSetup(conf);
// Attach events.
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
eventjs.add(conf.target, "mousemove", conf.onPointerMove);
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
// Return this object.
conf.target.isPointerEmitter = true;
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.pointerdown = root.pointerdown;
eventjs.Gesture._gestureHandlers.pointermove = root.pointermove;
eventjs.Gesture._gestureHandlers.pointerup = root.pointerup;
return root;
})(eventjs.proxy);
/*:
"Device Motion" and "Shake" event proxy.
----------------------------------------------------
http://developer.android.com/reference/android/hardware/Sensoreventjs.html#values
----------------------------------------------------
eventjs.add(window, "shake", function(event, self) {});
eventjs.add(window, "devicemotion", function(event, self) {
console.log(self.acceleration, self.accelerationIncludingGravity);
});
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
root.shake = function(conf) {
// Externally accessible data.
var self = {
gesture: "devicemotion",
acceleration: {},
accelerationIncludingGravity: {},
target: conf.target,
listener: conf.listener,
remove: function() {
window.removeEventListener('devicemotion', onDeviceMotion, false);
}
};
// Setting up local variables.
var threshold = 4; // Gravitational threshold.
var timeout = 1000; // Timeout between shake events.
var timeframe = 200; // Time between shakes.
var shakes = 3; // Minimum shakes to trigger event.
var lastShake = (new Date()).getTime();
var gravity = { x: 0, y: 0, z: 0 };
var delta = {
x: { count: 0, value: 0 },
y: { count: 0, value: 0 },
z: { count: 0, value: 0 }
};
// Tracking the events.
var onDeviceMotion = function(e) {
var alpha = 0.8; // Low pass filter.
var o = e.accelerationIncludingGravity;
gravity.x = alpha * gravity.x + (1 - alpha) * o.x;
gravity.y = alpha * gravity.y + (1 - alpha) * o.y;
gravity.z = alpha * gravity.z + (1 - alpha) * o.z;
self.accelerationIncludingGravity = gravity;
self.acceleration.x = o.x - gravity.x;
self.acceleration.y = o.y - gravity.y;
self.acceleration.z = o.z - gravity.z;
///
if (conf.gesture === "devicemotion") {
conf.listener(e, self);
return;
}
var data = "xyz";
var now = (new Date()).getTime();
for (var n = 0, length = data.length; n < length; n ++) {
var letter = data[n];
var ACCELERATION = self.acceleration[letter];
var DELTA = delta[letter];
var abs = Math.abs(ACCELERATION);
/// Check whether another shake event was recently registered.
if (now - lastShake < timeout) continue;
/// Check whether delta surpasses threshold.
if (abs > threshold) {
var idx = now * ACCELERATION / abs;
var span = Math.abs(idx + DELTA.value);
// Check whether last delta was registered within timeframe.
if (DELTA.value && span < timeframe) {
DELTA.value = idx;
DELTA.count ++;
// Check whether delta count has enough shakes.
if (DELTA.count === shakes) {
conf.listener(e, self);
// Reset tracking.
lastShake = now;
DELTA.value = 0;
DELTA.count = 0;
}
} else {
// Track first shake.
DELTA.value = idx;
DELTA.count = 1;
}
}
}
};
// Attach events.
if (!window.addEventListener) return;
window.addEventListener('devicemotion', onDeviceMotion, false);
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.shake = root.shake;
return root;
})(eventjs.proxy);
/*:
"Swipe" event proxy (1+ fingers).
----------------------------------------------------
CONFIGURE: snap, threshold, maxFingers.
----------------------------------------------------
eventjs.add(window, "swipe", function(event, self) {
console.log(self.velocity, self.angle);
});
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
var RAD_DEG = Math.PI / 180;
root.swipe = function(conf) {
conf.snap = conf.snap || 90; // angle snap.
conf.threshold = conf.threshold || 1; // velocity threshold.
conf.gesture = conf.gesture || "swipe";
// Tracking the events.
conf.onPointerDown = function (event) {
if (root.pointerStart(event, self, conf)) {
eventjs.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
}
};
conf.onPointerMove = function (event) {
var touches = event.changedTouches || root.getCoords(event);
var length = touches.length;
for (var i = 0; i < length; i ++) {
var touch = touches[i];
var sid = touch.identifier || Infinity;
var o = conf.tracker[sid];
// Identifier defined outside of listener.
if (!o) continue;
o.move.x = touch.pageX;
o.move.y = touch.pageY;
o.moveTime = (new Date()).getTime();
}
};
conf.onPointerUp = function(event) {
if (root.pointerEnd(event, self, conf)) {
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
///
var velocity1;
var velocity2
var degree1;
var degree2;
/// Calculate centroid of gesture.
var start = { x: 0, y: 0 };
var endx = 0;
var endy = 0;
var length = 0;
///
for (var sid in conf.tracker) {
var touch = conf.tracker[sid];
var xdist = touch.move.x - touch.start.x;
var ydist = touch.move.y - touch.start.y;
///
endx += touch.move.x;
endy += touch.move.y;
start.x += touch.start.x;
start.y += touch.start.y;
length ++;
///
var distance = Math.sqrt(xdist * xdist + ydist * ydist);
var ms = touch.moveTime - touch.startTime;
var degree2 = Math.atan2(xdist, ydist) / RAD_DEG + 180;
var velocity2 = ms ? distance / ms : 0;
if (typeof(degree1) === "undefined") {
degree1 = degree2;
velocity1 = velocity2;
} else if (Math.abs(degree2 - degree1) <= 20) {
degree1 = (degree1 + degree2) / 2;
velocity1 = (velocity1 + velocity2) / 2;
} else {
return;
}
}
///
var fingers = conf.gestureFingers;
if (conf.minFingers <= fingers && conf.maxFingers >= fingers) {
if (velocity1 > conf.threshold) {
start.x /= length;
start.y /= length;
self.start = start;
self.x = endx / length;
self.y = endy / length;
self.angle = -((((degree1 / conf.snap + 0.5) >> 0) * conf.snap || 360) - 360);
self.velocity = velocity1;
self.fingers = fingers;
self.state = "swipe";
conf.listener(event, self);
}
}
}
};
// Generate maintenance commands, and other configurations.
var self = root.pointerSetup(conf);
// Attach events.
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.swipe = root.swipe;
return root;
})(eventjs.proxy);
/*:
"Tap" and "Longpress" event proxy.
----------------------------------------------------
CONFIGURE: delay (longpress), timeout (tap).
----------------------------------------------------
eventjs.add(window, "tap", function(event, self) {
console.log(self.fingers);
});
----------------------------------------------------
multi-finger tap // touch an target for <= 250ms.
multi-finger longpress // touch an target for >= 500ms
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
root.longpress = function(conf) {
conf.gesture = "longpress";
return root.tap(conf);
};
root.tap = function(conf) {
conf.delay = conf.delay || 500;
conf.timeout = conf.timeout || 250;
conf.driftDeviance = conf.driftDeviance || 10;
conf.gesture = conf.gesture || "tap";
// Setting up local variables.
var timestamp, timeout;
// Tracking the events.
conf.onPointerDown = function (event) {
if (root.pointerStart(event, self, conf)) {
timestamp = (new Date()).getTime();
// Initialize event listeners.
eventjs.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
// Make sure this is a "longpress" event.
if (conf.gesture !== "longpress") return;
timeout = setTimeout(function() {
if (event.cancelBubble && ++event.cancelBubbleCount > 1) return;
// Make sure no fingers have been changed.
var fingers = 0;
for (var key in conf.tracker) {
var point = conf.tracker[key];
if (point.end === true) return;
if (conf.cancel) return;
fingers ++;
}
// Send callback.
if (conf.minFingers <= fingers && conf.maxFingers >= fingers) {
self.state = "start";
self.fingers = fingers;
self.x = point.start.x;
self.y = point.start.y;
conf.listener(event, self);
}
}, conf.delay);
}
};
conf.onPointerMove = function (event) {
var bbox = conf.bbox;
var touches = event.changedTouches || root.getCoords(event);
var length = touches.length;
for (var i = 0; i < length; i ++) {
var touch = touches[i];
var identifier = touch.identifier || Infinity;
var pt = conf.tracker[identifier];
if (!pt) continue;
var x = (touch.pageX - bbox.x1 - parseInt(window.scrollX));
var y = (touch.pageY - bbox.y1 - parseInt(window.scrollY));
///
var dx = x - pt.start.x;
var dy = y - pt.start.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (!(x > 0 && x < bbox.width && // Within target coordinates..
y > 0 && y < bbox.height &&
distance <= conf.driftDeviance)) { // Within drift deviance.
// Cancel out this listener.
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
conf.cancel = true;
return;
}
}
};
conf.onPointerUp = function(event) {
if (root.pointerEnd(event, self, conf)) {
clearTimeout(timeout);
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
if (event.cancelBubble && ++event.cancelBubbleCount > 1) return;
// Callback release on longpress.
if (conf.gesture === "longpress") {
if (self.state === "start") {
self.state = "end";
conf.listener(event, self);
}
return;
}
// Cancel event due to movement.
if (conf.cancel) return;
// Ensure delay is within margins.
if ((new Date()).getTime() - timestamp > conf.timeout) return;
// Send callback.
var fingers = conf.gestureFingers;
if (conf.minFingers <= fingers && conf.maxFingers >= fingers) {
self.state = "tap";
self.fingers = conf.gestureFingers;
conf.listener(event, self);
}
}
};
// Generate maintenance commands, and other configurations.
var self = root.pointerSetup(conf);
// Attach events.
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.tap = root.tap;
eventjs.Gesture._gestureHandlers.longpress = root.longpress;
return root;
})(eventjs.proxy);
/*:
"Mouse Wheel" event proxy.
----------------------------------------------------
eventjs.add(window, "wheel", function(event, self) {
console.log(self.state, self.wheelDelta);
});
*/
if (typeof(eventjs) === "undefined") var eventjs = {};
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
eventjs.proxy = (function(root) { "use strict";
root.wheelPreventElasticBounce = function(el) {
if (!el) return;
if (typeof(el) === "string") el = document.querySelector(el);
eventjs.add(el, "wheel", function(event, self) {
self.preventElasticBounce();
eventjs.stop(event);
});
};
root.wheel = function(conf) {
// Configure event listener.
var interval;
var timeout = conf.timeout || 150;
var count = 0;
// Externally accessible data.
var self = {
gesture: "wheel",
state: "start",
wheelDelta: 0,
target: conf.target,
listener: conf.listener,
preventElasticBounce: function(event) {
var target = this.target;
var scrollTop = target.scrollTop;
var top = scrollTop + target.offsetHeight;
var height = target.scrollHeight;
if (top === height && this.wheelDelta <= 0) eventjs.cancel(event);
else if (scrollTop === 0 && this.wheelDelta >= 0) eventjs.cancel(event);
eventjs.stop(event);
},
add: function() {
conf.target[add](type, onMouseWheel, false);
},
remove: function() {
conf.target[remove](type, onMouseWheel, false);
}
};
// Tracking the events.
var onMouseWheel = function(event) {
event = event || window.event;
self.state = count++ ? "change" : "start";
self.wheelDelta = event.detail ? event.detail * -20 : event.wheelDelta;
conf.listener(event, self);
clearTimeout(interval);
interval = setTimeout(function() {
count = 0;
self.state = "end";
self.wheelDelta = 0;
conf.listener(event, self);
}, timeout);
};
// Attach events.
var add = document.addEventListener ? "addEventListener" : "attachEvent";
var remove = document.removeEventListener ? "removeEventListener" : "detachEvent";
var type = eventjs.getEventSupport("mousewheel") ? "mousewheel" : "DOMMouseScroll";
conf.target[add](type, onMouseWheel, false);
// Return this object.
return self;
};
eventjs.Gesture = eventjs.Gesture || {};
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
eventjs.Gesture._gestureHandlers.wheel = root.wheel;
return root;
})(eventjs.proxy);
/*
"Orientation Change"
----------------------------------------------------
https://developer.apple.com/library/safari/documentation/SafariDOMAdditions/Reference/DeviceOrientationEventClassRef/DeviceOrientationEvent/DeviceOrientationEvent.html#//apple_ref/doc/uid/TP40010526
----------------------------------------------------
Event.add(window, "deviceorientation", function(event, self) {});
*/
if (typeof(Event) === "undefined") var Event = {};
if (typeof(Event.proxy) === "undefined") Event.proxy = {};
Event.proxy = (function(root) { "use strict";
root.orientation = function(conf) {
// Externally accessible data.
var self = {
gesture: "orientationchange",
previous: null, /* Report the previous orientation */
current: window.orientation,
target: conf.target,
listener: conf.listener,
remove: function() {
window.removeEventListener('orientationchange', onOrientationChange, false);
}
};
// Tracking the events.
var onOrientationChange = function(e) {
self.previous = self.current;
self.current = window.orientation;
if(self.previous !== null && self.previous != self.current) {
conf.listener(e, self);
return;
}
};
// Attach events.
if (window.DeviceOrientationEvent) {
window.addEventListener("orientationchange", onOrientationChange, false);
}
// Return this object.
return self;
};
Event.Gesture = Event.Gesture || {};
Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
Event.Gesture._gestureHandlers.orientation = root.orientation;
return root;
})(Event.proxy);