Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: if no next interact was present, we would not get events #47

Merged
merged 2 commits into from
Mar 31, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions js/lib/MouseInteraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ const _ = require("lodash");
const d3_selection_1 = require("d3-selection");
const d3GetEvent = function () { return require("d3-selection").event; }.bind(this);

const clickEvents = ['click', 'dblclick', 'mouseenter', 'mouseleave', 'contextmenu'];
const keyEvents = ['keydown', 'keyup'];
const throttledEvents = ['mousemove'];
const dragEvents = ['start', 'drag', 'end'];

class MouseInteractionModel extends base_1.WidgetModel {
defaults() {
return Object.assign({}, base_1.WidgetModel.prototype.defaults(), {
Expand All @@ -36,7 +41,6 @@ exports.MouseInteractionModel = MouseInteractionModel;
class MouseInteraction extends Interaction_1.Interaction {
async render() {
super.render();
this.el.setAttribute('display', 'none');
this.eventElement = d3.select(this.parent.interaction.node());
this.nextView = null;
this.x_scale = await this.create_child_view(this.model.get("x_scale"));
Expand All @@ -57,28 +61,30 @@ class MouseInteraction extends Interaction_1.Interaction {
this.listenTo(this.model, 'change:move_throttle', updateThrottle);

this.bindEvents();
await this.updateNextInteract();
// no await for this async function, because otherwise we want for
// this.displayed, which will never happen before render resolves
this.updateNextInteract();
}

bindEvents() {
const events = this.model.get("events");
// we don't want to bind these events if we don't need them, because drag events
// can call stop propagation
if (this.eventEnabled("dragstart") && this.eventEnabled("dragmove") && this.eventEnabled("dragend")) {
this.eventElement.call(d3_drag_1.drag().on("start", () => {
this.eventElement.call(d3_drag_1.drag().on(this._eventName("start"), () => {
const e = d3GetEvent();
this._emit('dragstart', { x: e.x, y: e.y });
}).on("drag", () => {
}).on(this._eventName("drag"), () => {
const e = d3GetEvent();
this._emit('dragmove', { x: e.x, y: e.y });
}).on("end", () => {
}).on(this._eventName("end"), () => {
const e = d3GetEvent();
this._emit('dragend', { x: e.x, y: e.y });
}));
}
// and click events
['click', 'dblclick', 'mouseenter', 'mouseleave', 'contextmenu'].forEach(eventName => {
this.eventElement.on(eventName, () => {
clickEvents.forEach(eventName => {
this.eventElement.on(this._eventName(eventName), () => {
this._emitThrottled.flush(); // we don't want mousemove events to come after enter/leave
if (eventName !== 'mouseleave') {
// to allow the div to get focus, but we will not allow it to be reachable by tab key
Expand All @@ -102,8 +108,8 @@ class MouseInteraction extends Interaction_1.Interaction {
return false
});
});
['keydown', 'keyup'].forEach(eventName => {
d3.select(this.parent.el).on(eventName, () => {
keyEvents.forEach(eventName => {
d3.select(this.parent.el).on(this._eventName(eventName), () => {
this._emitThrottled.flush(); // we don't want mousemove events to come after enter/leave
const e = d3GetEvent();
// to be consistent with drag events, we need to user clientPoint
Expand All @@ -116,8 +122,8 @@ class MouseInteraction extends Interaction_1.Interaction {
});
});
// throttled events
['mousemove'].forEach(eventName => {
this.eventElement.on(eventName, () => {
throttledEvents.forEach(eventName => {
this.eventElement.on(this._eventName(eventName), () => {
const e = d3GetEvent();
// to be consistent with drag events, we need to user clientPoint
const [x, y] = d3_selection_1.clientPoint(this.eventElement.node(), e);
Expand All @@ -127,13 +133,30 @@ class MouseInteraction extends Interaction_1.Interaction {
});
}

_eventName(name) {
// using namespaced event names (e.g. click.view123) to support multiple
// listeners on the same DOM element (our parent interaction node)
return `${name}.${this.cid}`
}

unbindEvents() {
const off = (name) => this.eventElement.on(this._eventName(name), null);
clickEvents.forEach(off);
keyEvents.forEach(off);
throttledEvents.forEach(off);
dragEvents.forEach(off);
}

eventEnabled(eventName) {
const events = this.model.get("events");
return (events == null) || events.includes(eventName);
}

async updateNextInteract() {
// this mimics Figure.set_iteraction
// but we want the 'next' interaction to be added after we are added
// to the DOM, so we don't steal all mouse events
await this.displayed;
const next = this.model.get('next')
if(this.nextView) {
this.nextView.remove();
Expand All @@ -154,6 +177,10 @@ class MouseInteraction extends Interaction_1.Interaction {
}
remove() {
super.remove();
if(this.nextView) {
this.nextView.remove();
}
this.unbindEvents();
this.parent.off('margin_updated', this.updateScaleRanges);
this.parent.el.removeAttribute("tabindex");
this._emitThrottled.flush();
Expand Down