• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {Timeline} from '../../timeline.mjs';
6import {SelectTimeEvent} from '../events.mjs';
7import {CSSColor, delay, SVG} from '../helper.mjs';
8
9import {TimelineTrackBase} from './timeline-track-base.mjs'
10
11const kItemHeight = 8;
12
13export class TimelineTrackStackedBase extends TimelineTrackBase {
14  _originalContentWidth = 0;
15  _drawableItems = new Timeline();
16
17  _updateChunks() {
18    // We don't need to update the chunks here.
19    this._updateDimensions();
20    this.requestUpdate();
21  }
22
23  set data(timeline) {
24    super.data = timeline;
25    this._contentWidth = 0;
26    if (timeline.values.length > 0) this._prepareDrawableItems();
27  }
28
29  _handleDoubleClick(event) {
30    if (event.button !== 0) return;
31    this._selectionHandler.clearSelection();
32    const item = this._getDrawableItemForEvent(event);
33    if (item === undefined) return;
34    event.stopImmediatePropagation();
35    this.dispatchEvent(new SelectTimeEvent(item.startTime, item.endTime));
36    return false;
37  }
38
39  _getStackDepthForEvent(event) {
40    return Math.floor(event.layerY / kItemHeight) - 1;
41  }
42
43  _getDrawableItemForEvent(event) {
44    const depth = this._getStackDepthForEvent(event);
45    const time = this.positionToTime(event.pageX);
46    const index = this._drawableItems.find(time);
47    for (let i = index - 1; i > 0; i--) {
48      const item = this._drawableItems.at(i);
49      if (item.depth != depth) continue;
50      if (item.endTime < time) continue;
51      return item;
52    }
53    return undefined;
54  }
55
56  _drawableItemToLogEntry(item) {
57    return item;
58  }
59
60  _getEntryForEvent(event) {
61    const item = this._getDrawableItemForEvent(event);
62    const logEntry = this._drawableItemToLogEntry(item);
63    if (item === undefined) return undefined;
64    const style = this.toolTipTargetNode.style;
65    style.left = `${event.layerX}px`;
66    style.top = `${(item.depth + 1) * kItemHeight}px`;
67    style.height = `${kItemHeight}px`
68    return logEntry;
69  }
70
71  _prepareDrawableItems() {
72    // Subclass responsibility.
73  }
74
75  _adjustStackDepth(maxDepth) {
76    // Account for empty top line
77    maxDepth++;
78    this._adjustHeight(maxDepth * kItemHeight);
79  }
80
81  _scaleContent(currentWidth) {
82    if (this._originalContentWidth == 0) return;
83    // Instead of repainting just scale the content.
84    const ratio = currentWidth / this._originalContentWidth;
85    this._scalableContentNode.style.transform = `scale(${ratio}, 1)`;
86    this.style.setProperty('--txt-scale', `scale(${1 / ratio}, 1)`);
87  }
88
89  async _drawContent() {
90    if (this._originalContentWidth > 0) return;
91    this._originalContentWidth = parseInt(this.timelineMarkersNode.style.width);
92    this._scalableContentNode.innerHTML = '';
93    let buffer = '';
94    const add = async () => {
95      const svg = SVG.svg();
96      svg.innerHTML = buffer;
97      this._scalableContentNode.appendChild(svg);
98      buffer = '';
99      await delay(50);
100    };
101    const items = this._drawableItems.values;
102    for (let i = 0; i < items.length; i++) {
103      if ((i % 3000) == 0) await add();
104      buffer += this._drawItem(items[i], i);
105    }
106    add();
107  }
108
109  _drawItem(item, i, outline = false) {
110    const x = roundTo3Digits(this.timeToPosition(item.time));
111    const y = (item.depth + 1) * kItemHeight;
112    let width = roundTo3Digits(item.duration * this._timeToPixel);
113    if (outline) {
114      return `<rect x=${x} y=${y} width=${width} height=${
115          kItemHeight - 1} class=fs />`;
116    }
117    let color = this._legend.colorForType(item.type);
118    if (i % 2 == 1) {
119      color = CSSColor.darken(color, 20);
120    }
121    return `<rect x=${x} y=${y} width=${width} height=${kItemHeight - 1} fill=${
122        color} class=f />`;
123  }
124
125  _drawItemText(item) {
126    const type = item.type;
127    const kHeight = 9;
128    const x = this.timeToPosition(item.time);
129    const y = item.depth * (kHeight + 1);
130    let width = item.duration * this._timeToPixel;
131    width -= width * 0.1;
132
133    let buffer = '';
134    if (width < 15 || type == 'Other') return buffer;
135    const rawName = item.entry.getName();
136    if (rawName.length == 0) return buffer;
137    const kChartWidth = 5;
138    const maxChars = Math.floor(width / kChartWidth)
139    const text = rawName.substr(0, maxChars);
140    buffer += `<text x=${x + 1} y=${y - 3} class=txt>${text}</text>`
141    return buffer;
142  }
143}
144
145function roundTo3Digits(value) {
146  return ((value * 1000) | 0) / 1000;
147}
148