@bokeh/bokehjs
Version:
Interactive, novel data visualization
88 lines • 3.71 kB
JavaScript
import { GestureTool, GestureToolView } from "./gesture_tool";
import { Modifiers, satisfies_modifiers, print_modifiers } from "./common";
import { Dimension } from "../../../core/enums";
import { clamp } from "../../../core/util/math";
import { tool_icon_wheel_pan } from "../../../styles/icons.css";
import { update_ranges } from "./pan_tool";
export class WheelPanToolView extends GestureToolView {
static __name__ = "WheelPanToolView";
_scroll(ev) {
const { modifiers } = this.model;
if (!satisfies_modifiers(modifiers, ev.modifiers)) {
this.plot_view.notify_about(`use ${print_modifiers(modifiers)} + scroll to pan`);
return false;
}
// clamp the magnitude of factor, if it is > 1 bad things happen
const factor = clamp(this.model.speed * ev.delta, -0.9, 0.9);
this._update_ranges(factor);
return true;
}
_update_ranges(factor) {
const { frame } = this.plot_view;
const hr = frame.bbox.h_range;
const vr = frame.bbox.v_range;
const [sx_low, sx_high] = [hr.start, hr.end];
const [sy_low, sy_high] = [vr.start, vr.end];
let xrs;
let yrs;
const { x_scales, y_scales } = frame;
// Here we are a bit careful to only update the range info for dimensions that
// are "in play". This is to avoid superfluous noise updates to dataranges that
// would cause windowed auto-ranging to turn off.
switch (this.model.dimension) {
case "height": {
const sy_range = Math.abs(sy_high - sy_low);
const sy0 = sy_low - sy_range * factor;
const sy1 = sy_high - sy_range * factor;
xrs = new Map();
yrs = update_ranges(y_scales, sy0, sy1);
break;
}
case "width": {
const sx_range = Math.abs(sx_high - sx_low);
const sx0 = sx_low - sx_range * factor;
const sx1 = sx_high - sx_range * factor;
xrs = update_ranges(x_scales, sx0, sx1);
yrs = new Map();
break;
}
}
// OK this sucks we can't set factor independently in each direction. It is used
// for GMap plots, and GMap plots always preserve aspect, so effective the value
// of 'dimensions' is ignored.
const pan_info = { xrs, yrs, factor };
this.plot_view.state.push("wheel_pan", { range: pan_info });
this.plot_view.update_range(pan_info, { scrolling: true });
this.model.document?.interactive_start(this.plot_view.model, () => this.plot_view.trigger_ranges_update_event());
}
}
export class WheelPanTool extends GestureTool {
static __name__ = "WheelPanTool";
constructor(attrs) {
super(attrs);
}
static {
this.prototype.default_view = WheelPanToolView;
this.define(() => ({
dimension: [Dimension, "width"],
modifiers: [Modifiers, {}],
}));
this.internal(({ Float }) => ({
speed: [Float, 1 / 1000],
}));
this.register_alias("xwheel_pan", () => new WheelPanTool({ dimension: "width" }));
this.register_alias("ywheel_pan", () => new WheelPanTool({ dimension: "height" }));
}
tool_name = "Wheel Pan";
tool_icon = tool_icon_wheel_pan;
event_type = "scroll";
default_order = 12;
get tooltip() {
return this._get_dim_tooltip(this.dimension);
}
supports_auto() {
const { alt, ctrl, shift } = this.modifiers;
return alt != null || ctrl != null || shift != null;
}
}
//# sourceMappingURL=wheel_pan_tool.js.map