mirror of https://github.com/ColorlibHQ/gentelella
321 lines
11 KiB
JavaScript
321 lines
11 KiB
JavaScript
|
|
/* global jQuery */
|
|
|
|
(function($) {
|
|
'use strict';
|
|
|
|
var options = {
|
|
propagateSupportedGesture: false
|
|
};
|
|
|
|
function init(plot) {
|
|
plot.hooks.processOptions.push(initTouchNavigation);
|
|
}
|
|
|
|
function initTouchNavigation(plot, options) {
|
|
var gestureState = {
|
|
twoTouches: false,
|
|
currentTapStart: { x: 0, y: 0 },
|
|
currentTapEnd: { x: 0, y: 0 },
|
|
prevTap: { x: 0, y: 0 },
|
|
currentTap: { x: 0, y: 0 },
|
|
interceptedLongTap: false,
|
|
isUnsupportedGesture: false,
|
|
prevTapTime: null,
|
|
tapStartTime: null,
|
|
longTapTriggerId: null
|
|
},
|
|
maxDistanceBetweenTaps = 20,
|
|
maxIntervalBetweenTaps = 500,
|
|
maxLongTapDistance = 20,
|
|
minLongTapDuration = 1500,
|
|
pressedTapDuration = 125,
|
|
mainEventHolder;
|
|
|
|
function interpretGestures(e) {
|
|
var o = plot.getOptions();
|
|
|
|
if (!o.pan.active && !o.zoom.active) {
|
|
return;
|
|
}
|
|
|
|
updateOnMultipleTouches(e);
|
|
mainEventHolder.dispatchEvent(new CustomEvent('touchevent', { detail: e }));
|
|
|
|
if (isPinchEvent(e)) {
|
|
executeAction(e, 'pinch');
|
|
} else {
|
|
executeAction(e, 'pan');
|
|
if (!wasPinchEvent(e)) {
|
|
if (isDoubleTap(e)) {
|
|
executeAction(e, 'doubleTap');
|
|
}
|
|
executeAction(e, 'tap');
|
|
executeAction(e, 'longTap');
|
|
}
|
|
}
|
|
}
|
|
|
|
function executeAction(e, gesture) {
|
|
switch (gesture) {
|
|
case 'pan':
|
|
pan[e.type](e);
|
|
break;
|
|
case 'pinch':
|
|
pinch[e.type](e);
|
|
break;
|
|
case 'doubleTap':
|
|
doubleTap.onDoubleTap(e);
|
|
break;
|
|
case 'longTap':
|
|
longTap[e.type](e);
|
|
break;
|
|
case 'tap':
|
|
tap[e.type](e);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function bindEvents(plot, eventHolder) {
|
|
mainEventHolder = eventHolder[0];
|
|
eventHolder[0].addEventListener('touchstart', interpretGestures, false);
|
|
eventHolder[0].addEventListener('touchmove', interpretGestures, false);
|
|
eventHolder[0].addEventListener('touchend', interpretGestures, false);
|
|
}
|
|
|
|
function shutdown(plot, eventHolder) {
|
|
eventHolder[0].removeEventListener('touchstart', interpretGestures);
|
|
eventHolder[0].removeEventListener('touchmove', interpretGestures);
|
|
eventHolder[0].removeEventListener('touchend', interpretGestures);
|
|
if (gestureState.longTapTriggerId) {
|
|
clearTimeout(gestureState.longTapTriggerId);
|
|
gestureState.longTapTriggerId = null;
|
|
}
|
|
}
|
|
|
|
var pan = {
|
|
touchstart: function(e) {
|
|
updatePrevForDoubleTap();
|
|
updateCurrentForDoubleTap(e);
|
|
updateStateForLongTapStart(e);
|
|
|
|
mainEventHolder.dispatchEvent(new CustomEvent('panstart', { detail: e }));
|
|
},
|
|
|
|
touchmove: function(e) {
|
|
preventEventBehaviors(e);
|
|
|
|
updateCurrentForDoubleTap(e);
|
|
updateStateForLongTapEnd(e);
|
|
|
|
if (!gestureState.isUnsupportedGesture) {
|
|
mainEventHolder.dispatchEvent(new CustomEvent('pandrag', { detail: e }));
|
|
}
|
|
},
|
|
|
|
touchend: function(e) {
|
|
preventEventBehaviors(e);
|
|
|
|
if (wasPinchEvent(e)) {
|
|
mainEventHolder.dispatchEvent(new CustomEvent('pinchend', { detail: e }));
|
|
mainEventHolder.dispatchEvent(new CustomEvent('panstart', { detail: e }));
|
|
} else if (noTouchActive(e)) {
|
|
mainEventHolder.dispatchEvent(new CustomEvent('panend', { detail: e }));
|
|
}
|
|
}
|
|
};
|
|
|
|
var pinch = {
|
|
touchstart: function(e) {
|
|
mainEventHolder.dispatchEvent(new CustomEvent('pinchstart', { detail: e }));
|
|
},
|
|
|
|
touchmove: function(e) {
|
|
preventEventBehaviors(e);
|
|
gestureState.twoTouches = isPinchEvent(e);
|
|
if (!gestureState.isUnsupportedGesture) {
|
|
mainEventHolder.dispatchEvent(new CustomEvent('pinchdrag', { detail: e }));
|
|
}
|
|
},
|
|
|
|
touchend: function(e) {
|
|
preventEventBehaviors(e);
|
|
}
|
|
};
|
|
|
|
var doubleTap = {
|
|
onDoubleTap: function(e) {
|
|
preventEventBehaviors(e);
|
|
mainEventHolder.dispatchEvent(new CustomEvent('doubletap', { detail: e }));
|
|
}
|
|
};
|
|
|
|
var longTap = {
|
|
touchstart: function(e) {
|
|
longTap.waitForLongTap(e);
|
|
},
|
|
|
|
touchmove: function(e) {
|
|
},
|
|
|
|
touchend: function(e) {
|
|
if (gestureState.longTapTriggerId) {
|
|
clearTimeout(gestureState.longTapTriggerId);
|
|
gestureState.longTapTriggerId = null;
|
|
}
|
|
},
|
|
|
|
isLongTap: function(e) {
|
|
var currentTime = new Date().getTime(),
|
|
tapDuration = currentTime - gestureState.tapStartTime;
|
|
if (tapDuration >= minLongTapDuration && !gestureState.interceptedLongTap) {
|
|
if (distance(gestureState.currentTapStart.x, gestureState.currentTapStart.y, gestureState.currentTapEnd.x, gestureState.currentTapEnd.y) < maxLongTapDistance) {
|
|
gestureState.interceptedLongTap = true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
waitForLongTap: function(e) {
|
|
var longTapTrigger = function() {
|
|
if (longTap.isLongTap(e)) {
|
|
mainEventHolder.dispatchEvent(new CustomEvent('longtap', { detail: e }));
|
|
}
|
|
gestureState.longTapTriggerId = null;
|
|
};
|
|
if (!gestureState.longTapTriggerId) {
|
|
gestureState.longTapTriggerId = setTimeout(longTapTrigger, minLongTapDuration);
|
|
}
|
|
}
|
|
};
|
|
|
|
var tap = {
|
|
touchstart: function(e) {
|
|
gestureState.tapStartTime = new Date().getTime();
|
|
},
|
|
|
|
touchmove: function(e) {
|
|
},
|
|
|
|
touchend: function(e) {
|
|
if (tap.isTap(e)) {
|
|
mainEventHolder.dispatchEvent(new CustomEvent('tap', { detail: e }));
|
|
preventEventBehaviors(e);
|
|
}
|
|
},
|
|
|
|
isTap: function(e) {
|
|
var currentTime = new Date().getTime(),
|
|
tapDuration = currentTime - gestureState.tapStartTime;
|
|
if (tapDuration <= pressedTapDuration) {
|
|
if (distance(gestureState.currentTapStart.x, gestureState.currentTapStart.y, gestureState.currentTapEnd.x, gestureState.currentTapEnd.y) < maxLongTapDistance) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
if (options.pan.enableTouch === true || options.zoom.enableTouch) {
|
|
plot.hooks.bindEvents.push(bindEvents);
|
|
plot.hooks.shutdown.push(shutdown);
|
|
};
|
|
|
|
function updatePrevForDoubleTap() {
|
|
gestureState.prevTap = {
|
|
x: gestureState.currentTap.x,
|
|
y: gestureState.currentTap.y
|
|
};
|
|
};
|
|
|
|
function updateCurrentForDoubleTap(e) {
|
|
gestureState.currentTap = {
|
|
x: e.touches[0].pageX,
|
|
y: e.touches[0].pageY
|
|
};
|
|
}
|
|
|
|
function updateStateForLongTapStart(e) {
|
|
gestureState.tapStartTime = new Date().getTime();
|
|
gestureState.interceptedLongTap = false;
|
|
gestureState.currentTapStart = {
|
|
x: e.touches[0].pageX,
|
|
y: e.touches[0].pageY
|
|
};
|
|
gestureState.currentTapEnd = {
|
|
x: e.touches[0].pageX,
|
|
y: e.touches[0].pageY
|
|
};
|
|
};
|
|
|
|
function updateStateForLongTapEnd(e) {
|
|
gestureState.currentTapEnd = {
|
|
x: e.touches[0].pageX,
|
|
y: e.touches[0].pageY
|
|
};
|
|
};
|
|
|
|
function isDoubleTap(e) {
|
|
var currentTime = new Date().getTime(),
|
|
intervalBetweenTaps = currentTime - gestureState.prevTapTime;
|
|
|
|
if (intervalBetweenTaps >= 0 && intervalBetweenTaps < maxIntervalBetweenTaps) {
|
|
if (distance(gestureState.prevTap.x, gestureState.prevTap.y, gestureState.currentTap.x, gestureState.currentTap.y) < maxDistanceBetweenTaps) {
|
|
e.firstTouch = gestureState.prevTap;
|
|
e.secondTouch = gestureState.currentTap;
|
|
return true;
|
|
}
|
|
}
|
|
gestureState.prevTapTime = currentTime;
|
|
return false;
|
|
}
|
|
|
|
function preventEventBehaviors(e) {
|
|
if (!gestureState.isUnsupportedGesture) {
|
|
e.preventDefault();
|
|
if (!plot.getOptions().propagateSupportedGesture) {
|
|
e.stopPropagation();
|
|
}
|
|
}
|
|
}
|
|
|
|
function distance(x1, y1, x2, y2) {
|
|
return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
|
}
|
|
|
|
function noTouchActive(e) {
|
|
return (e.touches && e.touches.length === 0);
|
|
}
|
|
|
|
function wasPinchEvent(e) {
|
|
return (gestureState.twoTouches && e.touches.length === 1);
|
|
}
|
|
|
|
function updateOnMultipleTouches(e) {
|
|
if (e.touches.length >= 3) {
|
|
gestureState.isUnsupportedGesture = true;
|
|
} else {
|
|
gestureState.isUnsupportedGesture = false;
|
|
}
|
|
}
|
|
|
|
function isPinchEvent(e) {
|
|
if (e.touches && e.touches.length >= 2) {
|
|
if (e.touches[0].target === plot.getEventHolder() &&
|
|
e.touches[1].target === plot.getEventHolder()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$.plot.plugins.push({
|
|
init: init,
|
|
options: options,
|
|
name: 'navigateTouch',
|
|
version: '0.3'
|
|
});
|
|
})(jQuery);
|