galadrielmap_sk
Version:
a server-based chartplotter navigation software for pleasure crafts, motorhomes, and off-road cars. It's can be used on tablets and smartphones without install any app. Only browser need.
266 lines (218 loc) • 9.76 kB
JavaScript
/*!
* long-press-event - v@version@
* Pure JavaScript long-press-event
* https://github.com/john-doherty/long-press-event
* @author John Doherty <www.johndoherty.info>
* @license MIT
*/
(function (window, document) {
'use strict';
// local timer object based on rAF
var timer = null;
// check if we're using a touch screen
var hasPointerEvents = (('PointerEvent' in window) || (window.navigator && 'msPointerEnabled' in window.navigator));
var isTouch = (('ontouchstart' in window) || (navigator.MaxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0));
// switch to pointer events or touch events if using a touch screen
var mouseDown = hasPointerEvents ? 'pointerdown' : isTouch ? 'touchstart' : 'mousedown';
var mouseUp = hasPointerEvents ? 'pointerup' : isTouch ? 'touchend' : 'mouseup';
var mouseMove = hasPointerEvents ? 'pointermove' : isTouch ? 'touchmove' : 'mousemove';
var mouseLeave = hasPointerEvents ? 'pointerleave' : isTouch ? 'touchleave' : 'mouseleave';
// track number of pixels the mouse moves during long press
var startX = 0; // mouse x position when timer started
var startY = 0; // mouse y position when timer started
var maxDiffX = 10; // max number of X pixels the mouse can move during long press before it is canceled
var maxDiffY = 10; // max number of Y pixels the mouse can move during long press before it is canceled
// patch CustomEvent to allow constructor creation (IE/Chrome)
if (typeof window.CustomEvent !== 'function') {
window.CustomEvent = function (event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
window.CustomEvent.prototype = window.Event.prototype;
}
// requestAnimationFrame() shim by Paul Irish
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
/**
* Behaves the same as setTimeout except uses requestAnimationFrame() where possible for better performance
* @param {function} fn The callback function
* @param {int} delay The delay in milliseconds
* @returns {object} handle to the timeout object
*/
function requestTimeout(fn, delay) {
if (!window.requestAnimationFrame && !window.webkitRequestAnimationFrame &&
!(window.mozRequestAnimationFrame && window.mozCancelRequestAnimationFrame) && // Firefox 5 ships without cancel support
!window.oRequestAnimationFrame && !window.msRequestAnimationFrame) return window.setTimeout(fn, delay);
var start = new Date().getTime();
var handle = {};
var loop = function () {
var current = new Date().getTime();
var delta = current - start;
if (delta >= delay) {
fn.call();
}
else {
handle.value = requestAnimFrame(loop);
}
};
handle.value = requestAnimFrame(loop);
return handle;
}
/**
* Behaves the same as clearTimeout except uses cancelRequestAnimationFrame() where possible for better performance
* @param {object} handle The callback function
* @returns {void}
*/
function clearRequestTimeout(handle) {
if (handle) {
window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) :
window.webkitCancelAnimationFrame ? window.webkitCancelAnimationFrame(handle.value) :
window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) : /* Support for legacy API */
window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) :
window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) :
window.msCancelRequestAnimationFrame ? window.msCancelRequestAnimationFrame(handle.value) :
clearTimeout(handle);
}
}
/**
* Fires the 'long-press' event on element
* @param {MouseEvent|PointerEvent|TouchEvent} originalEvent The original event being fired
* @returns {void}
*/
function fireLongPressEvent(originalEvent) {
clearLongPressTimer();
originalEvent = unifyEvent(originalEvent);
// fire the long-press event
var allowClickEvent = this.dispatchEvent(new CustomEvent('long-press', {
bubbles: true,
cancelable: true,
// custom event data (legacy)
detail: {
clientX: originalEvent.clientX,
clientY: originalEvent.clientY,
offsetX: originalEvent.offsetX,
offsetY: originalEvent.offsetY,
pageX: originalEvent.pageX,
pageY: originalEvent.pageY
},
// add coordinate data that would typically acompany a touch/click event
clientX: originalEvent.clientX,
clientY: originalEvent.clientY,
offsetX: originalEvent.offsetX,
offsetY: originalEvent.offsetY,
pageX: originalEvent.pageX,
pageY: originalEvent.pageY,
screenX: originalEvent.screenX,
screenY: originalEvent.screenY
}));
if (!allowClickEvent) {
// suppress the next click event if e.preventDefault() was called in long-press handler
document.addEventListener('click', function suppressEvent(e) {
document.removeEventListener('click', suppressEvent, true);
cancelEvent(e);
}, true);
}
}
/**
* consolidates mouse, touch, and Pointer events
* @param {MouseEvent|PointerEvent|TouchEvent} e The original event being fired
* @returns {MouseEvent|PointerEvent|Touch}
*/
function unifyEvent(e) {
if (e.changedTouches !== undefined) {
return e.changedTouches[0];
}
return e;
}
/**
* method responsible for starting the long press timer
* @param {event} e - event object
* @returns {void}
*/
function startLongPressTimer(e) {
clearLongPressTimer(e);
var el = e.target;
// get delay from html attribute if it exists, otherwise default to 1500
var longPressDelayInMs = parseInt(getNearestAttribute(el, 'data-long-press-delay', '1500'), 10); // default 1500
// start the timer
timer = requestTimeout(fireLongPressEvent.bind(el, e), longPressDelayInMs);
}
/**
* method responsible for clearing a pending long press timer
* @param {event} e - event object
* @returns {void}
*/
function clearLongPressTimer(e) {
clearRequestTimeout(timer);
timer = null;
}
/**
* Cancels the current event
* @param {object} e - browser event object
* @returns {void}
*/
function cancelEvent(e) {
e.stopImmediatePropagation();
e.preventDefault();
e.stopPropagation();
}
/**
* Starts the timer on mouse down and logs current position
* @param {object} e - browser event object
* @returns {void}
*/
function mouseDownHandler(e) {
startX = e.clientX;
startY = e.clientY;
startLongPressTimer(e);
}
/**
* If the mouse moves n pixels during long-press, cancel the timer
* @param {object} e - browser event object
* @returns {void}
*/
function mouseMoveHandler(e) {
// calculate total number of pixels the pointer has moved
var diffX = Math.abs(startX - e.clientX);
var diffY = Math.abs(startY - e.clientY);
// if pointer has moved more than allowed, cancel the long-press timer and therefore the event
if (diffX >= maxDiffX || diffY >= maxDiffY) {
clearLongPressTimer(e);
}
}
/**
* Gets attribute off HTML element or nearest parent
* @param {object} el - HTML element to retrieve attribute from
* @param {string} attributeName - name of the attribute
* @param {any} defaultValue - default value to return if no match found
* @returns {any} attribute value or defaultValue
*/
function getNearestAttribute(el, attributeName, defaultValue) {
// walk up the dom tree looking for data-action and data-trigger
while (el && el !== document.documentElement) {
var attributeValue = el.getAttribute(attributeName);
if (attributeValue) {
return attributeValue;
}
el = el.parentNode;
}
return defaultValue;
}
// hook events that clear a pending long press event
document.addEventListener(mouseUp, clearLongPressTimer, true);
document.addEventListener(mouseLeave, clearLongPressTimer, true);
document.addEventListener(mouseMove, mouseMoveHandler, true);
document.addEventListener('wheel', clearLongPressTimer, true);
document.addEventListener('scroll', clearLongPressTimer, true);
// hook events that can trigger a long press event
document.addEventListener(mouseDown, mouseDownHandler, true); // <- start
}(window, document));