Skip to content

Commit

Permalink
Event handling bug fixes (visgl#669)
Browse files Browse the repository at this point in the history
* fix error when mousemove is triggered outside of the canvas
* fix drag events
  • Loading branch information
Pessimistress authored May 31, 2017
1 parent b8e18ad commit fa6550a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 28 deletions.
76 changes: 48 additions & 28 deletions src/react/deckgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -164,43 +191,41 @@ 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
this.props.onLayerHover(firstInfo, selectedInfos, event.srcEvent);
}
}

_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;
Expand All @@ -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
Expand All @@ -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) {
Expand Down
7 changes: 7 additions & 0 deletions src/utils/events/event-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}

Expand Down

0 comments on commit fa6550a

Please sign in to comment.