@bokeh/bokehjs
Version:
Interactive, novel data visualization
157 lines • 5.17 kB
JavaScript
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