UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

136 lines 4.88 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"; // TODO UIElement needs to inherit from DOMNode const ElementLike = Or(Ref(UIElement), Ref(DOMNode)); export class CompositeRendererView extends RendererView { static __name__ = "CompositeRendererView"; _renderer_views = new Map(); get renderer_views() { return this.model.renderers.map((renderer) => this._renderer_views.get(renderer)); } _element_views = new Map(); get element_views() { return this.model.elements.map((element) => this._element_views.get(element)); } *children() { yield* super.children(); yield* this.renderer_views; yield* 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: this.plot_view }); } async _update_renderers() { await this._build_renderers(); } async _update_elements() { const { created } = await this._build_elements(); const created_elements = new Set(created); // First remove and then either reattach existing elements or render and // attach new elements, so that the order of children is consistent, while // avoiding expensive re-rendering of existing views. for (const element_view of this.element_views) { element_view.el.remove(); } for (const element_view of this.element_views) { const is_new = created_elements.has(element_view); const target = element_view.rendering_target() ?? this.shadow_el; if (is_new) { element_view.render_to(target); } else { target.append(element_view.el); } } this.r_after_render(); } 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(); }); } _has_rendered_elements = false; paint(ctx) { if (!this._has_rendered_elements) { for (const element_view of this.element_views) { const target = element_view.rendering_target() ?? this.shadow_el; element_view.render_to(target); } this._has_rendered_elements = true; } 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