diff --git a/src/react/deckgl.js b/src/react/deckgl.js index d887d3b6c25..a0af9a8bbef 100644 --- a/src/react/deckgl.js +++ b/src/react/deckgl.js @@ -138,23 +138,50 @@ export default class DeckGL extends React.Component { events: { click: this._onClick, mousemove: this._onMouseMove, - dragstart: this._onDragEvent, - dragmove: this._onDragEvent, - dragend: this._onDragEvent, - dragcancel: this._onDragCancel + panstart: this._onDragEvent, + panmove: this._onDragEvent, + panend: this._onDragEvent, + pancancel: this._onDragEvent } }); } + // Get mouse position {x, y} relative to the container + _getPos(event) { + const {srcEvent, center, rootElement} = event; + let x; + let y; + + if (center) { + // processed pointer input, supports touch + x = center.x; + y = center.y; + } else if (srcEvent) { + // fallback + x = srcEvent.clientX; + y = srcEvent.clientY; + } + if (!Number.isFinite(x)) { + // srcEvent.clientX may be undefined if it's not from a mouse + return null; + } + + const rect = rootElement.getBoundingClientRect(); + + return { + x: x - rect.left - rootElement.clientLeft, + y: y - rect.top - rootElement.clientTop + }; + } + // Route events to layers _onClick(event) { - // use offsetX|Y for relative position to the container, drop event if falsy - if (!event || !event.srcEvent || !Number.isFinite(event.srcEvent.offsetX)) { + const pos = this._getPos(event); + if (!pos) { return; } - const {srcEvent: {offsetX: x, offsetY: y}} = event; const radius = this.props.pickingRadius; - const selectedInfos = this.layerManager.pickLayer({x, y, radius, mode: 'click'}); + const selectedInfos = this.layerManager.pickLayer({x: pos.x, y: pos.y, radius, mode: 'click'}); if (selectedInfos.length) { const firstInfo = selectedInfos.find(info => info.index >= 0); // Event.event holds the original MouseEvent object @@ -164,13 +191,13 @@ export default class DeckGL extends React.Component { // Route events to layers _onMouseMove(event) { - // use offsetX|Y for relative position to the container, drop event if falsy - if (!event || !event.srcEvent || !Number.isFinite(event.srcEvent.offsetX)) { + const pos = this._getPos(event); + if (!pos || pos.x < 0 || pos.y < 0 || pos.x > this.props.width || pos.y > this.props.height) { + // Check if pointer is inside the canvas return; } - const {srcEvent: {offsetX: x, offsetY: y}} = event; const radius = this.props.pickingRadius; - const selectedInfos = this.layerManager.pickLayer({x, y, radius, mode: 'hover'}); + const selectedInfos = this.layerManager.pickLayer({x: pos.x, y: pos.y, radius, mode: 'hover'}); if (selectedInfos.length) { const firstInfo = selectedInfos.find(info => info.index >= 0); // Event.event holds the original MouseEvent object @@ -178,29 +205,27 @@ export default class DeckGL extends React.Component { } } - _onDragEvent(event, explicitType) { - // use offsetX|Y for relative position to the container, drop event if falsy - if (!event || !event.srcEvent || !Number.isFinite(event.srcEvent.offsetX)) { + _onDragEvent(event) { + const pos = this._getPos(event); + if (!pos) { return; } - const {srcEvent: {offsetX: x, offsetY: y}} = event; - const type = typeof explicitType === 'string' ? explicitType : event.srcEvent.type; let mode; let layerEventHandler; - switch (type) { - case 'mousedown': + switch (event.type) { + case 'panstart': mode = 'dragstart'; layerEventHandler = this.props.onLayerDragStart; break; - case 'mousemove': + case 'panmove': mode = 'dragmove'; layerEventHandler = this.props.onLayerDragMove; break; - case 'dragcancel': + case 'pancancel': mode = 'dragcancel'; layerEventHandler = this.props.onLayerDragCancel; break; - case 'mouseup': + case 'panend': mode = 'dragend'; layerEventHandler = this.props.onLayerDragEnd; break; @@ -211,7 +236,7 @@ export default class DeckGL extends React.Component { if (mode) { const radius = this.props.pickingRadius; - const selectedInfos = this.layerManager.pickLayer({x, y, radius, mode}); + const selectedInfos = this.layerManager.pickLayer({x: pos.x, y: pos.y, radius, mode}); if (selectedInfos.length) { const firstInfo = selectedInfos.find(info => info.index >= 0); // srcEvent holds the original MouseEvent object @@ -220,11 +245,6 @@ export default class DeckGL extends React.Component { } } - _onDragCancel(event) { - // rewrite event type for dragcancel / dragend disambiguation - this._onDragEvent(event, 'dragcancel'); - } - _onRenderFrame({gl}) { const redraw = this.layerManager.needsRedraw({clearRedrawFlags: true}); if (!redraw) { diff --git a/src/utils/events/event-manager.js b/src/utils/events/event-manager.js index 3a1e771826d..b826f8c5183 100644 --- a/src/utils/events/event-manager.js +++ b/src/utils/events/event-manager.js @@ -42,6 +42,7 @@ export default class EventManager { // TODO: support overriding default RECOGNIZERS by passing // recognizers / configs, keyed to event name. + this.element = element; this._onBasicInput = this._onBasicInput.bind(this); this.manager = new Manager(element, {recognizers: RECOGNIZERS}) .on('hammer.input', this._onBasicInput); @@ -144,6 +145,9 @@ export default class EventManager { * See constants.BASIC_EVENT_CLASSES basic event class definitions. */ _onBasicInput(event) { + // For calculating pointer position relative to the canvas + event.rootElement = this.element; + const {srcEvent} = event; const eventAliases = BASIC_EVENT_ALIASES[srcEvent.type]; if (eventAliases) { @@ -160,6 +164,9 @@ export default class EventManager { * and pipe back out through same (Hammer) channel used by other events. */ _onOtherEvent(event) { + // For calculating pointer position relative to the canvas + event.rootElement = this.element; + this.manager.emit(event.type, event); }