UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

157 lines 5.17 kB
import { RegionSelectTool, RegionSelectToolView } from "./region_select_tool"; import { PolyAnnotation } from "../../annotations/poly_annotation"; import { tool_icon_polygon_select } from "../../../styles/icons.css"; export class PolySelectToolView extends RegionSelectToolView { static __name__ = "PolySelectToolView"; _is_selecting = false; _mappers() { const mapper = (units, scale, view, canvas) => { switch (units) { case "canvas": return canvas; case "screen": return view; case "data": return scale; } }; const { overlay } = this.model; const { frame, canvas } = this.plot_view; const { x_scale, y_scale } = frame; const { x_view, y_view } = frame.bbox; const { x_screen, y_screen } = canvas.bbox; return { x: mapper(overlay.xs_units, x_scale, x_view, x_screen), y: mapper(overlay.ys_units, y_scale, y_view, y_screen), }; } _v_compute(xs, ys) { const { x, y } = this._mappers(); return [x.v_compute(xs), y.v_compute(ys)]; } _v_invert(sxs, sys) { const { x, y } = this._mappers(); return [x.v_invert(sxs), y.v_invert(sys)]; } connect_signals() { super.connect_signals(); const { pan } = this.model.overlay; this.connect(pan, ([phase, ev]) => { if ((phase == "pan" && this._is_continuous(ev)) || (phase == "pan:end" && !this._is_selecting)) { const { xs, ys } = this.model.overlay; const [sxs, sys] = this._v_compute(xs, ys); this._do_select(sxs, sys, false, this._select_mode(ev)); } }); const { active } = this.model.properties; this.on_change(active, () => { if (!this.model.active && !this.model.persistent) { this._clear_overlay(); } }); } _tap(ev) { const { sx, sy } = ev; const { frame } = this.plot_view; if (!frame.bbox.contains(sx, sy)) { return; } this._clear_other_overlays(); const [sxs, sys] = (() => { if (this._is_selecting) { const { xs, ys } = this.model.overlay; const [sxs, sys] = this._v_compute(xs, ys); return [[...sxs], [...sys]]; } else { this._is_selecting = true; return [[], []]; } })(); sxs.push(sx); sys.push(sy); const [xs, ys] = this._v_invert(sxs, sys); this.model.overlay.update({ xs, ys }); if (this._is_continuous(ev.modifiers)) { this._do_select(sxs, sys, true, this._select_mode(ev.modifiers)); } } _finish_selection(ev) { this._is_selecting = false; const { xs, ys } = this.model.overlay; const [sxs, sys] = this._v_compute(xs, ys); this._do_select(sxs, sys, true, this._select_mode(ev)); this.plot_view.state.push("poly_select", { selection: this.plot_view.get_selection() }); if (!this.model.persistent) { this._clear_overlay(); } } _press(ev) { this._finish_selection(ev.modifiers); } _keyup(ev) { if (!this.model.active) { return; } if (ev.key == "Enter") { this._finish_selection(ev.modifiers); return; } if (ev.key == "Escape") { if (this.model.overlay.visible) { this._clear_overlay(); return; } } super._keyup(ev); } _clear_selection() { if (this.model.overlay.visible) { this._clear_overlay(); } else { this._is_selecting = false; super._clear_selection(); } } _clear_overlay() { this._is_selecting = false; super._clear_overlay(); } _do_select(sx, sy, final, mode) { const { greedy } = this.model; const geometry = { type: "poly", sx, sy, greedy }; this._select(geometry, final, mode); } } export const DEFAULT_POLY_OVERLAY = () => { return new PolyAnnotation({ syncable: false, level: "overlay", visible: false, editable: true, xs_units: "data", ys_units: "data", fill_color: "lightgrey", fill_alpha: 0.5, line_color: "black", line_alpha: 1.0, line_width: 2, line_dash: [4, 4], }); }; export class PolySelectTool extends RegionSelectTool { static __name__ = "PolySelectTool"; constructor(attrs) { super(attrs); } static { this.prototype.default_view = PolySelectToolView; this.define(({ Ref }) => ({ overlay: [Ref(PolyAnnotation), DEFAULT_POLY_OVERLAY], })); this.register_alias("poly_select", () => new PolySelectTool()); } tool_name = "Poly Select"; tool_icon = tool_icon_polygon_select; event_type = "tap"; default_order = 11; } //# sourceMappingURL=poly_select_tool.js.map