Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contain all rendering related tasks in DOMView.render() #13871

Open
wants to merge 1 commit into
base: branch-3.5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 24 additions & 28 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 {create_element, 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 Down Expand Up @@ -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
7 changes: 4 additions & 3 deletions bokehjs/src/lib/models/tools/toolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ export class ToolbarView extends UIElementView {
return true
}

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

protected _build_overflow_menu(): void {
const {location} = this.model
const reversed = location == "left" || location == "above"
const orientation = this.model.horizontal ? "vertical" : "horizontal"
Expand Down Expand Up @@ -113,6 +111,7 @@ export class ToolbarView extends UIElementView {

override remove(): void {
remove_views(this._tool_button_views)
this._overflow_menu.remove()
super.remove()
}

Expand Down Expand Up @@ -172,6 +171,8 @@ export class ToolbarView extends UIElementView {
override render(): void {
super.render()

this._build_overflow_menu()

this.el.classList.add(toolbars[this.model.location])
this.el.classList.toggle(toolbars.inner, this.model.inner)
this._on_visible_change()
Expand Down