@bokeh/bokehjs
Version:
Interactive, novel data visualization
131 lines • 4.59 kB
JavaScript
import { Renderer, RendererView } from "./renderer";
import { UIElement } from "../ui/ui_element";
import { DOMNode } from "../dom/dom_node";
import { build_views, remove_views } from "../../core/build_views";
import { Ref, Or } from "../../core/kinds";
import { LayoutDOM } from "../layouts/layout_dom";
// TODO UIElement needs to inherit from DOMNode
export const ElementLike = Or(Ref(UIElement), Ref(DOMNode));
export class CompositeRendererView extends RendererView {
static __name__ = "CompositeRendererView";
_renderer_views = new Map();
get renderer_views() {
return this.computed_renderer_views;
}
_element_views = new Map();
get element_views() {
return this.computed_element_views;
}
children_views() {
return [...super.children_views(), ...this.renderer_views, ...this.element_views];
}
async lazy_initialize() {
await super.lazy_initialize();
await this._build_renderers();
await this._build_elements();
}
_computed_renderers = [];
get computed_renderers() {
return [...this.model.renderers, ...this._computed_renderers];
}
get computed_renderer_views() {
return this.computed_renderers.map((item) => this._renderer_views.get(item)).filter((rv) => rv != null);
}
async _build_renderers() {
return await build_views(this._renderer_views, this.computed_renderers, { parent: this.plot_view });
}
_computed_elements = [];
get computed_elements() {
return [...this.model.elements, ...this._computed_elements];
}
get computed_element_views() {
return this.computed_elements.map((item) => this._element_views.get(item)).filter((ev) => ev != null);
}
async _build_elements() {
return await build_views(this._element_views, this.computed_elements, { parent: (model) => model instanceof LayoutDOM ? null : this.plot_view });
}
async _update_renderers() {
await this._build_renderers();
}
async _update_elements() {
const { created } = await this._build_elements();
const created_views = new Set(created);
// Since appending to a DOM node will move the node to the end if it has
// already been added appending all the children in order will result in
// correct ordering.
for (const view of this.element_views) {
const is_new = created_views.has(view);
const target = view.rendering_target() ?? this.self_target;
if (is_new) {
view.render_to(target);
}
else {
target.append(view.el);
}
}
this.r_after_render();
}
render() {
super.render();
for (const element_view of this.element_views) {
const target = element_view.rendering_target() ?? this.self_target;
element_view.render_to(target);
}
}
remove() {
remove_views(this._renderer_views);
remove_views(this._element_views);
super.remove();
}
connect_signals() {
super.connect_signals();
const { renderers, elements } = this.model.properties;
this.on_change(renderers, async () => {
await this._update_renderers();
});
this.on_change(elements, async () => {
await this._update_elements();
});
}
paint(ctx) {
super.paint(ctx);
if (this.displayed && this.is_renderable) {
for (const renderer of this.computed_renderer_views) {
renderer.paint(ctx);
}
}
const { displayed } = this;
for (const element_view of this.element_views) {
element_view.reposition(displayed);
}
}
has_finished() {
if (!super.has_finished()) {
return false;
}
for (const renderer_view of this.renderer_views) {
if (!renderer_view.has_finished()) {
return false;
}
}
for (const element_view of this.element_views) {
if (!element_view.has_finished()) {
return false;
}
}
return true;
}
}
export class CompositeRenderer extends Renderer {
static __name__ = "CompositeRenderer";
constructor(attrs) {
super(attrs);
}
static {
this.define(({ List, Ref }) => ({
renderers: [List(Ref(Renderer)), []],
elements: [List(ElementLike), []],
}));
}
}
//# sourceMappingURL=composite_renderer.js.map