UNPKG

@visactor/vrender-kits

Version:
194 lines (189 loc) 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: !0 }), exports.Gesture = void 0; const vrender_core_1 = require("@visactor/vrender-core"), vutils_1 = require("@visactor/vutils"), PRESS_TIME = 251, PRESS_THRESHOLD = 9, SWIPE_VELOCITY = .3, SWIPE_THRESHOLD = 10, TAP_INTERVAL = 300, calcDirection = (start, end) => { const xDistance = end.x - start.x, yDistance = end.y - start.y; return Math.abs(xDistance) > Math.abs(yDistance) ? xDistance > 0 ? "right" : "left" : yDistance > 0 ? "down" : "up"; }, calcDistance = (point1, point2) => { const xDistance = Math.abs(point2.x - point1.x), yDistance = Math.abs(point2.y - point1.y); return Math.sqrt(xDistance * xDistance + yDistance * yDistance); }, getCenter = points => { const pointersLength = points.length; if (1 === pointersLength) return { x: Math.round(points[0].x), y: Math.round(points[0].y) }; let x = 0, y = 0, i = 0; for (;i < pointersLength; ) x += points[i].x, y += points[i].y, i++; return { x: Math.round(x / pointersLength), y: Math.round(y / pointersLength) }; }; class Gesture extends vutils_1.EventEmitter { constructor(element, config = {}) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; super(), this.cachedEvents = [], this.startPoints = [], this.processEvent = {}, this.throttleTimer = 0, this.emitThrottles = [], this.lastTapTarget = null, this.onStart = ev => { this.startTime = vrender_core_1.clock.now(); const {cachedEvents: cachedEvents, startPoints: startPoints} = this; ev && cachedEvents.push(ev.clone()), startPoints.length = cachedEvents.length; for (let i = 0; i < cachedEvents.length; i++) { const {x: x, y: y} = cachedEvents[i], point = { x: x, y: y }; startPoints[i] = point; } if (1 !== startPoints.length) this.startDistance = calcDistance(startPoints[0], startPoints[1]), this.center = getCenter([ startPoints[0], startPoints[1] ]); else { const event = cachedEvents[0]; this.pressTimeout = setTimeout((() => { event.direction = "none", event.deltaX = 0, event.deltaY = 0, event.points = startPoints, this.triggerStartEvent("press", event), this.triggerEvent("press", event), this.eventType = "press", this.direction = "none", this.pressTimeout = null; }), this.config.press.time); } }, this.onMove = ev => { this.clearPressTimeout(); const {startPoints: startPoints, cachedEvents: cachedEvents} = this; if (!startPoints.length) return; const moveEvent = ev.clone(), {x: x, y: y, pointerId: pointerId} = moveEvent; for (let i = 0, len = cachedEvents.length; i < len; i++) if (pointerId === cachedEvents[i].pointerId) { cachedEvents[i] = moveEvent; break; } const point = { x: x, y: y }, points = cachedEvents.map((cachedEvent => ({ x: cachedEvent.x, y: cachedEvent.y }))), now = vrender_core_1.clock.now(); if (this.prevMoveTime = this.lastMoveTime, this.prevMovePoint = this.lastMovePoint, this.lastMoveTime = now, this.lastMovePoint = point, 1 === startPoints.length) { const startPoint = startPoints[0], deltaX = x - startPoint.x, deltaY = y - startPoint.y, direction = this.direction || calcDirection(startPoint, point); this.direction = direction; const eventType = this.getEventType(point); return moveEvent.direction = direction, moveEvent.deltaX = deltaX, moveEvent.deltaY = deltaY, moveEvent.points = points, this.triggerStartEvent(eventType, moveEvent), void this.triggerEvent(eventType, moveEvent); } const {startDistance: startDistance} = this, currentDistance = calcDistance(points[0], points[1]); moveEvent.scale = currentDistance / startDistance, moveEvent.center = this.center, moveEvent.points = points, this.triggerStartEvent("pinch", moveEvent), this.triggerEvent("pinch", moveEvent); }, this.onEnd = ev => { const endEvent = ev.clone(), {cachedEvents: cachedEvents, startPoints: startPoints} = this, points = cachedEvents.map((ev => ({ x: ev.x, y: ev.y }))); if (endEvent.points = points, this.triggerEndEvent(endEvent), 1 === cachedEvents.length) { const now = vrender_core_1.clock.now(), lastMoveTime = this.lastMoveTime; if (now - lastMoveTime < 100) { const intervalTime = lastMoveTime - (this.prevMoveTime || this.startTime); if (intervalTime > 0) { const prevMovePoint = this.prevMovePoint || startPoints[0], lastMovePoint = this.lastMovePoint || startPoints[0], distance = calcDistance(prevMovePoint, lastMovePoint), velocity = distance / intervalTime; if (velocity > this.config.swipe.velocity && distance > this.config.swipe.threshold) return endEvent.velocity = velocity, endEvent.direction = calcDirection(prevMovePoint, lastMovePoint), this.triggerEvent("swipe", endEvent), this.cachedEvents = [], this.startPoints = [], void this.reset(); } } now - this.startTime < this.config.press.time && (now - this.lastTapTime < this.config.tap.interval && ev.target === this.lastTapTarget ? this.tapCount++ : this.tapCount = 1, this.lastTapTime = now, this.lastTapTarget = ev.target, 1 === this.tapCount ? this.triggerEvent("tap", endEvent) : 2 === this.tapCount && (this.triggerEvent("doubletap", endEvent), this.tapCount = 0)); } for (let i = 0, len = cachedEvents.length; i < len; i++) if (cachedEvents[i].pointerId === endEvent.pointerId) { cachedEvents.splice(i, 1), startPoints.splice(i, 1); break; } this.reset(), cachedEvents.length > 0 && this.onStart(); }, this.element = element, this.tapCount = 0, this.lastTapTime = 0, this.config = { press: { time: null !== (_b = null === (_a = null == config ? void 0 : config.press) || void 0 === _a ? void 0 : _a.time) && void 0 !== _b ? _b : 251, threshold: null !== (_d = null === (_c = null == config ? void 0 : config.press) || void 0 === _c ? void 0 : _c.threshold) && void 0 !== _d ? _d : 9 }, swipe: { threshold: null !== (_f = null === (_e = null == config ? void 0 : config.swipe) || void 0 === _e ? void 0 : _e.threshold) && void 0 !== _f ? _f : 10, velocity: null !== (_h = null === (_g = null == config ? void 0 : config.swipe) || void 0 === _g ? void 0 : _g.velocity) && void 0 !== _h ? _h : .3 }, tap: { interval: null !== (_k = null === (_j = null == config ? void 0 : config.tap) || void 0 === _j ? void 0 : _j.interval) && void 0 !== _k ? _k : 300 } }, this.initEvents(); } initEvents() { const {element: element} = this; element && (element.addEventListener("pointerdown", this.onStart), element.addEventListener("pointermove", this.onMove), element.addEventListener("pointerup", this.onEnd), element.addEventListener("pointerleave", this.onEnd), element.addEventListener("pointerupoutside", this.onEnd)); } removeEvents() { const {element: element} = this; element && (element.removeEventListener("pointerdown", this.onStart), element.removeEventListener("pointermove", this.onMove), element.removeEventListener("pointerup", this.onEnd), element.removeEventListener("pointerleave", this.onEnd), element.removeEventListener("pointerupoutside", this.onEnd)); } release() { this.removeEvents(), this.element = null; } getEventType(point) { const {eventType: eventType, startTime: startTime, startPoints: startPoints} = this; if ("press" === eventType) return eventType; let type; return type = vrender_core_1.clock.now() - startTime > this.config.press.time && calcDistance(startPoints[0], point) < this.config.press.threshold ? "press" : "pan", this.eventType = type, type; } enable(eventType) { this.processEvent[eventType] = !0; } isProcess(eventType) { return this.processEvent[eventType]; } pushEvent(type, ev) { const {emitThrottles: emitThrottles} = this, newEvent = { type: type, ev: ev }; for (let i = 0, len = emitThrottles.length; i < len; i++) if (emitThrottles[i].type === type) return void emitThrottles.splice(i, 1, newEvent); emitThrottles.push(newEvent); } clearPressTimeout() { this.pressTimeout && (clearTimeout(this.pressTimeout), this.pressTimeout = null); } reset() { this.clearPressTimeout(), this.startTime = 0, this.startDistance = 0, this.direction = null, this.eventType = null, this.prevMoveTime = 0, this.prevMovePoint = null, this.lastMoveTime = 0, this.lastMovePoint = null; } triggerEvent(type, ev) { this.pushEvent(type, ev); const {throttleTimer: throttleTimer, emitThrottles: emitThrottles} = this; throttleTimer || (this.throttleTimer = vrender_core_1.application.global.getRequestAnimationFrame()((() => { vrender_core_1.application.global.getCancelAnimationFrame()(this.throttleTimer), this.throttleTimer = null; for (let i = 0, len = emitThrottles.length; i < len; i++) { const {type: type, ev: ev} = emitThrottles[i]; this.emitEvent(type, ev); } this.emitThrottles.length = 0; }))); } triggerStartEvent(type, ev) { this.isProcess(type) || (this.enable(type), this.triggerEvent(`${type}start`, ev)); } triggerEndEvent(ev) { const processEvent = this.processEvent; Object.keys(processEvent).forEach((type => { this.triggerEvent(`${type}end`, ev), "press" === type && this.triggerEvent(`${type}up`, ev), delete processEvent[type]; })); } emitEvent(type, e) { if (!this.element) return; const listeners = this.element._events[vrender_core_1.WILDCARD]; if (listeners) if ("fn" in listeners) listeners.fn.call(listeners.context, e, type); else for (let i = 0, j = listeners.length; i < j && !e.propagationImmediatelyStopped; i++) listeners[i].fn.call(listeners[i].context, e, type); this.emit(type, e); } } exports.Gesture = Gesture; //# sourceMappingURL=gesture.js.map