UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

131 lines 4.59 kB
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