• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BaseElement, element } from '../../../base-ui/BaseElement';
17import { TraceRow } from './base/TraceRow';
18import { dpr } from './base/Extension';
19import {
20  drawFlagLineSegment,
21  drawLines,
22  drawLinkLines,
23  drawLogsLineSegment,
24  drawWakeUp,
25  drawWakeUpList,
26  PairPoint,
27  Rect,
28} from '../../database/ui-worker/ProcedureWorkerCommon';
29import { Flag } from './timer-shaft/Flag';
30import { TimerShaftElement } from './TimerShaftElement';
31import { CpuStruct } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
32import { WakeupBean } from '../../bean/WakeupBean';
33import { LitIcon } from '../../../base-ui/icon/LitIcon';
34import { SpSystemTrace } from '../SpSystemTrace';
35import { LitPopover } from '../../../base-ui/popover/LitPopoverV';
36
37const maxScale = 0.8; //收藏最大高度为界面最大高度的80%
38const topHeight = 150; // 顶部cpu使用率部分高度固定为150px
39const minHeight = 40; //泳道最低高度为40
40const mouseMoveRange = 5;
41
42@element('sp-chart-list')
43export class SpChartList extends BaseElement {
44  private static COLLECT_G1 = '1';
45  private static COLLECT_G2 = '2';
46  private collectEl1: HTMLDivElement | null | undefined;
47  private collectEl2: HTMLDivElement | null | undefined;
48  private groupTitle1: HTMLDivElement | null | undefined;
49  private groupTitle2: HTMLDivElement | null | undefined;
50  private icon1: LitIcon | null | undefined;
51  private icon2: LitIcon | null | undefined;
52  private removeCollectIcon1: LitIcon | null | undefined;
53  private removeCollectIcon2: LitIcon | null | undefined;
54  private rootEl: HTMLDivElement | null | undefined;
55  private fragmentGroup1: DocumentFragment = document.createDocumentFragment();
56  private fragmentGroup2: DocumentFragment = document.createDocumentFragment();
57  private canvas: HTMLCanvasElement | null | undefined; //绘制收藏泳道图
58  private canvasCtx: CanvasRenderingContext2D | undefined | null;
59  private canResize: boolean = false;
60  private isPress: boolean = false;
61  private startPageY = 0;
62  private startClientHeight: number = 0;
63  private scrollTimer: unknown;
64  collect1Expand: boolean = true;
65  collect2Expand: boolean = true;
66  // @ts-ignore
67  private collectRowList1: Array<TraceRow<unknown>> = [];
68  // @ts-ignore
69  private collectRowList2: Array<TraceRow<unknown>> = [];
70  private maxHeight = 0;
71  private manualHeight = 0;
72  private spSystemTrace: SpSystemTrace | undefined | null;
73
74  initElements(): void {
75    this.spSystemTrace = document?.querySelector('body > sp-application')?.shadowRoot?.querySelector('#sp-system-trace');
76    this.collectEl1 = this.shadowRoot?.querySelector<HTMLDivElement>('#collect-group-1');
77    this.collectEl2 = this.shadowRoot?.querySelector<HTMLDivElement>('#collect-group-2');
78    this.groupTitle1 = this.shadowRoot?.querySelector<HTMLDivElement>('#group-1-title');
79    this.groupTitle2 = this.shadowRoot?.querySelector<HTMLDivElement>('#group-2-title');
80    this.icon1 = this.shadowRoot?.querySelector<LitIcon>('#group_1_expand');
81    this.icon2 = this.shadowRoot?.querySelector<LitIcon>('#group_2_expand');
82    this.removeCollectIcon1 = this.shadowRoot?.querySelector<LitIcon>('#group_1_collect');
83    this.removeCollectIcon2 = this.shadowRoot?.querySelector<LitIcon>('#group_2_collect');
84    this.rootEl = this.shadowRoot?.querySelector<HTMLDivElement>('.root');
85    this.canvas = this.shadowRoot?.querySelector<HTMLCanvasElement>('.panel-canvas');
86    this.canvasCtx = this.canvas?.getContext('2d'); //@ts-ignore
87    window.subscribe(window.SmartEvent.UI.RowHeightChange, (data: { expand: number; value: number }) => {
88      this.resizeHeight();
89      if (data.expand) {
90        let offset = this.scrollTop + data.value;
91        offset = offset < 0 ? 0 : offset;
92        this.scrollTop = offset;
93      } else {
94        let offset = this.scrollTop - data.value;
95        offset = offset < 0 ? 0 : offset;
96        this.scrollTop = offset;
97      }
98      this.refreshFavoriteCanvas();
99    });
100    this.initChartListListener();
101  }
102
103  private initChartListListener(): void {
104    let offsetYTimeOut: unknown = undefined;
105    const foldCollect1 = (): void => {
106      if (offsetYTimeOut) {
107        //@ts-ignore
108        clearTimeout(offsetYTimeOut);
109      }
110      this.collect1Expand = !this.collect1Expand;
111      if (this.collect1Expand) {//展开G1
112        this.icon1!.style.transform = 'rotateZ(0deg)';
113        this.collectEl1?.appendChild(this.fragmentGroup1);
114        this.scrollTop = this.scrollHeight;
115      } else {//折叠G1
116        this.icon1!.style.transform = 'rotateZ(-90deg)';
117        this.collectRowList1.forEach((row) => this.fragmentGroup1.appendChild(row));
118        this.scrollTop = 0;
119      }
120      offsetYTimeOut = setTimeout(() => {
121        this.handleCollectFunc();
122        this.spSystemTrace?.refreshCanvas(true);
123      }, 50);
124      this.resizeHeight();
125    };
126    this.icon1?.addEventListener('click', () => foldCollect1());
127    const foldCollect2 = (): void => {
128      this.collect2Expand = !this.collect2Expand;
129      if (this.collect2Expand) {//展开G2
130        this.icon2!.style.transform = 'rotateZ(0deg)';
131        this.collectEl2?.appendChild(this.fragmentGroup2);
132        this.scrollTop = this.scrollHeight;
133      } else {//折叠G2
134        this.icon2!.style.transform = 'rotateZ(-90deg)';
135        this.collectRowList2.forEach((row) => this.fragmentGroup2.appendChild(row));
136        this.scrollTop = 0;
137      }
138      offsetYTimeOut = setTimeout(() => {
139        this.handleCollectFunc();
140        this.spSystemTrace?.refreshCanvas(true);
141      }, 50);
142      this.resizeHeight();
143    };
144    this.icon2?.addEventListener('click', () => foldCollect2());
145    document.addEventListener('keyup', (e) => {
146      if (e.key.toLowerCase() === 'b' && e.ctrlKey === false && this.spSystemTrace?.keyboardEnable) {
147        // 收藏夹有泳道时 为true
148        const hasChildNode1 = this.collectEl1?.hasChildNodes() || this.fragmentGroup1.hasChildNodes();
149        const hasChildNode2 = this.collectEl2?.hasChildNodes() || this.fragmentGroup2.hasChildNodes();
150        // 两个收藏夹都有泳道时
151        if (hasChildNode1 && hasChildNode2) {
152          const flag = this.collect1Expand === this.collect2Expand;
153          if (flag) {
154            foldCollect1();
155            foldCollect2();
156          } else {
157            // 两收藏夹的折叠状态不一致 优先一起折叠
158            if (this.collect1Expand) {
159              foldCollect1();
160            }
161            else {
162              foldCollect2();
163            }
164          }
165          return;
166        }
167        // 只影响有泳道的收藏夹
168        if (hasChildNode1) {
169          foldCollect1();
170        }
171        if (hasChildNode2) {
172          foldCollect2();
173        }
174      }
175    });
176
177    this.removeCollectIcon1?.addEventListener('click', () => {
178      Array.from(this.collectRowList1).forEach(row => {
179        row.collectEL?.click();
180      });
181    });
182    this.removeCollectIcon2?.addEventListener('click', () => {
183      Array.from(this.collectRowList2).forEach(row => {
184        row.collectEL?.click();
185      });
186    });
187  }
188
189  private handleCollectFunc(): void {
190    this.spSystemTrace!.handleCollectFunc(this.spSystemTrace?.linkNodes!);
191  }
192
193  removeAllCollectRow(): void {
194    Array.from(this.collectRowList1).forEach(row => {
195      row.collectEL?.click();
196    });
197    Array.from(this.collectRowList2).forEach(row => {
198      row.collectEL?.click();
199    });
200  }
201
202  private resizeHeight(): void {
203    this.maxHeight = 0;
204    // @ts-ignore
205    this.collectEl1!.childNodes.forEach((item) => (this.maxHeight += (item as unknown).clientHeight));
206    // @ts-ignore
207    this.collectEl2!.childNodes.forEach((item) => (this.maxHeight += (item as unknown).clientHeight));
208    if (this.groupTitle1) {
209      this.maxHeight += this.groupTitle1.clientHeight;
210    }
211    if (this.groupTitle2) {
212      this.maxHeight += this.groupTitle2.clientHeight;
213    }
214
215    this.maxHeight = Math.min(this.getMaxLimitHeight(), this.maxHeight);
216    if (this.manualHeight > 0) {
217      this.style.height = `${Math.min(this.maxHeight, this.manualHeight)}px`;
218    } else {
219      this.style.height = `${this.maxHeight}px`;
220    }
221  }
222
223  private getMaxLimitHeight(): number {
224    return (this.parentElement!.clientHeight - topHeight) * maxScale;
225  }
226
227  // @ts-ignore
228  getCollectRows(filter?: (row: TraceRow<unknown>) => boolean): Array<TraceRow<unknown>> | [] {
229    if (filter) {
230      return [...this.collectRowList1.filter(filter), ...this.collectRowList2.filter(filter)];
231    } else {
232      return this.getAllCollectRows();
233    }
234  }
235
236  getRowScrollTop(): number {
237    return this.rootEl?.scrollTop || 0;
238  }
239
240  // @ts-ignore
241  expandSearchRowGroup(row: TraceRow<unknown>): void {
242    this.updateGroupDisplay();
243    if (row.collectGroup === SpChartList.COLLECT_G1) {
244      if (!this.collect1Expand) {
245        this.collect1Expand = true;
246        this.icon1!.style.transform = 'rotateZ(0deg)';
247        this.collectEl1?.appendChild(this.fragmentGroup1);
248      }
249    } else {
250      if (!this.collect2Expand) {
251        this.collect2Expand = true;
252        this.icon2!.style.transform = 'rotateZ(0deg)';
253        this.collectEl2?.appendChild(this.fragmentGroup2);
254        this.scrollTop = this.scrollHeight;
255      }
256    }
257    this.resizeHeight();
258  }
259
260  // @ts-ignore
261  getCollectRow(filter: (row: TraceRow<unknown>) => boolean): TraceRow<unknown> | undefined {
262    return this.collectRowList1.find(filter) || this.collectRowList2.find(filter);
263  }
264
265  // @ts-ignore
266  getAllCollectRows(): Array<TraceRow<unknown>> {
267    return [...this.collectRowList1, ...this.collectRowList2];
268  }
269
270  getCollectRowsInfo(group: string): unknown {
271    return (group === SpChartList.COLLECT_G1 ? this.collectRowList1 : this.collectRowList2).map((row) => {
272      let rowJson = {
273        type: row.rowType,
274        name: row.name,
275        id: row.rowId,
276        parents: [],
277      };
278      this.getRowParent(rowJson, row);
279      rowJson.parents.reverse();
280      return rowJson;
281    });
282  }
283
284  // @ts-ignore
285  getRowParent(obj: unknown, row: TraceRow<unknown>): void {
286    if (row.parentRowEl) {
287      // @ts-ignore
288      if (obj.parents) {
289        let parent: unknown = {
290          type: row.parentRowEl.rowType,
291          name: row.parentRowEl.name,
292          id: row.parentRowEl.rowId,
293        };
294        // @ts-ignore
295        (obj.parents as Array<unknown>).push(parent);
296      } else {
297        // @ts-ignore
298        obj.parents = [parent];
299      }
300      this.getRowParent(obj, row.parentRowEl);
301    }
302  }
303
304  // @ts-ignore
305  getAllSelectCollectRows(): Array<TraceRow<unknown>> {
306    // @ts-ignore
307    const rows: Array<TraceRow<unknown>> = [];
308    for (const row of this.collectRowList1) {
309      if (row.checkType === '2') {
310        rows.push(row);
311      }
312    }
313    for (const row of this.collectRowList2) {
314      if (row.checkType === '2') {
315        rows.push(row);
316      }
317    }
318    return rows;
319  }
320
321  insertRowBefore(node: Node, child: Node): void {
322    // @ts-ignore
323    if (child === null || (child as TraceRow<unknown>).collectGroup === (node as TraceRow<unknown>).collectGroup) {
324      // @ts-ignore
325      if ((node as TraceRow<unknown>).collectGroup === SpChartList.COLLECT_G1) {
326        this.collectEl1!.insertBefore(node, child);
327        // @ts-ignore
328        this.collectRowList1 = Array.from(this.collectEl1!.children) as TraceRow<unknown>[];
329      } else {
330        this.collectEl2!.insertBefore(node, child);
331        // @ts-ignore
332        this.collectRowList2 = Array.from(this.collectEl2!.children) as TraceRow<unknown>[];
333      }
334    }
335  }
336
337  reset(): void {
338    this.maxHeight = 0;
339    this.clearRect();
340    this.collect1Expand = true;
341    this.collect2Expand = true;
342    this.icon1!.style.transform = 'rotateZ(0deg)';
343    this.icon2!.style.transform = 'rotateZ(0deg)';
344    this.collectRowList1.forEach((row) => {
345      row.clearMemory();
346    });
347    this.collectRowList2.forEach((row) => {
348      row.clearMemory();
349    });
350    this.collectRowList1 = [];
351    this.collectRowList2 = [];
352    this.fragmentGroup1 = document.createDocumentFragment();
353    this.fragmentGroup2 = document.createDocumentFragment();
354    this.collectEl1!.innerHTML = '';
355    this.collectEl2!.innerHTML = '';
356    this.updateGroupDisplay();
357    this.style.height = 'auto';
358  }
359
360  context(): CanvasRenderingContext2D | undefined | null {
361    return this.canvasCtx;
362  }
363
364  getCanvas(): HTMLCanvasElement | null | undefined {
365    return this.canvas;
366  }
367
368  connectedCallback(): void {
369    super.connectedCallback();
370    const vessel = this.parentNode as HTMLDivElement;
371    vessel.addEventListener('mousedown', this.onMouseDown);
372    vessel.addEventListener('mouseup', this.onMouseUp);
373    vessel.addEventListener('mousemove', this.onMouseMove);
374    vessel.addEventListener('mouseenter', this.onMouseEnter);
375    this.addEventListener('scroll', this.onScroll, { passive: true });
376  }
377
378  disconnectedCallback(): void {
379    super.disconnectedCallback();
380    const vessel = this.parentNode as HTMLDivElement;
381    vessel.removeEventListener('mousedown', this.onMouseDown);
382    vessel.removeEventListener('mouseup', this.onMouseUp);
383    vessel.removeEventListener('mousemove', this.onMouseMove);
384    vessel.removeEventListener('mouseenter', this.onMouseEnter);
385    this.removeEventListener('scroll', this.onScroll);
386  }
387
388  onScroll = (ev: Event): void => {
389    this.canvas!.style.transform = `translateY(${this.scrollTop}px)`;
390    if (this.scrollTimer) {
391      // @ts-ignore
392      clearTimeout(this.scrollTimer);
393    }
394    this.scrollTimer = setTimeout(() => {
395      TraceRow.range!.refresh = true;
396      window.publish(window.SmartEvent.UI.RefreshCanvas, {});
397    }, 100);
398    window.publish(window.SmartEvent.UI.RefreshCanvas, {});
399  };
400
401  onMouseEnter = (ev: MouseEvent): void => {
402    if (this.canResize && this.isPress) {
403      // @ts-ignore
404      if (ev?.buttons === 0) { // 0表示鼠标没有按键动作,说明此时鼠标已经松开,使收藏显示区域拖拽伸缩功能不可用
405        this.isPress = false;
406        this.canResize = false;
407        this.style.cursor = 'default';
408        // @ts-ignore
409        (window as unknown).collectResize = false;
410        if (this.style.display === 'flex') {
411          this.refreshFavoriteCanvas();
412        }
413      }
414    }
415  };
416
417  onMouseDown = (ev: MouseEvent): void => {
418    this.isPress = true;
419    this.startPageY = ev.pageY;
420    this.startClientHeight = this.clientHeight;
421    if (this.containPoint(ev)) {
422      if (
423        this.getBoundingClientRect().bottom > ev.pageY - mouseMoveRange &&
424        this.getBoundingClientRect().bottom < ev.pageY + mouseMoveRange
425      ) {
426        this.style.cursor = 'row-resize';
427        this.canResize = true;
428      } else {
429        this.style.cursor = 'default';
430        this.canResize = false;
431      }
432      // @ts-ignore
433      (window as unknown).collectResize = this.canResize;
434    }
435  };
436
437  onMouseMove = (ev: MouseEvent): void => {
438    if (this.containPoint(ev)) {
439      let inResizeArea =
440        this.getBoundingClientRect().bottom > ev.pageY - mouseMoveRange &&
441        this.getBoundingClientRect().bottom < ev.pageY + mouseMoveRange;
442      if ((this.isPress && this.canResize) || inResizeArea) {
443        this.style.cursor = 'row-resize';
444      } else {
445        this.style.cursor = 'default';
446      }
447    }
448    //防止点击触发move时间
449    if (Math.abs(ev.pageY - this.startPageY) < 2) {
450      return;
451    }
452    if (this.canResize && this.isPress) {
453      //@ts-ignore
454      if (!(window as unknown).collectResize) {
455        return;
456      }
457      // @ts-ignore
458      (window as unknown).collectResize = true;
459      // 拖动超过所有泳道最大高度 或小于一个泳道的高度,不支持拖动
460      let newHeight = this.startClientHeight + ev.pageY - this.startPageY;
461      if (newHeight > this.maxHeight) {
462        newHeight = this.maxHeight;
463      }
464      if (newHeight > this.getMaxLimitHeight()) {
465        newHeight = this.getMaxLimitHeight();
466      }
467      if (newHeight < minHeight) {
468        newHeight = minHeight;
469      }
470      this!.style.height = `${newHeight}px`;
471      this.manualHeight = newHeight;
472    } else {
473      // @ts-ignore
474      (window as unknown).collectResize = false;
475    }
476  };
477
478  onMouseUp = (ev: MouseEvent): void => {
479    this.isPress = false;
480    this.canResize = false;
481    this.style.cursor = 'default';
482    // @ts-ignore
483    (window as unknown).collectResize = false;
484    if (this.style.display === 'flex') {
485      this.refreshFavoriteCanvas();
486    }
487  };
488
489  // @ts-ignore
490  insertRow(row: TraceRow<unknown>, group: string, updateGroup: boolean): void {
491    this.style.display = 'flex';
492    let collectGroup = !updateGroup && row.collectGroup ? row.collectGroup : group;
493    if (row.collectGroup !== SpChartList.COLLECT_G1 && row.collectGroup !== SpChartList.COLLECT_G2) {
494      row.collectGroup = group;
495    }
496    if (updateGroup) {
497      row.collectGroup = group;
498    }
499    if (collectGroup === SpChartList.COLLECT_G1) {
500      if (!this.collect1Expand) {
501        this.collect1Expand = true;
502        this.icon1!.style.transform = 'rotateZ(0deg)';
503      }
504      if (this.collectRowList1.indexOf(row) === -1) {
505        this.collectRowList1.push(row);
506      }
507      if (!this.fragmentGroup1.contains(row)) {
508        this.fragmentGroup1.appendChild(row);
509      }
510      this.collectEl1?.appendChild(this.fragmentGroup1);
511      this.scrollTo({ top: this.collectEl1?.clientHeight });
512    } else {
513      if (!this.collect2Expand) {
514        this.collect2Expand = true;
515        this.icon2!.style.transform = 'rotateZ(0deg)';
516      }
517      if (this.collectRowList2.indexOf(row) === -1) {
518        this.collectRowList2.push(row);
519      }
520      if (!this.fragmentGroup2.contains(row)) {
521        this.fragmentGroup2.appendChild(row);
522      }
523      this.collectEl2!.appendChild(this.fragmentGroup2);
524      this.scrollTo({ top: this.scrollHeight });
525    }
526    this.updateGroupDisplay();
527    this.resizeHeight();
528    this.refreshFavoriteCanvas();
529    row.currentContext = this.canvasCtx;
530  }
531
532  // @ts-ignore
533  deleteRow(row: TraceRow<unknown>, clearCollectGroup: boolean): void {
534    if (row.collectGroup === SpChartList.COLLECT_G1) {
535      this.collectRowList1.splice(this.collectRowList1.indexOf(row), 1);
536      if (!this.fragmentGroup1.contains(row)) {
537        this.fragmentGroup1.appendChild(row);
538      }
539      this.fragmentGroup1.removeChild(row);
540    } else {
541      this.collectRowList2.splice(this.collectRowList2.indexOf(row), 1);
542      if (!this.fragmentGroup2.contains(row)) {
543        this.fragmentGroup2.appendChild(row);
544      }
545      this.fragmentGroup2.removeChild(row);
546    }
547    if (clearCollectGroup) {
548      row.collectGroup = undefined;
549    }
550    this.updateGroupDisplay();
551    this.resizeHeight();
552    this.scrollTop = 0;
553    this.refreshFavoriteCanvas();
554    row.currentContext = undefined;
555    if (this.collectRowList1.length === 0 && this.collectRowList2.length === 0) {
556      this.style.height = 'auto';
557      this.style.display = 'none';
558      this.manualHeight = 0;
559    }
560  }
561
562  hideCollectArea(): void {
563    if (this.collect1Expand) {
564      this.collectRowList1.forEach((row) => this.fragmentGroup1.appendChild(row));
565    }
566    if (this.collect2Expand) {
567      this.collectRowList2.forEach((row) => this.fragmentGroup2.appendChild(row));
568    }
569    this.groupTitle1!.style.display = 'none';
570    this.groupTitle2!.style.display = 'none';
571    this.resizeHeight();
572  }
573
574  showCollectArea(): void {
575    if (this.collect1Expand) {
576      this.collectEl1?.appendChild(this.fragmentGroup1);
577    }
578    if (this.collect2Expand) {
579      this.collectEl2?.appendChild(this.fragmentGroup2);
580    }
581    this.updateGroupDisplay();
582    this.resizeHeight();
583  }
584
585  updateGroupDisplay(): void {
586    this.groupTitle1!.style.display = this.collectRowList1.length === 0 ? 'none' : 'flex';
587    this.groupTitle2!.style.display = this.collectRowList2.length === 0 ? 'none' : 'flex';
588  }
589
590  hasCollectRow(): boolean {
591    return this.collectRowList2.length > 0 || this.collectRowList1.length > 0;
592  }
593
594  clearRect(): void {
595    this.canvasCtx?.clearRect(0, 0, this.canvas?.clientWidth ?? 0, this.canvas?.clientHeight ?? 0);
596  }
597
598  drawLines(xs: number[] | undefined, color: string): void {
599    drawLines(this.canvasCtx!, xs ?? [], this.clientHeight, color);
600  }
601
602  drawFlagLineSegment(
603    hoverFlag: Flag | undefined | null,
604    selectFlag: Flag | undefined | null,
605    tse: TimerShaftElement
606  ): void {
607    drawFlagLineSegment(
608      this.canvasCtx,
609      hoverFlag,
610      selectFlag,
611      new Rect(0, 0, TraceRow.FRAME_WIDTH, this.canvas?.clientHeight!),
612      tse
613    );
614  }
615
616  drawWakeUp(): void {
617    drawWakeUp(
618      this.canvasCtx,
619      CpuStruct.wakeupBean,
620      TraceRow.range!.startNS,
621      TraceRow.range!.endNS,
622      TraceRow.range!.totalNS,
623      new Rect(0, 0, TraceRow.FRAME_WIDTH, this.canvas?.clientHeight!)
624    );
625  }
626
627  drawWakeUpList(bean: WakeupBean): void {
628    drawWakeUpList(this.canvasCtx, bean, TraceRow.range!.startNS, TraceRow.range!.endNS, TraceRow.range!.totalNS, {
629      x: 0,
630      y: 0,
631      width: TraceRow.FRAME_WIDTH,
632      height: this.canvas!.clientHeight!,
633    } as Rect);
634  }
635
636  drawLogsLineSegment(bean: Flag | null | undefined, timeShaft: TimerShaftElement): void {
637    drawLogsLineSegment(
638      this.canvasCtx,
639      bean,
640      {
641        x: 0,
642        y: 0,
643        width: TraceRow.FRAME_WIDTH,
644        height: this.canvas!.clientHeight,
645      },
646      timeShaft
647    );
648  }
649
650  drawLinkLines(nodes: PairPoint[][], tse: TimerShaftElement, isFavorite: boolean, favoriteHeight: number): void {
651    drawLinkLines(this.canvasCtx!, nodes, tse, isFavorite, favoriteHeight);
652  }
653
654  refreshFavoriteCanvas(): void {
655    let sp = document.querySelector("body > sp-application")?.shadowRoot?.querySelector("#sp-system-trace") as SpSystemTrace;
656    let favoriteList = sp.shadowRoot?.querySelector("#favorite-chart-list") as SpChartList;
657    let popover = (favoriteList.shadowRoot?.querySelector("#collect-group-1 > trace-row")?.shadowRoot?.querySelector("#rowSetting") || favoriteList.shadowRoot?.querySelector("#collect-group-2 > trace-row")?.shadowRoot?.querySelector("#rowSetting")) as LitPopover;
658    let spChartList = document.querySelector("body > sp-application")?.shadowRoot?.querySelector("#sp-system-trace")?.shadowRoot?.querySelector("#favorite-chart-list");
659    this.canvas!.style.width = `${this.clientWidth - 248}px`;
660    this.canvas!.style.left = `248px`;
661    this.canvas!.width = this.canvas?.clientWidth! * dpr();
662    this.canvas!.height = this.clientHeight * dpr();
663    if (sp.collectRows && sp.collectRows.length) {
664      let isHiperf = sp.collectRows.some((row) => {
665        return row.rowId === 'HiPerf-callchart' && row.rowParentId === 'HiPerf';
666      });
667      let rowHeight = sp.collectRows.reduce((pre, row) => {
668        let height = row._frame?.height;
669        return pre + height!;
670      }, 0);
671      let titleHeight = sp.groupTitle1!.clientHeight || sp.groupTitle2!.clientHeight;
672      if (sp.collectEl1!.innerHTML.trim() !== '' && sp.collectEl2!.innerHTML.trim() !== '') {
673        titleHeight = titleHeight * 2;
674      }
675      let spChartListHeight = spChartList!.clientHeight * dpr();
676      let finalHeight = rowHeight + titleHeight > spChartListHeight ? spChartListHeight : rowHeight + titleHeight;
677      if (popover && isHiperf) {
678        favoriteList.style.height = popover.visible === 'true' ? `${this.canvas!.height}px` : `${finalHeight}px`;
679      }
680    }
681    this.canvas!.getContext('2d')!.scale(dpr(), dpr());
682    window.publish(window.SmartEvent.UI.RefreshCanvas, {});
683  }
684
685  private getHtmlCss(): string {
686    return `<style>
687    :host{
688        display: none;
689        width: 100%;
690        height: auto;
691        overflow-anchor: none;
692        z-index: 3;
693        box-shadow: 0 10px 10px #00000044;
694        position: relative;
695        overflow: auto;
696        overflow-x: hidden;
697        scroll-behavior: smooth;
698    }
699    .root{
700        width: 100%;
701        box-sizing: border-box;
702    }
703    .panel-canvas{
704        position: absolute;
705        top: 0;
706        right: 0;
707        bottom: 0;
708        box-sizing: border-box;
709    }
710    .icon:hover {
711     color:#ecb93f;
712    }
713    .icon {
714        margin-right: 10px;
715        cursor: pointer;
716    }
717    </style>`;
718  }
719
720  initHtml(): string {
721    return `
722 ${this.getHtmlCss()}
723<canvas id="canvas-panel" class="panel-canvas" ondragstart="return false"></canvas>
724<div class="root">
725    <div id="group-1-title" style="background-color: #efefef;padding: 10px;align-items: center">
726        <lit-icon id="group_1_expand" class="icon" name="caret-down" size="19"></lit-icon>
727        <span style="width: 184px;font-size: 10px;color: #898989">G1</span>
728        <lit-icon id="group_1_collect" name="star-fill" style="color: #5291FF;cursor: pointer" size="19"></lit-icon>
729    </div>
730    <div id="collect-group-1"></div>
731    <div id="group-2-title" style="background-color: #efefef;padding: 10px;align-items: center">
732        <lit-icon id="group_2_expand" class="icon" name="caret-down" size="19"></lit-icon>
733        <span style="width: 184px;font-size: 10px;color: #898989">G2</span>
734        <lit-icon id="group_2_collect" name="star-fill" style="color: #f56940;cursor: pointer" size="19"></lit-icon>
735    </div>
736    <div id="collect-group-2"></div>
737</div>
738`;
739  }
740}
741