UNPKG

awv3

Version:
180 lines (159 loc) 5.96 kB
import * as Error from './error'; import Events from './events'; function createStates(dom, events, listener, options = undefined) { return events.reduce( (prev, name) => { dom.addEventListener(name, listener, options); return { ...prev, [name]: { type: name, fulfilled: false, detach: () => dom.removeEventListener(name, listener) } }; }, {} ); } export default class Dom { constructor(view = Error.log('View undefined'), handlers = {}) { this.view = view; this.canvas = view.canvas; this.renderer = view.renderer; this.dom = view.dom; this.recent = []; this.enabled = true; this.debounce = true; // Mix in event generic handler Events.mixin(this, handlers); // Add internal dom event handlers this.eventHandler = this.handleEvent.bind(this); this.eventHandlerDefault = this.handleEventDefault.bind(this); let passiveStates = createStates( this.dom, ['mousedown', 'mouseup', 'mousemove', 'mouseout'], this.eventHandler, { passive: true } ); let standardStates = createStates( this.dom, ['touchstart', 'touchmove', 'touchend', 'wheel'], this.eventHandlerDefault, { passive: false } ); let globalStates = createStates( document, ['keydown', 'keyup'], this.eventHandler, { passive: true } ); this.states = { ...passiveStates, ...standardStates, ...globalStates }; // Common last-state-data can be accessed here this.mouse = {}; this.wheel = {}; this.touch = {}; this.keys = {}; // Array of changes to be called on next update this.changes = []; } // This seems to be buggy, doesn't detach mouse event handlers for some weird reason detach() { for (let key in this.states) this.states[key].detach(); } update() { if (this.changes.length > 0) { for (let change of this.changes) { this.emit(change.type, change); change.fulfilled = false; } this.changes = []; } } handleEventDefault(event) { event.preventDefault(); this.handleEvent(event); } handleEvent(event) { if (!this.enabled) return; let { type, pageX, pageY, clientX, clientY, button, which, deltaMode, deltaY } = event; let state = this.states[type]; if (this.debounce && state.fulfilled) return; // Wheel state.delta = deltaY * (deltaMode ? -1 : -0.03); // Generic state.fulfilled = true; state.pageX = pageX; state.pageY = pageY; state.clientX = clientX; state.clientY = clientY; state.offsetX = pageX - this.renderer.offset.left - this.view.left; state.offsetY = pageY - this.renderer.offset.top - this.view.top; // Touch state.touches = []; if (!!event.touches) { for (let item of [].slice.call(event.touches)) { pageX = item.pageX; pageY = item.pageY; clientX = item.clientX; clientY = item.clientY; state.touches.push({ clientX: clientX, clientY: clientY, offsetX: pageX - this.renderer.offset.left - this.view.left, offsetY: pageY - this.renderer.offset.top - this.view.top, pageX: pageX, pageY: pageY }); } state.touch = true; state.multitouch = state.touches.length > 1; if (state.touches.length > 0) { state.offsetX = this.touch.offsetX = state.touches[0].offsetX; state.offsetY = this.touch.offsetX = state.touches[0].offsetY; } else { state.offsetX = this.touch.offsetX; state.offsetY = this.touch.offsetX; } } state.button = button; state.which = which; state.event = event; this.changes.push(state); const keyToName = { 16: "shift", 17: "control", 18: "alt", }; if (type === 'mousedown') { this.mouse.down = true; this.mouse.button = button; document.addEventListener('mouseup', this.eventHandlerDefault, false); document.addEventListener('mousemove', this.eventHandlerDefault, false); } else if (type === 'mouseup') { this.mouse.down = false; this.mouse.button = button; document.removeEventListener('mouseup', this.eventHandlerDefault); document.removeEventListener('mousemove', this.eventHandlerDefault); } else if (type === 'touchstart') { this.touch.down = true; document.addEventListener('touchend', this.eventHandlerDefault, false); document.addEventListener('touchmove', this.eventHandlerDefault, false); } else if (type === 'touchend') { this.touch.down = false; document.removeEventListener('touchend', this.eventHandlerDefault); document.removeEventListener('touchmove', this.eventHandlerDefault); } else if (type === 'keydown') { let name = keyToName[which]; if (name) this.keys[name] = true; } else if (type === 'keyup') { let name = keyToName[which]; if (name) this.keys[name] = false; } this.recent[state.type] = state; if (!this.debounce) this.update(); } }