diff --git a/ui/src/frontend/panel_container.ts b/ui/src/frontend/panel_container.ts index c0b3a34179..dd33b2ba24 100644 --- a/ui/src/frontend/panel_container.ts +++ b/ui/src/frontend/panel_container.ts @@ -35,6 +35,8 @@ import { runningStatStr, } from './perf'; import {TrackGroupAttrs} from './viewer_page'; +import {trackRegistry} from './track_registry'; +import {SCROLLING_TRACK_GROUP} from '../common/state'; // If the panel container scrolls, the backing canvas height is // SCROLLING_CANVAS_OVERDRAW_FACTOR * parent container height. @@ -237,32 +239,64 @@ export class PanelContainer implements m.ClassComponent { return (attrs as {collapsed?: boolean}).collapsed !== undefined; } - renderPanel(node: AnyAttrsVnode, key: string, extraClass = ''): m.Vnode { + renderPanel( + node: AnyAttrsVnode, + key: string, + style?: Partial ): m.Vnode { assertFalse(this.panelByKey.has(key)); this.panelByKey.set(key, node); return m( - `.panel${extraClass}`, - {key, 'data-key': key}, + `.panel`, + {key, 'data-key': key, style}, perfDebug() ? [node, m('.debug-panel-border', {key: 'debug-panel-border'})] : node); } + getHeightOfParent(id?: string):number { + if (id && id !== SCROLLING_TRACK_GROUP) { + const trackGroup = globals.state.trackGroups[id]; + if (trackGroup && + trackGroup.parentGroup && + trackGroup.parentGroup !== SCROLLING_TRACK_GROUP) { + const parentGroup = globals.state.trackGroups[trackGroup.parentGroup]; + const summaryTrack = + globals.state.tracks[parentGroup.tracks[0]]; + const summaryTrackElement = + trackRegistry.get(summaryTrack.kind).create({ + trackId: summaryTrack.id, + engine: globals.engines.get(summaryTrack.engineId)!, + }); + const height = summaryTrackElement.getHeight(); + return this.getHeightOfParent(trackGroup?.parentGroup) + height; + } + } + return 0; + }; + // Render a tree of panels into one vnode. Argument `path` is used to build // `key` attribute for intermediate tree vnodes: otherwise Mithril internals // will complain about keyed and non-keyed vnodes mixed together. - renderTree(node: AnyAttrsVnode, path: string): m.Vnode { + renderTree( + node: AnyAttrsVnode, + path: string, + depthObject: { depth:number } = {depth: 0}): m.Vnode { if (this.isTrackGroupAttrs(node.attrs)) { + const top = this.getHeightOfParent(node.attrs.header.attrs.trackGroupId); + const children = node.attrs.childTracks.map( + (child, index) => this.renderTree(child, `${path}-${index}`, depthObject)); return m( - 'div', - {key: path}, - this.renderPanel( - node.attrs.header, - `${path}-header`, - node.attrs.collapsed ? '' : '.sticky'), - ...node.attrs.childTracks.map( - (child, index) => this.renderTree(child, `${path}-${index}`))); + 'div', + {key: path}, + this.renderPanel( + node.attrs.header, + `${path}-header`, !node.attrs.collapsed ?{ + 'position': 'sticky', + 'top': top + 'px', + 'zIndex': ((++depthObject.depth) + 2).toString(), + }: undefined), ...children); + ; } return this.renderPanel(node, assertExists(node.key) as string); }