Skip to content

Commit

Permalink
Contain all rendering related tasks in DOMView.render()
Browse files Browse the repository at this point in the history
  • Loading branch information
mattpap committed May 14, 2024
1 parent 10179da commit 9ae6455
Show file tree
Hide file tree
Showing 17 changed files with 99 additions and 114 deletions.
2 changes: 1 addition & 1 deletion bokehjs/src/lib/core/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const _createElement = <T extends keyof HTMLElementTagNameMap>(tag: T) => {
}
}

export function createElement<T extends keyof HTMLElementTagNameMap>(
export function create_element<T extends keyof HTMLElementTagNameMap>(
tag: T, attrs: HTMLAttrs | null, ...children: HTMLChild[]): HTMLElementTagNameMap[T] {
return _createElement(tag)(attrs, ...children)
}
Expand Down
54 changes: 25 additions & 29 deletions bokehjs/src/lib/core/dom_view.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {View} from "./view"
import type {SerializableState} from "./view"
import type {StyleSheet, StyleSheetLike} from "./dom"
import {createElement, empty, InlineStyleSheet, ClassList} from "./dom"
import {create_element, InlineStyleSheet, ClassList} from "./dom"
import {isString} from "./util/types"
import {assert} from "./util/assert"
import type {BBox} from "./util/bbox"
Expand All @@ -16,7 +16,12 @@ export abstract class DOMView extends View {

static tag_name: keyof HTMLElementTagNameMap = "div"

el: ChildNode
protected _el: ChildNode | null = null
get el(): ChildNode {
assert(this._el != null, "not rendered")
return this._el
}

shadow_el?: ShadowRoot

get bbox(): BBox | undefined {
Expand All @@ -29,17 +34,8 @@ export abstract class DOMView extends View {
return bbox != null ? {...state, bbox: bbox.round()} : state
}

get children_el(): Node {
return this.shadow_el ?? this.el
}

override initialize(): void {
super.initialize()
this.el = this._create_element()
}

override remove(): void {
this.el.remove()
this._el?.remove()
super.remove()
}

Expand All @@ -51,7 +47,13 @@ export abstract class DOMView extends View {
return []
}

abstract render(): void
render(): void {
const el = this._create_element()
if (this._el != null) {
this._el.replaceWith(el)
}
this._el = el
}

render_to(target: Node): void {
this.render()
Expand All @@ -73,7 +75,7 @@ export abstract class DOMView extends View {
}

protected _create_element(): this["el"] {
return createElement(this.constructor.tag_name, {class: this.css_classes()})
return create_element(this.constructor.tag_name, {class: this.css_classes()})
}

reposition(_displayed?: boolean): void {}
Expand All @@ -92,12 +94,15 @@ export abstract class DOMView extends View {
}

export abstract class DOMElementView extends DOMView {
declare el: HTMLElement
declare protected _el: HTMLElement
override get el(): HTMLElement {
return super.el as HTMLElement
}

class_list: ClassList

override initialize(): void {
super.initialize()
override render(): void {
super.render()
this.class_list = new ClassList(this.el.classList)
}
}
Expand All @@ -108,24 +113,15 @@ export abstract class DOMComponentView extends DOMElementView {

declare shadow_el: ShadowRoot

override initialize(): void {
super.initialize()
this.shadow_el = this.el.attachShadow({mode: "open"})
}

override stylesheets(): StyleSheetLike[] {
return [...super.stylesheets(), base_css]
}

empty(): void {
empty(this.shadow_el)
this.class_list.clear()
override render(): void {
super.render()
this.shadow_el = this.el.attachShadow({mode: "open"})
this._applied_css_classes = []
this._applied_stylesheets = []
}

render(): void {
this.empty()
this._update_stylesheets()
this._update_css_classes()
this._update_css_variables()
Expand Down
11 changes: 6 additions & 5 deletions bokehjs/src/lib/core/visuals/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ export class Visuals {
throw new Error("unknown visual")
}
})()

if (visual instanceof VisualProperties) {
visual.update()
}

this._visuals.push(visual)

Object.defineProperty(this, prefix + visual.type, {
Expand All @@ -65,4 +60,10 @@ export class Visuals {
})
}
}

update(): void {
for (const visual of this) {
visual.update()
}
}
}
4 changes: 1 addition & 3 deletions bokehjs/src/lib/models/annotations/data_annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ export abstract class DataAnnotationView extends AnnotationView {
}
}

for (const visual of this.visuals) {
visual.update()
}
this.visuals.update()
}

abstract map_data(): void
Expand Down
3 changes: 1 addition & 2 deletions bokehjs/src/lib/models/dom/dom_element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import type {ViewStorage, IterViews} from "core/build_views"
import {build_views, remove_views} from "core/build_views"
import {isString} from "core/util/types"
import {apply_styles} from "core/css"
import {empty} from "core/dom"
import type * as p from "core/properties"

export abstract class DOMElementView extends DOMNodeView {
Expand All @@ -31,7 +30,7 @@ export abstract class DOMElementView extends DOMNodeView {
}

override render(): void {
empty(this.el)
super.render()
apply_styles(this.el.style, this.model.style)

for (const child of this.model.children) {
Expand Down
6 changes: 3 additions & 3 deletions bokehjs/src/lib/models/dom/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {DOMNode, DOMNodeView} from "./dom_node"
import {UIElement} from "../ui/ui_element"
import type {ViewStorage, IterViews} from "core/build_views"
import {build_views, remove_views} from "core/build_views"
import {empty, span} from "core/dom"
import {span} from "core/dom"
import {assert} from "core/util/assert"
import {isString, isArray} from "core/util/types"
import type * as p from "core/properties"
Expand Down Expand Up @@ -43,8 +43,8 @@ export class HTMLView extends DOMNodeView {
super.remove()
}

render(): void {
empty(this.el)
override render(): void {
super.render()

const html = (() => {
const {html} = this.model
Expand Down
4 changes: 0 additions & 4 deletions bokehjs/src/lib/models/dom/placeholder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ export abstract class PlaceholderView extends DOMNodeView {
declare model: Placeholder
static override tag_name = "span" as const

override render(): void {
// XXX: no implementation?
}

abstract update(source: ColumnarDataSource, i: DataIndex | null, vars: object/*, formatters?: Formatters*/): void
}

Expand Down
1 change: 1 addition & 0 deletions bokehjs/src/lib/models/dom/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export class TextView extends DOMNodeView {
declare el: globalThis.Text

override render(): void {
super.render()
this.el.textContent = this.model.content
}

Expand Down
5 changes: 2 additions & 3 deletions bokehjs/src/lib/models/dom/value_of.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {DOMNode, DOMNodeView} from "./dom_node"
import {HasProps} from "core/has_props"
import {empty} from "core/dom"
import {to_string} from "core/util/pretty"
import type * as p from "core/properties"

Expand All @@ -17,8 +16,8 @@ export class ValueOfView extends DOMNodeView {
}
}

render(): void {
empty(this.el)
override render(): void {
super.render()
this.el.style.display = "contents"

const text = (() => {
Expand Down
5 changes: 1 addition & 4 deletions bokehjs/src/lib/models/glyphs/glyph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,10 +350,7 @@ export abstract class GlyphView extends DOMComponentView {
}
}

for (const visual of this.visuals) {
visual.update()
}

this.visuals.update()
this.glglyph?.set_visuals_changed()
}

Expand Down
31 changes: 14 additions & 17 deletions bokehjs/src/lib/models/layouts/layout_dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,6 @@ export abstract class LayoutDOMView extends PaneView {
override connect_signals(): void {
super.connect_signals()

this.el.addEventListener("mouseenter", (event) => {
this.mouseenter.emit(event)
})
this.el.addEventListener("mouseleave", (event) => {
this.mouseleave.emit(event)
})

if (this.parent instanceof LayoutDOMView) {
this.connect(this.parent.disabled, (disabled) => {
this.disabled.emit(disabled || this.model.disabled)
Expand Down Expand Up @@ -122,16 +115,7 @@ export abstract class LayoutDOMView extends PaneView {
}

async build_child_views(): Promise<UIElementView[]> { // TODO BuildResult<UIElement>
const {created, removed} = await build_views(this._child_views, this.child_models, {parent: this})

for (const view of removed) {
this._resize_observer.unobserve(view.el)
}

for (const view of created) {
this._resize_observer.observe(view.el, {box: "border-box"})
}

const {created} = await build_views(this._child_views, this.child_models, {parent: this})
return created
}

Expand All @@ -141,6 +125,13 @@ export abstract class LayoutDOMView extends PaneView {
for (const child_view of this.child_views) {
child_view.render_to(this.shadow_el)
}

this.el.addEventListener("mouseenter", (event) => {
this.mouseenter.emit(event)
})
this.el.addEventListener("mouseleave", (event) => {
this.mouseleave.emit(event)
})
}

protected _update_children(): void {}
Expand Down Expand Up @@ -443,6 +434,12 @@ export abstract class LayoutDOMView extends PaneView {

override _after_render(): void {
// XXX no super
this._resize_observer.disconnect()

for (const child_view of this.child_views) {
this._resize_observer.observe(child_view.el, {box: "border-box"})
}

if (!this.is_managed) {
this.invalidate_layout()
}
Expand Down
5 changes: 5 additions & 0 deletions bokehjs/src/lib/models/renderers/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ export abstract class RendererView extends StyledElementView implements visuals.
return true
}

override render(): void {
super.render()
this.visuals.update()
}

paint(): void {
// It would be better to update geometry (the internal layout) only when
// necessary, but conditions for that are not clear, so for now update
Expand Down
46 changes: 23 additions & 23 deletions bokehjs/src/lib/models/tools/tool_button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,23 @@ export abstract class ToolButtonView extends UIElementView {
protected _menu: ContextMenu
protected _ui_gestures: UIGestures

override initialize(): void {
super.initialize()
override connect_signals(): void {
super.connect_signals()
this.connect(this.model.change, () => this.render())
this.connect(this.model.tool.change as Signal0<Tool>, () => this.render())
}

override remove(): void {
this._ui_gestures.remove()
this._menu.remove()
super.remove()
}

override stylesheets(): StyleSheetLike[] {
return [...super.stylesheets(), tool_button_css, icons_css]
}

protected _build_menu(): void {
const {location} = this.parent.model
const reverse = location == "left" || location == "above"
const orientation = this.parent.model.horizontal ? "vertical" : "horizontal"
Expand All @@ -37,6 +51,12 @@ export abstract class ToolButtonView extends UIElementView {
return event.composedPath().includes(this.el)
},
})
}

override render(): void {
super.render()

this._build_menu()

this._ui_gestures = new UIGestures(this.el, {
on_tap: (event: TapEvent) => {
Expand All @@ -52,6 +72,7 @@ export abstract class ToolButtonView extends UIElementView {
this._pressed()
},
})
this._ui_gestures.connect_signals()

this.el.addEventListener("keydown", (event) => {
switch (event.key as Keys) {
Expand All @@ -66,27 +87,6 @@ export abstract class ToolButtonView extends UIElementView {
default:
}
})
}

override connect_signals(): void {
super.connect_signals()
this._ui_gestures.connect_signals()
this.connect(this.model.change, () => this.render())
this.connect(this.model.tool.change as Signal0<Tool>, () => this.render())
}

override remove(): void {
this._ui_gestures.remove()
this._menu.remove()
super.remove()
}

override stylesheets(): StyleSheetLike[] {
return [...super.stylesheets(), tool_button_css, icons_css]
}

override render(): void {
super.render()

this.class_list.add(tool_button[this.parent.model.location])
if (this.model.tool.disabled) {
Expand Down

0 comments on commit 9ae6455

Please sign in to comment.