UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

121 lines 4.39 kB
import { SelectTool, SelectToolView } from "./select_tool"; import { Modifiers, satisfies_modifiers } from "./common"; import { MenuItem } from "../../ui/menus"; import { execute } from "../../../core/util/callbacks"; import { SelectionMode } from "../../../core/enums"; import { TapBehavior, TapGesture } from "../../../core/enums"; import { tool_icon_tap_select, tool_icon_toggle_mode } from "../../../styles/icons.css"; export class TapToolView extends SelectToolView { static __name__ = "TapToolView"; _tap(ev) { const is_tap = this.model.gesture == "tap"; if (is_tap) { this._handle_tap(ev); } return is_tap; } _doubletap(ev) { const is_doubletap = this.model.gesture == "doubletap"; if (is_doubletap) { this._handle_tap(ev); } return is_doubletap; } _handle_tap(ev) { if (!satisfies_modifiers(this.model.modifiers, ev.modifiers)) { return; } const { sx, sy } = ev; const { frame } = this.plot_view; if (!frame.bbox.contains(sx, sy)) { return; } this._clear_other_overlays(); const geometry = { type: "point", sx, sy }; if (this.model.behavior == "select") { this._select(geometry, true, this._select_mode(ev.modifiers)); } else { this._inspect(geometry, ev.modifiers); } } _select(geometry, final, mode) { const renderers_by_source = this._computed_renderers_by_data_source(); for (const [, renderers] of renderers_by_source) { const sm = renderers[0].get_selection_manager(); const r_views = renderers.map((r) => this.plot_view.views.find_one(r)).filter((r) => r != null); const did_hit = sm.select(r_views, geometry, final, mode); if (did_hit) { const [rv] = r_views; this._emit_callback(rv, geometry, sm.source); } } this._emit_selection_event(geometry); this.plot_view.state.push("tap", { selection: this.plot_view.get_selection() }); } _inspect(geometry, modifiers) { for (const r of this.computed_renderers) { const rv = this.plot_view.views.find_one(r); if (rv == null) { continue; } const sm = r.get_selection_manager(); const did_hit = sm.inspect(rv, geometry); if (did_hit) { this._emit_callback(rv, geometry, sm.source, modifiers); } } } _emit_callback(rv, geometry, source, modifiers) { const { callback } = this.model; if (callback != null) { const x = rv.coordinates.x_scale.invert(geometry.sx); const y = rv.coordinates.y_scale.invert(geometry.sy); const data = { geometries: { ...geometry, x, y }, source, event: { modifiers }, }; void execute(callback, this.model, data); } } } export class TapTool extends SelectTool { static __name__ = "TapTool"; constructor(attrs) { super(attrs); } static { this.prototype.default_view = TapToolView; this.define(({ Any, Nullable }) => ({ mode: [SelectionMode, "toggle"], behavior: [TapBehavior, "select"], gesture: [TapGesture, "tap"], modifiers: [Modifiers, {}], callback: [Nullable(Any /*TODO*/), null], })); this.register_alias("click", () => new TapTool({ behavior: "inspect" })); this.register_alias("tap", () => new TapTool()); this.register_alias("doubletap", () => new TapTool({ gesture: "doubletap" })); } tool_name = "Tap"; tool_icon = tool_icon_tap_select; event_type = "tap"; default_order = 10; get menu() { return [ new MenuItem({ icon: `.${tool_icon_toggle_mode}`, label: "Toggle mode", tooltip: "Toggle the current selection", checked: () => this.mode == "toggle", action: () => { this.mode = "toggle"; this.active = true; }, }), ...super.menu, ]; } } //# sourceMappingURL=tap_tool.js.map