@bokeh/bokehjs
Version:
Interactive, novel data visualization
166 lines • 6.13 kB
JavaScript
import { CanvasPanel, CanvasPanelView } from "./canvas_panel";
import { CategoricalScale } from "../scales/categorical_scale";
import { LogScale } from "../scales/log_scale";
import { Scale } from "../scales/scale";
import { LinearScale } from "../scales/linear_scale";
import { Range } from "../ranges/range";
import { Range1d } from "../ranges/range1d";
import { DataRange1d } from "../ranges/data_range1d";
import { FactorRange } from "../ranges/factor_range";
import { entries } from "../../core/util/object";
import { assert } from "../../core/util/assert";
import * as css from "../../styles/cartesian_frame.css";
export class CartesianFrameView extends CanvasPanelView {
static __name__ = "CartesianFrameView";
initialize() {
super.initialize();
this._configure_scales();
}
remove() {
this._unregister_frame();
super.remove();
}
stylesheets() {
return [...super.stylesheets(), css.default];
}
connect_signals() {
super.connect_signals();
const { x_range, y_range, x_scale, y_scale, extra_x_ranges, extra_y_ranges, extra_x_scales, extra_y_scales } = this.model.properties;
this.on_change([x_range, y_range, x_scale, y_scale, extra_x_ranges, extra_y_ranges, extra_x_scales, extra_y_scales], () => {
this._configure_scales();
});
}
_x_target;
_y_target;
_x_ranges = new Map();
_y_ranges = new Map();
_x_scales = new Map();
_y_scales = new Map();
_x_scale;
_y_scale;
_get_ranges(range, extra_ranges) {
return new Map([...entries(extra_ranges), ["default", range]]);
}
_get_scales(scale, extra_scales, ranges, frame_range) {
const in_scales = new Map([...entries(extra_scales), ["default", scale]]);
const scales = new Map();
for (const [name, range] of ranges) {
const factor_range = range instanceof FactorRange;
const categorical_scale = scale instanceof CategoricalScale;
if (factor_range != categorical_scale) {
throw new Error(`'${range.type}' is incompatible '${scale.type}'`);
}
if (scale instanceof LogScale && range instanceof DataRange1d) {
range.scale_hint = "log";
}
const base_scale = in_scales.get(name) ?? scale;
const derived_scale = base_scale.clone();
derived_scale.setv({ source_range: range, target_range: frame_range });
scales.set(name, derived_scale);
}
return scales;
}
_configure_ranges() {
// data to/from screen space transform (left-bottom <-> left-top origin)
const { bbox } = this;
this._x_target = new Range1d({ start: bbox.left, end: bbox.right });
this._y_target = new Range1d({ start: bbox.bottom, end: bbox.top });
}
_configure_scales() {
const { x_range, y_range, extra_x_ranges, extra_y_ranges } = this.model;
const { x_scale, y_scale, extra_x_scales, extra_y_scales } = this.model;
assert(x_scale.properties.source_range.is_unset && x_scale.properties.target_range.is_unset);
assert(y_scale.properties.source_range.is_unset && y_scale.properties.target_range.is_unset);
this._configure_ranges();
this._unregister_frame();
this._x_ranges = this._get_ranges(x_range, extra_x_ranges);
this._y_ranges = this._get_ranges(y_range, extra_y_ranges);
this._register_frame();
this._x_scales = this._get_scales(x_scale, extra_x_scales, this._x_ranges, this._x_target);
this._y_scales = this._get_scales(y_scale, extra_y_scales, this._y_ranges, this._y_target);
this._x_scale = this._x_scales.get("default");
this._y_scale = this._y_scales.get("default");
this.mark_finished();
}
_update_scales() {
this._configure_ranges();
for (const [, scale] of this._x_scales) {
scale.target_range = this._x_target;
}
for (const [, scale] of this._y_scales) {
scale.target_range = this._y_target;
}
}
_register_frame() {
for (const range of this.ranges.values()) {
range.frames.add(this);
}
}
_unregister_frame() {
for (const range of this.ranges.values()) {
range.frames.delete(this);
}
}
set_geometry(bbox) {
super.set_geometry(bbox);
this._update_scales();
}
get x_range() {
return this.model.x_range;
}
get y_range() {
return this.model.y_range;
}
get x_target() {
return this._x_target;
}
get y_target() {
return this._y_target;
}
get x_ranges() {
return this._x_ranges;
}
get y_ranges() {
return this._y_ranges;
}
get ranges() {
return new Set([...this.x_ranges.values(), ...this.y_ranges.values()]);
}
get x_scales() {
return this._x_scales;
}
get y_scales() {
return this._y_scales;
}
get scales() {
return new Set([...this.x_scales.values(), ...this.y_scales.values()]);
}
get x_scale() {
return this._x_scale;
}
get y_scale() {
return this._y_scale;
}
}
export class CartesianFrame extends CanvasPanel {
static __name__ = "CartesianFrame";
constructor(attrs) {
super(attrs);
}
static {
this.prototype.default_view = CartesianFrameView;
this.define(({ Bool, Float, Dict, Ref }) => ({
x_range: [Ref(Range), () => new DataRange1d()],
y_range: [Ref(Range), () => new DataRange1d()],
x_scale: [Ref(Scale), () => new LinearScale()],
y_scale: [Ref(Scale), () => new LinearScale()],
extra_x_ranges: [Dict(Ref(Range)), {}],
extra_y_ranges: [Dict(Ref(Range)), {}],
extra_x_scales: [Dict(Ref(Scale)), {}],
extra_y_scales: [Dict(Ref(Scale)), {}],
match_aspect: [Bool, false],
aspect_scale: [Float, 1],
}));
}
}
//# sourceMappingURL=cartesian_frame.js.map