• 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.js';
17import './trace/TimerShaftElement.js';
18import './trace/base/TraceRow.js';
19import {
20  queryBySelectAllocationOrReturn,
21  queryBySelectExecute,
22  queryEbpfSamplesCount,
23  querySceneSearchFunc,
24  querySearchFunc,
25  threadPool,
26} from '../database/SqlLite.js';
27import { RangeSelectStruct, TraceRow } from './trace/base/TraceRow.js';
28import { TimerShaftElement } from './trace/TimerShaftElement.js';
29import './trace/base/TraceSheet.js';
30import { TraceSheet } from './trace/base/TraceSheet.js';
31import { RangeSelect } from './trace/base/RangeSelect.js';
32import { SelectionParam } from '../bean/BoxSelection.js';
33import { procedurePool } from '../database/Procedure.js';
34import { SpApplication } from '../SpApplication.js';
35import { Flag } from './trace/timer-shaft/Flag.js';
36import { SportRuler, SlicesTime } from './trace/timer-shaft/SportRuler.js';
37import { SpHiPerf } from './chart/SpHiPerf.js';
38import { SearchSdkBean, SearchThreadProcessBean } from '../bean/SearchFuncBean.js';
39import { error, info } from '../../log/Log.js';
40import {
41  drawFlagLineSegment,
42  drawLines,
43  drawLinkLines,
44  drawWakeUp,
45  drawWakeUpList,
46  isFrameContainPoint,
47  LineType,
48  ns2x,
49  ns2xByTimeShaft,
50  PairPoint,
51  Rect,
52} from '../database/ui-worker/ProcedureWorkerCommon.js';
53import { SpChartManager } from './chart/SpChartManager.js';
54import { CpuStruct, WakeupBean } from '../database/ui-worker/ProcedureWorkerCPU.js';
55import { ProcessStruct } from '../database/ui-worker/ProcedureWorkerProcess.js';
56import { CpuFreqStruct } from '../database/ui-worker/ProcedureWorkerFreq.js';
57import { CpuFreqLimitsStruct } from '../database/ui-worker/ProcedureWorkerCpuFreqLimits.js';
58import { ThreadStruct } from '../database/ui-worker/ProcedureWorkerThread.js';
59import { func, FuncStruct } from '../database/ui-worker/ProcedureWorkerFunc.js';
60import { CpuStateStruct } from '../database/ui-worker/ProcedureWorkerCpuState.js';
61import { HiPerfCpuStruct } from '../database/ui-worker/ProcedureWorkerHiPerfCPU.js';
62import { HiPerfProcessStruct } from '../database/ui-worker/ProcedureWorkerHiPerfProcess.js';
63import { HiPerfThreadStruct } from '../database/ui-worker/ProcedureWorkerHiPerfThread.js';
64import { HiPerfEventStruct } from '../database/ui-worker/ProcedureWorkerHiPerfEvent.js';
65import { HiPerfReportStruct } from '../database/ui-worker/ProcedureWorkerHiPerfReport.js';
66import { FpsStruct } from '../database/ui-worker/ProcedureWorkerFPS.js';
67import { CpuAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerCpuAbility.js';
68import { DiskAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerDiskIoAbility.js';
69import { MemoryAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerMemoryAbility.js';
70import { NetworkAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerNetworkAbility.js';
71import { ClockStruct } from '../database/ui-worker/ProcedureWorkerClock.js';
72import { Utils } from './trace/base/Utils.js';
73import { IrqStruct } from '../database/ui-worker/ProcedureWorkerIrq.js';
74import { JanksStruct } from '../bean/JanksStruct.js';
75import { JankStruct } from '../database/ui-worker/ProcedureWorkerJank.js';
76import { tabConfig } from './trace/base/TraceSheetConfig.js';
77import { TabPaneCurrent } from './trace/sheet/TabPaneCurrent.js';
78import { LitTabpane } from '../../base-ui/tabs/lit-tabpane.js';
79import { HeapStruct } from '../database/ui-worker/ProcedureWorkerHeap.js';
80import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js';
81import { HeapSnapshotStruct } from '../database/ui-worker/ProcedureWorkerHeapSnapshot.js';
82import { HeapDataInterface } from '../../js-heap/HeapDataInterface.js';
83import { TabPaneSummary } from './trace/sheet/snapshot/TabPaneSummary.js';
84import { LitTabs } from '../../base-ui/tabs/lit-tabs.js';
85import { SpJsMemoryChart } from './chart/SpJsMemoryChart.js';
86import { TraceRowConfig } from './trace/base/TraceRowConfig.js';
87import { HeapTimelineStruct } from '../database/ui-worker/ProcedureWorkerHeapTimeline.js';
88import { TabPaneCurrentSelection } from './trace/sheet/TabPaneCurrentSelection.js';
89import { AppStartupStruct } from '../database/ui-worker/ProcedureWorkerAppStartup.js';
90import { SoStruct } from '../database/ui-worker/ProcedureWorkerSoInit.js';
91import { TabPaneTaskFrames } from './trace/sheet/task/TabPaneTaskFrames.js';
92import { FlagsConfig } from './SpFlags.js';
93
94function dpr() {
95  return window.devicePixelRatio || 1;
96}
97//节流处理
98function throttle(fn: any, t: number, ev: any): any {
99  let timer: any = null;
100  return function () {
101    if (!timer) {
102      timer = setTimeout(function () {
103        if (ev) {
104          fn(ev);
105        } else {
106          fn();
107        }
108        timer = null;
109      }, t);
110    }
111  };
112}
113
114@element('sp-system-trace')
115export class SpSystemTrace extends BaseElement {
116  static mouseCurrentPosition = 0;
117  static offsetMouse = 0;
118  static moveable = true;
119  static scrollViewWidth = 0;
120  static isCanvasOffScreen = true;
121  static DATA_DICT: Map<number, string> = new Map<number, string>();
122  static DATA_TASK_POOL_CALLSTACK: Map<number, { id: number; ts: number; dur: number; name: string }> = new Map<
123    number,
124    { id: number; ts: number; dur: number; name: string }
125  >();
126  static SDK_CONFIG_MAP: any;
127  static sliceRangeMark: any;
128  static wakeupList: Array<WakeupBean> = [];
129  intersectionObserver: IntersectionObserver | undefined;
130  tipEL: HTMLDivElement | undefined | null;
131  rowsEL: HTMLDivElement | undefined | null;
132  rowsPaneEL: HTMLDivElement | undefined | null;
133  spacerEL: HTMLDivElement | undefined | null;
134  favoriteRowsEL: HTMLDivElement | undefined | null;
135  visibleRows: Array<TraceRow<any>> = [];
136  collectRows: Array<TraceRow<any>> = [];
137  keyboardEnable = true;
138  currentRowType = ''; /*保存当前鼠标所在行的类型*/
139  observerScrollHeightEnable: boolean = false;
140  observerScrollHeightCallback: Function | undefined;
141  // @ts-ignore
142  observer = new ResizeObserver((entries) => {
143    if (this.observerScrollHeightEnable && this.observerScrollHeightCallback) {
144      this.observerScrollHeightCallback();
145    }
146  });
147  static btnTimer: any = null;
148  isMousePointInSheet = false;
149  hoverFlag: Flag | undefined | null = undefined;
150  selectFlag: Flag | undefined | null;
151  slicestime: SlicesTime | undefined | null = null;
152  public timerShaftEL: TimerShaftElement | null | undefined;
153  private traceSheetEL: TraceSheet | undefined | null;
154  private rangeSelect!: RangeSelect;
155  private chartManager: SpChartManager | undefined | null;
156  private loadTraceCompleted: boolean = false;
157  private rangeTraceRow: Array<TraceRow<any>> | undefined = [];
158  canvasFavoritePanel: HTMLCanvasElement | null | undefined; //绘制收藏泳道图
159  canvasFavoritePanelCtx: CanvasRenderingContext2D | null | undefined;
160  canvasPanel: HTMLCanvasElement | null | undefined; //绘制取消收藏后泳道图
161  canvasPanelCtx: CanvasRenderingContext2D | undefined | null;
162  linkNodes: PairPoint[][] = [];
163  public currentClickRow: HTMLDivElement | undefined | null;
164  private litTabs: LitTabs | undefined | null;
165  eventMap: any = {};
166  private isSelectClick: boolean = false;
167  private selectionParam: SelectionParam | undefined;
168
169  addPointPair(a: PairPoint, b: PairPoint) {
170    if (a.rowEL.collect) {
171      a.rowEL.translateY = a.rowEL.getBoundingClientRect().top - 195;
172    } else {
173      a.rowEL.translateY = a.rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
174    }
175    if (b.rowEL.collect) {
176      b.rowEL.translateY = b.rowEL.getBoundingClientRect().top - 195;
177    } else {
178      b.rowEL.translateY = b.rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
179    }
180    a.y = a.rowEL!.translateY! + a.offsetY;
181    b.y = b.rowEL!.translateY! + b.offsetY;
182    this.linkNodes.push([a, b]);
183  }
184
185  clearPointPair() {
186    this.linkNodes.length = 0;
187  }
188
189  removeLinkLinesByBusinessType(...businessTypes: string[]) {
190    this.linkNodes = this.linkNodes.filter((pointPair) => {
191      return !(businessTypes.indexOf(pointPair[0].business) > -1);
192    });
193  }
194
195  hiddenLinkLinesByBusinessType(...businessTypes: string[]) {
196    this.linkNodes.map((value) => {
197      if (businessTypes.indexOf(value[0].business) !== -1) {
198        value[0].hidden = true;
199        value[1].hidden = true;
200      }
201    });
202  }
203
204  showLinkLinesByBusinessType(...businessTypes: string[]) {
205    this.linkNodes.map((value) => {
206      if (businessTypes.indexOf(value[0].business) !== -1) {
207        value[0].hidden = false;
208        value[1].hidden = false;
209      }
210    });
211  }
212
213  initElements(): void {
214    let sideColor = document!.querySelector("body > sp-application")!.shadowRoot!.querySelector!("#main-menu")?.
215      shadowRoot?.querySelector("div.bottom > div.color");
216    let rightButton: HTMLElement | null | undefined =
217      this.shadowRoot?.querySelector("div > trace-sheet")?.shadowRoot?.
218      querySelector("#current-selection > tabpane-current-selection")?.shadowRoot?.querySelector("#rightButton")
219    this.rowsEL = this.shadowRoot?.querySelector<HTMLDivElement>('.rows');
220    this.tipEL = this.shadowRoot?.querySelector<HTMLDivElement>('.tip');
221    this.rowsPaneEL = this.shadowRoot?.querySelector<HTMLDivElement>('.rows-pane');
222    this.spacerEL = this.shadowRoot?.querySelector<HTMLDivElement>('.spacer');
223    this.canvasFavoritePanel = this.shadowRoot?.querySelector<HTMLCanvasElement>('.panel-canvas-favorite');
224    this.timerShaftEL = this.shadowRoot?.querySelector('.timer-shaft');
225    this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet');
226    this.favoriteRowsEL = this.shadowRoot?.querySelector('.favorite-rows');
227    this.rangeSelect = new RangeSelect(this);
228    rightButton?.addEventListener('click', (event: any) => {
229      if (SpSystemTrace.btnTimer) {
230        return;
231      }
232      this.wakeupListNull();
233      SpSystemTrace.wakeupList.unshift(CpuStruct.wakeupBean!);
234      this.queryCPUWakeUpList(CpuStruct.wakeupBean!);
235      setTimeout(() => {
236        requestAnimationFrame(() => this.refreshCanvas(false));
237      }, 300);
238      SpSystemTrace.btnTimer = setTimeout(() => {
239        SpSystemTrace.btnTimer = null; // 2.清空节流阀,方便下次开启定时器
240      }, 2000);
241    });
242    sideColor?.addEventListener('click', (event: any) => {
243      requestAnimationFrame(() => this.refreshCanvas(true));
244    });
245    document?.addEventListener('triangle-flag', (event: any) => {
246      let temporaryTime = this.timerShaftEL?.drawTriangle(event.detail.time, event.detail.type);
247      if (event.detail.timeCallback && temporaryTime) event.detail.timeCallback(temporaryTime);
248    });
249    document?.addEventListener('flag-change', (event: any) => {
250      this.timerShaftEL?.modifyFlagList(event.detail);
251      if (event.detail.hidden) {
252        this.selectFlag = undefined;
253        this.traceSheetEL?.setAttribute('mode', 'hidden');
254        this.refreshCanvas(true);
255      }
256    });
257    document?.addEventListener('slices-change', (event: any) => {
258      this.timerShaftEL?.modifySlicesList(event.detail);
259      if (event.detail.hidden) {
260        this.slicestime = null;
261        this.traceSheetEL?.setAttribute('mode', 'hidden');
262        this.refreshCanvas(true);
263      }
264    });
265    if (this.timerShaftEL?.collecBtn) {
266      this.timerShaftEL.collecBtn.onclick = () => {
267        if (this.timerShaftEL!.collecBtn!.hasAttribute('close')) {
268          this.timerShaftEL!.collecBtn!.removeAttribute('close');
269        } else {
270          this.timerShaftEL!.collecBtn!.setAttribute('close', '');
271        }
272        if (this.collectRows.length > 0) {
273          this.collectRows.forEach((row) => {
274            row?.collectEL?.onclick?.(new MouseEvent('auto-collect', undefined));
275          });
276        }
277      };
278    }
279    document?.addEventListener('collect', (event: any) => {
280      let currentRow = event.detail.row;
281      if (currentRow.collect) {
282        if (
283          !this.collectRows.find((find) => {
284            return find === currentRow;
285          })
286        ) {
287          this.collectRows.push(currentRow);
288        }
289        if (event.detail.type !== 'auto-collect' && this.timerShaftEL!.collecBtn!.hasAttribute('close')) {
290          currentRow.collect = false;
291          this.timerShaftEL!.collecBtn!.click();
292          return;
293        }
294        let replaceRow = document.createElement('div');
295        replaceRow.setAttribute('row-id', currentRow.rowId + '-' + currentRow.rowType);
296        replaceRow.setAttribute('type', 'replaceRow');
297        replaceRow.setAttribute('row-parent-id', currentRow.rowParentId);
298        replaceRow.style.display = 'none';
299        currentRow.rowHidden = !currentRow.hasAttribute('scene');
300        // 添加收藏时,在线程名前面追加父亲ID
301        let rowParentId = currentRow.rowParentId;
302        if (rowParentId) {
303          let parentRows = this.shadowRoot?.querySelectorAll<TraceRow<any>>(`trace-row[row-id='${rowParentId}']`);
304          parentRows?.forEach((parentRow) => {
305            if (
306              parentRow?.name &&
307              parentRow?.name != currentRow.name &&
308              !parentRow.rowType!.startsWith('cpu') &&
309              !parentRow.rowType!.startsWith('thread') &&
310              !parentRow.rowType!.startsWith('func')
311            ) {
312              currentRow.name += '(' + parentRow.name + ')';
313            }
314          });
315        }
316        if (this.rowsEL!.contains(currentRow)) {
317          this.rowsEL!.replaceChild(replaceRow, currentRow);
318        } else {
319          if (currentRow.hasParentRowEl) {
320            let parent = currentRow.parentRowEl;
321            parent!.replaceTraceRow(replaceRow, currentRow);
322          }
323        }
324        this.favoriteRowsEL!.append(currentRow);
325      } else {
326        this.favoriteRowsEL!.removeChild(currentRow);
327        if (event.detail.type !== 'auto-collect') {
328          let rowIndex = this.collectRows.indexOf(currentRow);
329          if (rowIndex !== -1) {
330            this.collectRows.splice(rowIndex, 1);
331          }
332        }
333        let row = currentRow;
334        let allowExpansionRow = [];
335        while (row.hasParentRowEl) {
336          let parent = row.parentRowEl;
337          allowExpansionRow.push(parent);
338          row = parent;
339        }
340        for (let index: number = allowExpansionRow.length - 1; index >= 0; index--) {
341          if (!allowExpansionRow[index]?.expansion && allowExpansionRow[index]?.hasAttribute('scene')) {
342            allowExpansionRow[index].expansion = true;
343          }
344        }
345        allowExpansionRow.length = 0;
346        let replaceRow = this.rowsEL!.querySelector<HTMLCanvasElement>(
347          `div[row-id='${currentRow.rowId}-${currentRow.rowType}']`
348        );
349        if (replaceRow != null) {
350          // 取消收藏时,删除父亲ID
351          let rowNameArr = currentRow.name.split('(');
352          if (rowNameArr.length > 1) {
353            let tempName = '';
354            tempName += rowNameArr[0];
355            currentRow.name = tempName;
356          } else {
357            currentRow.name = rowNameArr[0];
358          }
359          this.rowsEL!.replaceChild(currentRow, replaceRow);
360          currentRow.style.boxShadow = `0 10px 10px #00000000`;
361        }
362        this.canvasFavoritePanel!.style.transform = `translateY(${
363          this.favoriteRowsEL!.scrollTop - currentRow.clientHeight
364        }px)`;
365      }
366      this.timerShaftEL?.displayCollect(this.collectRows.length !== 0);
367      this.refreshFavoriteCanvas();
368      this.refreshCanvas(true);
369      this.linkNodes.forEach((itln) => {
370        if (itln[0].rowEL === currentRow) {
371          if (itln[0].rowEL.collect) {
372            itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195;
373          } else {
374            itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
375          }
376          itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY;
377        } else if (itln[1].rowEL === currentRow) {
378          if (itln[1].rowEL.collect) {
379            itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195;
380          } else {
381            itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
382          }
383          itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY;
384        }
385      });
386      // 收藏夹元素拖动排序功能
387      this.currentClickRow = null;
388      currentRow.setAttribute('draggable', 'true');
389      currentRow.addEventListener('dragstart', () => {
390        this.currentClickRow = currentRow;
391      });
392      currentRow.addEventListener('dragover', (ev: any) => {
393        ev.preventDefault();
394        ev.dataTransfer.dropEffect = 'move';
395      });
396      currentRow.addEventListener('drop', (ev: any) => {
397        if (this.favoriteRowsEL != null && this.currentClickRow != null && this.currentClickRow !== currentRow) {
398          let rect = currentRow.getBoundingClientRect();
399          if (ev.clientY >= rect.top && ev.clientY < rect.top + rect.height / 2) {
400            //向上移动
401            this.favoriteRowsEL.insertBefore(this.currentClickRow, currentRow);
402          } else if (ev.clientY <= rect.bottom && ev.clientY > rect.top + rect.height / 2) {
403            //向下移动
404            this.favoriteRowsEL.insertBefore(this.currentClickRow, currentRow.nextSibling);
405          }
406          this.refreshFavoriteCanvas();
407        }
408      });
409      currentRow.addEventListener('dragend', () => {
410        this.linkNodes.forEach((itln) => {
411          if (itln[0].rowEL.collect) {
412            itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195;
413          } else {
414            itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
415          }
416          if (itln[1].rowEL.collect) {
417            itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195;
418          } else {
419            itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
420          }
421          itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY;
422          itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY;
423        });
424        this.currentClickRow = null;
425      });
426    });
427    SpSystemTrace.scrollViewWidth = this.getScrollWidth();
428    this.rangeSelect.selectHandler = (rows, refreshCheckBox) => {
429      rows.forEach((item) => {
430        this.setAttribute('clickRow', item.rowType!);
431        this.setAttribute('rowName', item.name);
432        this.setAttribute('rowId', item.rowId!);
433      });
434      if (rows.length == 0) {
435        this.shadowRoot!.querySelectorAll<TraceRow<any>>('trace-row').forEach((it) => {
436          it.checkType = '-1';
437          if (it.folder) {
438            it.childrenList.forEach((item) => {
439              it.checkType = '-1';
440            });
441          }
442        });
443        this.refreshCanvas(true);
444        this.traceSheetEL?.setAttribute('mode', 'hidden');
445        return;
446      }
447      if (refreshCheckBox) {
448        if (rows.length > 0) {
449          this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach((row) => {
450            row.checkType = '0';
451            if (row.folder) {
452              row.childrenList.forEach((ite) => {
453                ite.checkType = '0';
454              });
455            }
456          });
457          rows.forEach((it) => {
458            it.checkType = '2';
459          });
460        } else {
461          this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach((row) => {
462            row.checkType = '-1';
463            if (row.folder) {
464              row.childrenList.forEach((it) => {
465                it.checkType = '-1';
466              });
467            }
468          });
469          return;
470        }
471      }
472      if (!this.isSelectClick) {
473        this.rangeTraceRow = [];
474      }
475      let selection = new SelectionParam();
476      selection.leftNs = 0;
477      selection.rightNs = 0;
478      selection.recordStartNs = (window as any).recordStartNS;
479      let native_memory = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'];
480      rows.forEach((it) => {
481        if (it.rowType == TraceRow.ROW_TYPE_CPU) {
482          selection.cpus.push(parseInt(it.rowId!));
483          info('load CPU traceRow id is : ', it.rowId);
484        } else if (it.rowType == TraceRow.ROW_TYPE_CPU_STATE) {
485          let filterId = parseInt(it.rowId!);
486          if (selection.cpuStateFilterIds.indexOf(filterId) == -1) {
487            selection.cpuStateFilterIds.push(filterId);
488          }
489        } else if (it.rowType == TraceRow.ROW_TYPE_CPU_FREQ) {
490          let filterId = parseInt(it.rowId!);
491          if (selection.cpuFreqFilterIds.indexOf(filterId) == -1) {
492            selection.cpuFreqFilterIds.push(filterId);
493          }
494        } else if (it.rowType == TraceRow.ROW_TYPE_CPU_FREQ_LIMIT) {
495          selection.cpuFreqLimitDatas.push(it.dataList!);
496        } else if (it.rowType == TraceRow.ROW_TYPE_PROCESS) {
497          this.pushPidToSelection(selection, it.rowId!);
498          if (it.getAttribute('hasStartup') === 'true') {
499            selection.startup = true;
500          }
501          if (it.getAttribute('hasStaticInit') === 'true') {
502            selection.staticInit = true;
503          }
504          let processChildRows: Array<TraceRow<any>> = [
505            ...this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`),
506          ];
507          if (!it.expansion) {
508            processChildRows = [...it.childrenList];
509          }
510          selection.processIds.push(parseInt(it.rowId!));
511          processChildRows.forEach((th) => {
512            th.rangeSelect = true;
513            th.checkType = '2';
514            if (th.rowType == TraceRow.ROW_TYPE_THREAD) {
515              selection.threadIds.push(parseInt(th.rowId!));
516            } else if (th.rowType == TraceRow.ROW_TYPE_FUNC) {
517              if (th.asyncFuncName) {
518                selection.funAsync.push({
519                  name: th.asyncFuncName,
520                  pid: th.asyncFuncNamePID || 0,
521                });
522              } else {
523                selection.funTids.push(parseInt(th.rowId!));
524              }
525            } else if (th.rowType == TraceRow.ROW_TYPE_MEM) {
526              selection.processTrackIds.push(parseInt(th.rowId!));
527            }
528          });
529          info('load process traceRow id is : ', it.rowId);
530        } else if (it.rowType == TraceRow.ROW_TYPE_NATIVE_MEMORY) {
531          let memoryRows: Array<TraceRow<any>> = [
532            ...this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`),
533          ];
534          if (!it.expansion) {
535            memoryRows = [...it.childrenList];
536          }
537          memoryRows.forEach((th) => {
538            th.rangeSelect = true;
539            th.checkType = '2';
540            if (th.getAttribute('heap-type') === 'native_hook_statistic') {
541              selection.nativeMemoryStatistic.push(th.rowId!);
542            } else {
543              selection.nativeMemory.push(th.rowId!);
544            }
545          });
546          info('load nativeMemory traceRow id is : ', it.rowId);
547        } else if (it.rowType == TraceRow.ROW_TYPE_STATIC_INIT) {
548          selection.staticInit = true;
549          this.pushPidToSelection(selection, it.rowParentId!);
550          info('load thread traceRow id is : ', it.rowId);
551        } else if (it.rowType == TraceRow.ROW_TYPE_APP_STARTUP) {
552          selection.startup = true;
553          this.pushPidToSelection(selection, it.rowParentId!);
554          info('load thread traceRow id is : ', it.rowId);
555        } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) {
556          this.pushPidToSelection(selection, it.rowParentId!);
557          selection.threadIds.push(parseInt(it.rowId!));
558          info('load thread traceRow id is : ', it.rowId);
559        } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) {
560          TabPaneTaskFrames.TaskArray = [];
561          this.pushPidToSelection(selection, it.rowParentId!);
562          if (it.asyncFuncName) {
563            selection.funAsync.push({
564              name: it.asyncFuncName,
565              pid: it.asyncFuncNamePID || 0,
566            });
567          } else {
568            selection.funTids.push(parseInt(it.rowId!));
569          }
570
571          let isIntersect = (a: FuncStruct, b: RangeSelectStruct) =>
572            Math.max(a.startTs! + a.dur!, b!.endNS || 0) - Math.min(a.startTs!, b!.startNS || 0) <
573              a.dur! + (b!.endNS || 0) - (b!.startNS || 0) && a.funName!.indexOf('H:Task ') >= 0;
574          let taskData = it.dataList.filter((taskData: FuncStruct) => {
575            taskData!.tid = parseInt(it.rowId!);
576            return isIntersect(taskData, TraceRow.rangeSelectObject!);
577          });
578          if (taskData.length > 0) {
579            selection.taskFramesData.push(taskData);
580          }
581          info('load func traceRow id is : ', it.rowId);
582        } else if (it.rowType == TraceRow.ROW_TYPE_MEM || it.rowType == TraceRow.ROW_TYPE_VIRTUAL_MEMORY) {
583          if (it.rowType == TraceRow.ROW_TYPE_MEM) {
584            selection.processTrackIds.push(parseInt(it.rowId!));
585          } else {
586            selection.virtualTrackIds.push(parseInt(it.rowId!));
587          }
588          info('load memory traceRow id is : ', it.rowId);
589        } else if (it.rowType == TraceRow.ROW_TYPE_FPS) {
590          selection.hasFps = true;
591          info('load FPS traceRow id is : ', it.rowId);
592        } else if (it.rowType == TraceRow.ROW_TYPE_HEAP) {
593          if (it.getAttribute('heap-type') === 'native_hook_statistic') {
594            selection.nativeMemoryStatistic.push(it.rowId!);
595          } else {
596            selection.nativeMemory.push(it.rowId!);
597          }
598          info('load nativeMemory traceRow id is : ', it.rowId);
599        } else if (it.rowType == TraceRow.ROW_TYPE_MONITOR) {
600          let abilityChildRows: Array<TraceRow<any>> = [
601            ...this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`),
602          ];
603          if (!it.expansion) {
604            abilityChildRows = [...it.childrenList];
605          }
606          abilityChildRows.forEach((th) => {
607            th.rangeSelect = true;
608            th.checkType = '2';
609            if (th.rowType == TraceRow.ROW_TYPE_CPU_ABILITY) {
610              selection.cpuAbilityIds.push(th.rowId!);
611            } else if (th.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY) {
612              selection.memoryAbilityIds.push(th.rowId!);
613            } else if (th.rowType == TraceRow.ROW_TYPE_DISK_ABILITY) {
614              selection.diskAbilityIds.push(th.rowId!);
615            } else if (th.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY) {
616              selection.networkAbilityIds.push(th.rowId!);
617            }
618          });
619        } else if (it.rowType == TraceRow.ROW_TYPE_CPU_ABILITY) {
620          selection.cpuAbilityIds.push(it.rowId!);
621          info('load CPU Ability traceRow id is : ', it.rowId);
622        } else if (it.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY) {
623          selection.memoryAbilityIds.push(it.rowId!);
624          info('load Memory Ability traceRow id is : ', it.rowId);
625        } else if (it.rowType == TraceRow.ROW_TYPE_DISK_ABILITY) {
626          selection.diskAbilityIds.push(it.rowId!);
627          info('load DiskIo Ability traceRow id is : ', it.rowId);
628        } else if (it.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY) {
629          selection.networkAbilityIds.push(it.rowId!);
630          info('load Network Ability traceRow id is : ', it.rowId);
631        } else if (it.rowType?.startsWith(TraceRow.ROW_TYPE_SDK)) {
632          if (it.rowType == TraceRow.ROW_TYPE_SDK) {
633            let sdkRows: Array<TraceRow<any>> = [
634              ...this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`),
635            ];
636            if (!it.expansion) {
637              sdkRows = [...it.childrenList];
638            }
639            sdkRows.forEach((th) => {
640              th.rangeSelect = true;
641              th.checkType = '2';
642            });
643          }
644          if (it.rowType == TraceRow.ROW_TYPE_SDK_COUNTER) {
645            selection.sdkCounterIds.push(it.rowId!);
646          }
647          if (it.rowType == TraceRow.ROW_TYPE_SDK_SLICE) {
648            selection.sdkSliceIds.push(it.rowId!);
649          }
650        } else if (it.rowType?.startsWith('hiperf')) {
651          if (it.rowType == TraceRow.ROW_TYPE_HIPERF_EVENT || it.rowType == TraceRow.ROW_TYPE_HIPERF_REPORT) {
652            return;
653          }
654          selection.perfSampleIds.push(1);
655          if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) {
656            let hiperfProcessRows: Array<TraceRow<any>> = [
657              ...this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`),
658            ];
659            if (!it.expansion) {
660              hiperfProcessRows = [...it.childrenList];
661            }
662            hiperfProcessRows.forEach((th) => {
663              th.rangeSelect = true;
664              th.checkType = '2';
665            });
666          }
667          if (it.rowType == TraceRow.ROW_TYPE_HIPERF || it.rowId == 'HiPerf-cpu-merge') {
668            selection.perfAll = true;
669          }
670          if (it.rowType == TraceRow.ROW_TYPE_HIPERF_CPU) {
671            selection.perfCpus.push(it.index);
672          }
673          if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) {
674            selection.perfProcess.push(parseInt(it.rowId!.split('-')[0]));
675          }
676          if (it.rowType == TraceRow.ROW_TYPE_HIPERF_THREAD) {
677            selection.perfThread.push(parseInt(it.rowId!.split('-')[0]));
678          }
679        } else if (it.rowType == TraceRow.ROW_TYPE_FILE_SYSTEM) {
680          if (it.rowId == 'FileSystemLogicalWrite') {
681            if (selection.fileSystemType.length == 0) {
682              selection.fileSystemType = [0, 1, 3];
683            } else {
684              if (selection.fileSystemType.indexOf(3) == -1) {
685                selection.fileSystemType.push(3);
686              }
687            }
688          } else if (it.rowId == 'FileSystemLogicalRead') {
689            if (selection.fileSystemType.length == 0) {
690              selection.fileSystemType = [0, 1, 2];
691            } else {
692              if (selection.fileSystemType.indexOf(2) == -1) {
693                selection.fileSystemType.push(2);
694              }
695            }
696          } else if (it.rowId == 'FileSystemVirtualMemory') {
697            selection.fileSysVirtualMemory = true;
698          } else if (it.rowId == 'FileSystemDiskIOLatency') {
699            selection.diskIOLatency = true;
700          } else {
701            if (!selection.diskIOLatency) {
702              let arr = it.rowId!.split('-').reverse();
703              let ipid = parseInt(arr[0]);
704              if (selection.diskIOipids.indexOf(ipid) == -1) {
705                selection.diskIOipids.push(ipid);
706              }
707              if (arr[1] == 'read') {
708                selection.diskIOReadIds.indexOf(ipid) == -1 ? selection.diskIOReadIds.push(ipid) : '';
709              } else if (arr[1] == 'write') {
710                selection.diskIOWriteIds.indexOf(ipid) == -1 ? selection.diskIOWriteIds.push(ipid) : '';
711              }
712            }
713          }
714        } else if (it.rowType == TraceRow.ROW_TYPE_POWER_ENERGY) {
715          selection.powerEnergy.push(it.rowId!);
716        } else if (it.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) {
717          selection.systemEnergy.push(it.rowId!);
718        } else if (it.rowType == TraceRow.ROW_TYPE_ANOMALY_ENERGY) {
719          selection.anomalyEnergy.push(it.rowId!);
720        } else if (it.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) {
721          info('load anomaly Energy traceRow id is : ', it.rowId);
722        } else if (it.rowType == TraceRow.ROW_TYPE_SMAPS) {
723          selection.smapsType.push(it.rowId!);
724        } else if (it.rowType == TraceRow.ROW_TYPE_CLOCK) {
725          selection.clockMapData.set(
726            it.rowId || '',
727            it.dataList.filter((clockData) => {
728              return Utils.getTimeIsCross(
729                clockData.startNS,
730                clockData.startNS + clockData.dur,
731                TraceRow.rangeSelectObject?.startNS || 0,
732                TraceRow.rangeSelectObject?.endNS || 0
733              );
734            })
735          );
736        } else if (it.rowType == TraceRow.ROW_TYPE_IRQ) {
737          it.dataList.forEach((irqData) => {
738            if (
739              Utils.getTimeIsCross(
740                irqData.startNS,
741                irqData.startNS + irqData.dur,
742                TraceRow.rangeSelectObject?.startNS || 0,
743                TraceRow.rangeSelectObject?.endNS || 0
744              )
745            ) {
746              if (selection.irqMapData.has(irqData.name)) {
747                selection.irqMapData.get(irqData.name)?.push(irqData);
748              } else {
749                selection.irqMapData.set(irqData.name, [irqData]);
750              }
751            }
752          });
753        } else if (it.rowType == TraceRow.ROW_TYPE_JANK) {
754          let isIntersect = (a: JanksStruct, b: RangeSelectStruct) =>
755            Math.max(a.ts! + a.dur!, b!.endNS || 0) - Math.min(a.ts!, b!.startNS || 0) <
756            a.dur! + (b!.endNS || 0) - (b!.startNS || 0);
757          if (it.name == 'Actual Timeline') {
758            selection.jankFramesData = [];
759            let jankDatas = it.dataList.filter((jankData: any) => {
760              return isIntersect(jankData, TraceRow.rangeSelectObject!);
761            });
762            selection.jankFramesData.push(jankDatas);
763          } else if (it.folder) {
764            selection.jankFramesData = [];
765            it.childrenList.forEach((child) => {
766              if (child.rowType == TraceRow.ROW_TYPE_JANK && child.name == 'Actual Timeline') {
767                let jankDatas = child.dataList.filter((jankData: any) => {
768                  return isIntersect(jankData, TraceRow.rangeSelectObject!);
769                });
770                selection.jankFramesData.push(jankDatas);
771              }
772            });
773          }
774        } else if (it.rowType === TraceRow.ROW_TYPE_HEAP_TIMELINE || it.rowType === TraceRow.ROW_TYPE_JS_MEMORY) {
775          selection.jsMemory.push(it.rowId);
776          let jsMemoryRows: Array<TraceRow<HeapTimelineStruct>> = [
777            ...this.shadowRoot!.querySelectorAll<TraceRow<HeapTimelineStruct>>(
778              `trace-row[row-parent-id='${it.rowId}']`
779            ),
780          ];
781          if (!it.expansion) {
782            jsMemoryRows = [...it.childrenList];
783          }
784          jsMemoryRows.forEach((th) => {
785            if (th.rowType === TraceRow.ROW_TYPE_HEAP_TIMELINE) {
786              it.dataList.length === 0 ? th.dataList : it.dataList;
787              selection.jsMemory.push(th.rowId);
788            } else {
789              selection.jsMemory = [];
790            }
791          });
792          let endNS = TraceRow.rangeSelectObject?.endNS ? TraceRow.rangeSelectObject?.endNS : TraceRow.range?.endNS;
793          let startNS = TraceRow.rangeSelectObject?.startNS
794            ? TraceRow.rangeSelectObject?.startNS
795            : TraceRow.range?.startNS;
796          let minNodeId, maxNodeId;
797          if (!it.dataList || it.dataList.length === 0) {
798            return;
799          }
800          for (let sample of it.dataList) {
801            if (sample.timestamp * 1000 <= startNS!) {
802              minNodeId = sample.lastAssignedId;
803            }
804            if (sample.timestamp * 1000 >= endNS!) {
805              if (maxNodeId === undefined) {
806                maxNodeId = sample.lastAssignedId;
807              }
808            }
809          }
810
811          // If the start time range of the selected box is greater than the end time of the sampled data
812          if (startNS! >= it.dataList[it.dataList.length - 1].timestamp * 1000) {
813            minNodeId = it.dataList[it.dataList.length - 1].lastAssignedId;
814          }
815          // If you select the box from the beginning
816          if (startNS! <= TraceRow.range?.startNS!) {
817            minNodeId = HeapDataInterface.getInstance().getMinNodeId(SpJsMemoryChart.file.id);
818          }
819          //If you select the box from the ending
820          if (endNS! >= TraceRow.range?.endNS! || endNS! >= it.dataList[it.dataList.length - 1].timestampUs * 1000) {
821            maxNodeId = HeapDataInterface.getInstance().getMaxNodeId(SpJsMemoryChart.file.id);
822          }
823          let summary = (this.traceSheetEL?.shadowRoot?.querySelector('#tabs') as LitTabs)
824            ?.querySelector('#box-heap-summary')
825            ?.querySelector('tabpane-summary') as TabPaneSummary;
826          summary.initSummaryData(SpJsMemoryChart.file, minNodeId, maxNodeId);
827        }
828        if (this.rangeTraceRow!.length !== rows.length) {
829          let event = this.createPointEvent(it);
830          SpStatisticsHttpUtil.addOrdinaryVisitAction({
831            action: 'trace_row',
832            event: event,
833          });
834        }
835      });
836      this.rangeTraceRow = rows;
837      this.isSelectClick = false;
838      if (selection.diskIOipids.length > 0 && !selection.diskIOLatency) {
839        selection.promiseList.push(
840          queryEbpfSamplesCount(
841            TraceRow.rangeSelectObject?.startNS || 0,
842            TraceRow.rangeSelectObject?.endNS || 0,
843            selection.diskIOipids
844          ).then((res) => {
845            if (res.length > 0) {
846              selection.fsCount = res[0].fsCount;
847              selection.vmCount = res[0].vmCount;
848            }
849            return new Promise((resolve) => resolve(1));
850          })
851        );
852      }
853      selection.leftNs = TraceRow.rangeSelectObject?.startNS || 0;
854      selection.rightNs = TraceRow.rangeSelectObject?.endNS || 0;
855      this.selectStructNull();
856      this.timerShaftEL?.removeTriangle('inverted');
857      if (selection.promiseList.length > 0) {
858        Promise.all(selection.promiseList).then(() => {
859          selection.promiseList = [];
860          this.traceSheetEL?.rangeSelect(selection);
861        });
862      } else {
863        this.traceSheetEL?.rangeSelect(selection);
864      }
865      this.timerShaftEL!.selectionList.push(selection); // 保持选中对象,为后面的再次选中该框选区域做准备。
866      this.selectionParam = selection;
867    };
868    // @ts-ignore
869    new ResizeObserver((entries) => {
870      TraceRow.FRAME_WIDTH = this.clientWidth - 249 - this.getScrollWidth();
871      requestAnimationFrame(() => {
872        this.timerShaftEL?.updateWidth(this.clientWidth - 1 - this.getScrollWidth());
873        this.shadowRoot!.querySelectorAll<TraceRow<any>>('trace-row').forEach((it) => {
874          it.updateWidth(this.clientWidth);
875        });
876      });
877    }).observe(this);
878
879    new ResizeObserver((entries) => {
880      this.canvasPanelConfig();
881      if (this.traceSheetEL!.getAttribute('mode') == 'hidden') {
882        this.timerShaftEL?.removeTriangle('triangle');
883      }
884      this.refreshFavoriteCanvas();
885      this.refreshCanvas(true);
886    }).observe(this.rowsPaneEL!);
887    new MutationObserver((mutations, observer) => {
888      for (const mutation of mutations) {
889        if (mutation.type === 'attributes') {
890          if (this.style.visibility === 'visible') {
891            if (TraceRow.rangeSelectObject && SpSystemTrace.sliceRangeMark) {
892              this.timerShaftEL?.setSlicesMark(
893                TraceRow.rangeSelectObject.startNS || 0,
894                TraceRow.rangeSelectObject.endNS || 0,
895                false
896              );
897              SpSystemTrace.sliceRangeMark = undefined;
898              window.publish(window.SmartEvent.UI.RefreshCanvas, {});
899            }
900          }
901        }
902      }
903    }).observe(this, {
904      attributes: true,
905      childList: false,
906      subtree: false,
907    });
908
909    this.intersectionObserver = new IntersectionObserver((entries) => {
910      entries.forEach((it) => {
911        let tr = it.target as TraceRow<any>;
912        if (!it.isIntersecting) {
913          tr.sleeping = true;
914          this.visibleRows = this.visibleRows.filter((it) => !it.sleeping);
915        } else {
916          if (
917            !this.visibleRows.find(
918              (vr) => vr.rowId === tr.rowId && vr.rowType === tr.rowType && vr.rowParentId === tr.rowParentId
919            )
920          ) {
921            this.visibleRows.push(tr);
922          }
923          tr.sleeping = false;
924        }
925        if (this.handler) clearTimeout(this.handler);
926        this.handler = setTimeout(() => this.refreshCanvas(false), 100);
927      });
928    });
929    window.addEventListener('keydown', (ev) => {
930      if (ev.key.toLocaleLowerCase() === 'escape') {
931        this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach((it) => {
932          it.checkType = '-1';
933        });
934        TraceRow.rangeSelectObject = undefined;
935        this.rangeSelect.rangeTraceRow = [];
936        this.selectStructNull();
937        this.timerShaftEL?.setSlicesMark();
938        this.traceSheetEL?.setAttribute('mode', 'hidden');
939        this.removeLinkLinesByBusinessType('janks', 'task');
940      }
941    });
942    this.chartManager = new SpChartManager(this);
943    this.canvasPanel = this.shadowRoot!.querySelector<HTMLCanvasElement>('#canvas-panel')!;
944    this.canvasFavoritePanel = this.shadowRoot!.querySelector<HTMLCanvasElement>('#canvas-panel-favorite')!;
945    this.canvasPanelCtx = this.canvasPanel.getContext('2d');
946
947    this.canvasFavoritePanelCtx = this.canvasFavoritePanel.getContext('2d');
948    this.canvasPanelConfig();
949    window.subscribe(window.SmartEvent.UI.SliceMark, (data) => {
950      this.sliceMarkEventHandler(data);
951    });
952    window.subscribe(window.SmartEvent.UI.TraceRowComplete, (tr) => {});
953    window.subscribe(window.SmartEvent.UI.RefreshCanvas, () => {
954      this.refreshCanvas(false);
955    });
956    window.subscribe(window.SmartEvent.UI.KeyboardEnable, (tr) => {
957      this.keyboardEnable = tr.enable;
958      if (!this.keyboardEnable) {
959        this.stopWASD();
960      }
961    });
962  }
963
964  pushPidToSelection(selection: SelectionParam, id: string) {
965    let pid = parseInt(id);
966    if (!selection.processIds.includes(pid)) {
967      selection.processIds.push(pid);
968    }
969  }
970
971  private createPointEvent(it: TraceRow<any>) {
972    let event = this.eventMap[it.rowType + ''];
973    if (event) {
974      return event;
975    } else {
976      if (it.rowType === TraceRow.ROW_TYPE_HEAP) {
977        event = it.name;
978      } else if (it.rowType === TraceRow.ROW_TYPE_HIPERF_CPU) {
979        event = 'HiPerf Cpu';
980        if (it.rowId === 'HiPerf-cpu-merge') {
981          event = 'HiPerf';
982        }
983      } else if (it.rowType === TraceRow.ROW_TYPE_FILE_SYSTEM) {
984        if (it.rowId === 'FileSystemLogicalWrite') {
985          event = 'FileSystem Logical Write';
986        } else if (it.rowId === 'FileSystemLogicalRead') {
987          event = 'FileSystem Logical Read';
988        } else if (it.rowId === 'FileSystemVirtualMemory') {
989          event = 'Page Fault Trace';
990        } else if (it.rowId!.startsWith('FileSystemDiskIOLatency')) {
991          event = 'Disk I/O Latency';
992          if (it.rowId!.startsWith('FileSystemDiskIOLatency-')) {
993            event = 'Bio Process';
994          }
995        }
996      } else if (it.rowType === TraceRow.ROW_TYPE_STATE_ENERGY) {
997        event = it.name;
998      } else if (it.rowType === TraceRow.ROW_TYPE_SMAPS) {
999        if (it.rowParentId === '') {
1000          event = 'VM Tracker';
1001        } else {
1002          event = it.name;
1003        }
1004      } else if (it.rowType === TraceRow.ROW_TYPE_JANK) {
1005        if (it.rowId === 'frameTime' || it.rowParentId === 'frameTime') {
1006          event = 'FrameTimeLine';
1007        } else if (it.hasAttribute('frame_type')) {
1008          event = it.getAttribute('frame_type') + '';
1009        }
1010      } else if (it.rowType === TraceRow.ROW_TYPE_DELIVER_INPUT_EVENT) {
1011        event = 'DeliverInputEvent';
1012        if (it.rowParentId === TraceRow.ROW_TYPE_DELIVER_INPUT_EVENT) {
1013          event = 'DeliverInputEvent Func';
1014        }
1015      } else {
1016        event = it.name;
1017      }
1018      return event;
1019    }
1020  }
1021
1022  refreshFavoriteCanvas() {
1023    let collectList = this.favoriteRowsEL?.querySelectorAll<TraceRow<any>>(`trace-row[collect-type]`) || [];
1024    let height = 0;
1025    collectList.forEach((row, index) => {
1026      height += row.offsetHeight;
1027      if (index == collectList.length - 1) {
1028        row.style.boxShadow = `0 10px 10px #00000044`;
1029      } else {
1030        row.style.boxShadow = `0 10px 10px #00000000`;
1031      }
1032    });
1033    if (height > this.rowsPaneEL!.offsetHeight) {
1034      this.favoriteRowsEL!.style.height = this.rowsPaneEL!.offsetHeight + 'px';
1035    } else {
1036      this.favoriteRowsEL!.style.height = height + 'px';
1037    }
1038    this.favoriteRowsEL!.style.width = this.canvasPanel?.offsetWidth + 'px';
1039    this.spacerEL!.style.height = height + 'px';
1040    this.canvasFavoritePanel!.style.height = this.favoriteRowsEL!.style.height;
1041    this.canvasFavoritePanel!.style.width = this.canvasPanel?.offsetWidth + 'px';
1042    this.canvasFavoritePanel!.width = this.canvasFavoritePanel!.offsetWidth * dpr();
1043    this.canvasFavoritePanel!.height = this.canvasFavoritePanel!.offsetHeight * dpr();
1044    this.canvasFavoritePanel!.getContext('2d')!.scale(dpr(), dpr());
1045  }
1046
1047  expansionAllParentRow(currentRow: TraceRow<any>) {
1048    let parentRow = this.rowsEL!.querySelector<TraceRow<any>>(
1049      `trace-row[row-id='${currentRow.rowParentId}'][folder][scene]`
1050    );
1051    if (parentRow) {
1052      parentRow.expansion = true;
1053      if (this.rowsEL!.querySelector<TraceRow<any>>(`trace-row[row-id='${parentRow.rowParentId}'][folder]`)) {
1054        this.expansionAllParentRow(parentRow);
1055      }
1056    }
1057  }
1058
1059  canvasPanelConfig() {
1060    this.canvasPanel!.style.left = `${this.timerShaftEL!.canvas!.offsetLeft!}px`;
1061    this.canvasPanel!.width = this.canvasPanel!.offsetWidth * dpr();
1062    this.canvasPanel!.height = this.canvasPanel!.offsetHeight * dpr();
1063    this.canvasPanelCtx!.scale(dpr(), dpr());
1064
1065    this.canvasFavoritePanel!.style.left = `${this.timerShaftEL!.canvas!.offsetLeft!}px`;
1066    this.canvasFavoritePanel!.width = this.canvasFavoritePanel!.offsetWidth * dpr();
1067    this.canvasFavoritePanel!.height = this.canvasFavoritePanel!.offsetHeight * dpr();
1068    this.canvasFavoritePanelCtx!.scale(dpr(), dpr());
1069  }
1070
1071  getScrollWidth() {
1072    let totalScrollDiv,
1073      scrollDiv,
1074      overflowDiv = document.createElement('div');
1075    overflowDiv.style.cssText = 'position:absolute; top:-2000px;width:200px; height:200px; overflow:hidden;';
1076    totalScrollDiv = document.body.appendChild(overflowDiv).clientWidth;
1077    overflowDiv.style.overflowY = 'scroll';
1078    scrollDiv = overflowDiv.clientWidth;
1079    document.body.removeChild(overflowDiv);
1080    return totalScrollDiv - scrollDiv;
1081  }
1082
1083  timerShaftELFlagClickHandler = (flag: Flag | undefined | null) => {
1084    if (flag) {
1085      setTimeout(() => {
1086        this.traceSheetEL?.displayFlagData(flag);
1087      }, 100);
1088    }
1089  };
1090
1091  timerShaftELFlagChange = (hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => {
1092    this.hoverFlag = hoverFlag;
1093    this.selectFlag = selectFlag;
1094    this.refreshCanvas(true, 'flagChange');
1095  };
1096
1097  timerShaftELRangeClick = (sliceTime: SlicesTime | undefined | null) => {
1098    if (sliceTime) {
1099      setTimeout(() => {
1100        this.traceSheetEL?.displayCurrent(sliceTime); // 给当前pane准备数据
1101        let selection = this.timerShaftEL!.selectionMap.get(sliceTime.id);
1102        if (selection) {
1103          selection.isCurrentPane = true; // 设置当前面板为可以显示的状态
1104          this.traceSheetEL?.rangeSelect(selection); // 显示选中区域对应的面板
1105        }
1106      }, 0);
1107    }
1108  };
1109
1110  timerShaftELRangeChange = (e: any) => {
1111    TraceRow.range = e;
1112    if (TraceRow.rangeSelectObject) {
1113      TraceRow.rangeSelectObject!.startX = Math.floor(
1114        ns2x(
1115          TraceRow.rangeSelectObject!.startNS!,
1116          TraceRow.range?.startNS!,
1117          TraceRow.range?.endNS!,
1118          TraceRow.range?.totalNS!,
1119          this.timerShaftEL!.sportRuler!.frame
1120        )
1121      );
1122      TraceRow.rangeSelectObject!.endX = Math.floor(
1123        ns2x(
1124          TraceRow.rangeSelectObject!.endNS!,
1125          TraceRow.range?.startNS!,
1126          TraceRow.range?.endNS!,
1127          TraceRow.range?.totalNS!,
1128          this.timerShaftEL!.sportRuler!.frame
1129        )
1130      );
1131    }
1132    //在rowsEL显示范围内的 trace-row组件将收到时间区间变化通知
1133    this.linkNodes.forEach((it) => {
1134      it[0].x = ns2xByTimeShaft(it[0].ns, this.timerShaftEL!);
1135      it[1].x = ns2xByTimeShaft(it[1].ns, this.timerShaftEL!);
1136    });
1137    this.refreshCanvas(false, 'rangeChange');
1138  };
1139  tim: number = -1;
1140  top: number = 0;
1141  handler: any = undefined;
1142  rowsElOnScroll = (e: any) => {
1143    this.linkNodes.forEach((itln) => {
1144      if (itln[0].rowEL.collect) {
1145        itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195;
1146      } else {
1147        itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
1148      }
1149      if (itln[1].rowEL.collect) {
1150        itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195;
1151      } else {
1152        itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
1153      }
1154      itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY;
1155      itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY;
1156    });
1157    if (this.scrollTimer) {
1158      clearTimeout(this.scrollTimer);
1159    }
1160    this.scrollTimer = setTimeout(() => {
1161      TraceRow.range!.refresh = true;
1162      requestAnimationFrame(() => this.refreshCanvas(false));
1163    }, 200);
1164    requestAnimationFrame(() => this.refreshCanvas(false));
1165  };
1166
1167  private scrollTimer: any;
1168
1169  favoriteRowsElOnScroll = (e: any) => {
1170    this.rowsElOnScroll(e);
1171  };
1172
1173  offset = 147;
1174
1175  getRowsContentHeight(): number {
1176    return [...this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row:not([sleeping])`)]
1177      .map((it) => it.clientHeight)
1178      .reduce((acr, cur) => acr + cur, 0);
1179  }
1180
1181  // refresh main canvas and favorite canvas
1182  refreshCanvas(cache: boolean, from?: string) {
1183    if (this.visibleRows.length == 0) {
1184      return;
1185    }
1186    //clear main canvas
1187    this.canvasPanelCtx?.clearRect(0, 0, this.canvasPanel!.offsetWidth, this.canvasPanel!.offsetHeight);
1188    //clear favorite canvas
1189    this.canvasFavoritePanelCtx?.clearRect(
1190      0,
1191      0,
1192      this.canvasFavoritePanel!.offsetWidth,
1193      this.canvasFavoritePanel!.offsetHeight
1194    );
1195    //draw lines for main canvas
1196    let rowsContentHeight = this.getRowsContentHeight();
1197    let canvasHeight =
1198      rowsContentHeight > this.canvasPanel!.clientHeight ? this.canvasPanel!.clientHeight : rowsContentHeight;
1199    canvasHeight += this.canvasFavoritePanel!.clientHeight;
1200    drawLines(this.canvasPanelCtx!, TraceRow.range?.xs || [], canvasHeight, this.timerShaftEL!.lineColor());
1201    //draw lines for favorite canvas
1202    drawLines(
1203      this.canvasFavoritePanelCtx!,
1204      TraceRow.range?.xs || [],
1205      this.canvasFavoritePanel!.clientHeight,
1206      this.timerShaftEL!.lineColor()
1207    );
1208    //canvas translate
1209    this.canvasPanel!.style.transform = `translateY(${this.rowsPaneEL!.scrollTop}px)`;
1210    this.canvasFavoritePanel!.style.transform = `translateY(${this.favoriteRowsEL!.scrollTop}px)`;
1211    //draw trace row
1212    this.visibleRows.forEach((v, i) => {
1213      if (v.collect) {
1214        v.translateY = v.getBoundingClientRect().top - 195;
1215      } else {
1216        v.translateY = v.offsetTop - this.rowsPaneEL!.scrollTop;
1217      }
1218      v.draw(cache);
1219    });
1220    //draw flag line segment for canvas
1221    drawFlagLineSegment(
1222      this.canvasPanelCtx,
1223      this.hoverFlag,
1224      this.selectFlag,
1225      {
1226        x: 0,
1227        y: 0,
1228        width: this.timerShaftEL?.canvas?.clientWidth,
1229        height: this.canvasPanel?.clientHeight,
1230      },
1231      this.timerShaftEL!
1232    );
1233    //draw flag line segment for favorite canvas
1234    drawFlagLineSegment(
1235      this.canvasFavoritePanelCtx,
1236      this.hoverFlag,
1237      this.selectFlag,
1238      {
1239        x: 0,
1240        y: 0,
1241        width: this.timerShaftEL?.canvas?.clientWidth,
1242        height: this.canvasFavoritePanel?.clientHeight,
1243      },
1244      this.timerShaftEL!
1245    );
1246    //draw wakeup for main canvas
1247    drawWakeUp(
1248      this.canvasPanelCtx,
1249      CpuStruct.wakeupBean,
1250      TraceRow.range!.startNS,
1251      TraceRow.range!.endNS,
1252      TraceRow.range!.totalNS,
1253      {
1254        x: 0,
1255        y: 0,
1256        width: TraceRow.FRAME_WIDTH,
1257        height: this.canvasPanel!.clientHeight!,
1258      } as Rect
1259    );
1260    //draw wakeup for favorite canvas
1261    drawWakeUp(
1262      this.canvasFavoritePanelCtx,
1263      CpuStruct.wakeupBean,
1264      TraceRow.range!.startNS,
1265      TraceRow.range!.endNS,
1266      TraceRow.range!.totalNS,
1267      {
1268        x: 0,
1269        y: 0,
1270        width: TraceRow.FRAME_WIDTH,
1271        height: this.canvasFavoritePanel!.clientHeight!,
1272      } as Rect
1273    );
1274    // draw wakeuplist for main canvas
1275    for (let i = 0; i < SpSystemTrace.wakeupList.length; i++) {
1276      if (i + 1 == SpSystemTrace.wakeupList.length) {
1277        return;
1278      }
1279      drawWakeUpList(
1280        this.canvasPanelCtx,
1281        SpSystemTrace.wakeupList[i + 1],
1282        TraceRow.range!.startNS,
1283        TraceRow.range!.endNS,
1284        TraceRow.range!.totalNS,
1285        {
1286          x: 0,
1287          y: 0,
1288          width: this.timerShaftEL!.canvas!.clientWidth,
1289          height: this.canvasPanel!.clientHeight!,
1290        } as Rect
1291      );
1292      drawWakeUpList(
1293        this.canvasFavoritePanelCtx,
1294        SpSystemTrace.wakeupList[i + 1],
1295        TraceRow.range!.startNS,
1296        TraceRow.range!.endNS,
1297        TraceRow.range!.totalNS,
1298        {
1299          x: 0,
1300          y: 0,
1301          width: this.timerShaftEL!.canvas!.clientWidth,
1302          height: this.canvasFavoritePanel!.clientHeight!,
1303        } as Rect
1304      );
1305    }
1306    // Draw the connection curve
1307    if (this.linkNodes) {
1308      drawLinkLines(this.canvasPanelCtx!, this.linkNodes, this.timerShaftEL!, false);
1309      drawLinkLines(this.canvasFavoritePanelCtx!, this.linkNodes, this.timerShaftEL!, true);
1310    }
1311  }
1312
1313  documentOnMouseDown = (ev: MouseEvent) => {
1314    if (!this.loadTraceCompleted) return;
1315    if (this.isWASDKeyPress()) {
1316      ev.preventDefault();
1317      ev.stopPropagation();
1318      return;
1319    }
1320    TraceRow.isUserInteraction = true;
1321    if (this.isMouseInSheet(ev)) return;
1322    this.observerScrollHeightEnable = false;
1323    if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) {
1324      let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft;
1325      let y = ev.offsetY;
1326      this.timerShaftEL?.documentOnMouseDown(ev);
1327      if (
1328        this.timerShaftEL!.sportRuler!.frame.contains(x, y) &&
1329        x > (TraceRow.rangeSelectObject?.startX || 0) &&
1330        x < (TraceRow.rangeSelectObject?.endX || 0)
1331      ) {
1332        let findSlicestime = this.timerShaftEL!.sportRuler?.findSlicesTime(x, y); // 查找帽子
1333        if (!findSlicestime) {
1334          // 如果没有找到帽子,则绘制一个三角形的旗子
1335          let time = Math.round(
1336            (x * (TraceRow.range?.endNS! - TraceRow.range?.startNS!)) / this.timerShaftEL!.canvas!.offsetWidth +
1337              TraceRow.range?.startNS!
1338          );
1339          this.timerShaftEL!.sportRuler!.drawTriangle(time, 'triangle');
1340        }
1341      } else {
1342        this.rangeSelect.mouseDown(ev);
1343        this.rangeSelect.drag = true;
1344      }
1345    } else {
1346      this.rangeSelect.drag = false;
1347    }
1348  };
1349
1350  onContextMenuHandler = (e: Event) => {
1351    setTimeout(() => {
1352      for (let key of this.keyPressMap.keys()) {
1353        if (this.keyPressMap.get(key)) {
1354          this.timerShaftEL?.stopWASD({ key: key });
1355          this.keyPressMap.set(key, false);
1356        }
1357      }
1358    }, 100);
1359  };
1360
1361  documentOnMouseUp = (ev: MouseEvent) => {
1362    if (!this.loadTraceCompleted) return;
1363    if (this.isWASDKeyPress()) {
1364      ev.preventDefault();
1365      ev.stopPropagation();
1366      return;
1367    }
1368    TraceRow.isUserInteraction = false;
1369    this.rangeSelect.isMouseDown = false;
1370    if ((window as any).isSheetMove) return;
1371    if (this.isMouseInSheet(ev)) return;
1372    this.rangeSelect.mouseUp(ev);
1373    this.timerShaftEL?.documentOnMouseUp(ev);
1374    ev.preventDefault();
1375    ev.stopPropagation();
1376  };
1377
1378  documentOnMouseOut = (ev: MouseEvent) => {
1379    if (!this.loadTraceCompleted) return;
1380    TraceRow.isUserInteraction = false;
1381    if (this.isMouseInSheet(ev)) return;
1382    if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) {
1383      this.rangeSelect.mouseOut(ev);
1384      this.timerShaftEL?.documentOnMouseOut(ev);
1385    }
1386  };
1387
1388  private keyPressMap: Map<string, boolean> = new Map([
1389    ['w', false],
1390    ['s', false],
1391    ['a', false],
1392    ['d', false],
1393  ]);
1394  documentOnKeyPress = (ev: KeyboardEvent) => {
1395    if (!this.loadTraceCompleted) return;
1396    let keyPress = ev.key.toLocaleLowerCase();
1397    TraceRow.isUserInteraction = true;
1398    if (this.isMousePointInSheet) {
1399      return;
1400    }
1401    this.observerScrollHeightEnable = false;
1402    if (this.keyboardEnable) {
1403      if (keyPress == 'm') {
1404        this.slicestime = this.setSLiceMark(ev.shiftKey);
1405        // 设置currentPane可以显示,并且修改调色板颜色和刚刚绘制的帽子颜色保持一致。
1406        this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet');
1407        let currentPane = this.traceSheetEL?.displayTab<TabPaneCurrent>('tabpane-current');
1408        if (this.slicestime) {
1409          currentPane?.setCurrentSlicesTime(this.slicestime);
1410        }
1411        // 显示对应的面板信息
1412        this.timerShaftEL!.selectionList.forEach((selection, index) => {
1413          if (this.timerShaftEL!.selectionList.length - 1 == index) {
1414            // 把最新添加的 SelectionParam 对象设置为可以显示当前面板
1415            selection.isCurrentPane = true;
1416            this.traceSheetEL?.rangeSelect(selection);
1417          } else {
1418            // 其他 SelectionParam 对象设置为不显示当前面板
1419            selection.isCurrentPane = false;
1420          }
1421        });
1422      }
1423      let keyPressWASD = keyPress === 'w' || keyPress === 'a' || keyPress === 's' || keyPress === 'd';
1424      if (keyPressWASD) {
1425        this.keyPressMap.set(keyPress, true);
1426        this.hoverFlag = null;
1427      }
1428      this.timerShaftEL!.documentOnKeyPress(ev);
1429    } else {
1430      this.stopWASD();
1431    }
1432  };
1433
1434  setSLiceMark(shiftKey: boolean): SlicesTime | null | undefined {
1435    if (CpuStruct.selectCpuStruct) {
1436      this.slicestime = this.timerShaftEL?.setSlicesMark(
1437        CpuStruct.selectCpuStruct.startTime || 0,
1438        (CpuStruct.selectCpuStruct.startTime || 0) + (CpuStruct.selectCpuStruct.dur || 0),
1439        shiftKey
1440      );
1441    } else if (ThreadStruct.selectThreadStruct) {
1442      this.slicestime = this.timerShaftEL?.setSlicesMark(
1443        ThreadStruct.selectThreadStruct.startTime || 0,
1444        (ThreadStruct.selectThreadStruct.startTime || 0) + (ThreadStruct.selectThreadStruct.dur || 0),
1445        shiftKey
1446      );
1447    } else if (FuncStruct.selectFuncStruct) {
1448      this.slicestime = this.timerShaftEL?.setSlicesMark(
1449        FuncStruct.selectFuncStruct.startTs || 0,
1450        (FuncStruct.selectFuncStruct.startTs || 0) + (FuncStruct.selectFuncStruct.dur || 0),
1451        shiftKey
1452      );
1453    } else if (IrqStruct.selectIrqStruct) {
1454      this.slicestime = this.timerShaftEL?.setSlicesMark(
1455        IrqStruct.selectIrqStruct.startNS || 0,
1456        (IrqStruct.selectIrqStruct.startNS || 0) + (IrqStruct.selectIrqStruct.dur || 0),
1457        shiftKey
1458      );
1459    } else if (TraceRow.rangeSelectObject) {
1460      this.slicestime = this.timerShaftEL?.setSlicesMark(
1461        TraceRow.rangeSelectObject.startNS || 0,
1462        TraceRow.rangeSelectObject.endNS || 0,
1463        shiftKey
1464      );
1465    } else if (JankStruct.selectJankStruct) {
1466      this.slicestime = this.timerShaftEL?.setSlicesMark(
1467        JankStruct.selectJankStruct.ts || 0,
1468        (JankStruct.selectJankStruct.ts || 0) + (JankStruct.selectJankStruct.dur || 0),
1469        shiftKey
1470      );
1471    } else if (AppStartupStruct.selectStartupStruct) {
1472      this.slicestime = this.timerShaftEL?.setSlicesMark(
1473        AppStartupStruct.selectStartupStruct.startTs || 0,
1474        (AppStartupStruct.selectStartupStruct.startTs || 0) + (AppStartupStruct.selectStartupStruct.dur || 0),
1475        shiftKey
1476      );
1477    } else if (SoStruct.selectSoStruct) {
1478      this.slicestime = this.timerShaftEL?.setSlicesMark(
1479        SoStruct.selectSoStruct.startTs || 0,
1480        (SoStruct.selectSoStruct.startTs || 0) + (SoStruct.selectSoStruct.dur || 0),
1481        shiftKey
1482      );
1483    } else {
1484      this.slicestime = this.timerShaftEL?.setSlicesMark();
1485    }
1486    return this.slicestime;
1487  }
1488
1489  stopWASD = () => {
1490    setTimeout(() => {
1491      for (let key of this.keyPressMap.keys()) {
1492        if (this.keyPressMap.get(key)) {
1493          this.timerShaftEL?.stopWASD({ key: key });
1494          this.keyPressMap.set(key, false);
1495        }
1496      }
1497    }, 100);
1498  };
1499
1500  documentOnKeyUp = (ev: KeyboardEvent) => {
1501    if (!this.loadTraceCompleted) return;
1502    let keyPress = ev.key.toLocaleLowerCase();
1503    if (keyPress === 'w' || keyPress === 'a' || keyPress === 's' || keyPress === 'd') {
1504      this.keyPressMap.set(keyPress, false);
1505    }
1506    TraceRow.isUserInteraction = false;
1507    this.observerScrollHeightEnable = false;
1508    this.keyboardEnable && this.timerShaftEL!.documentOnKeyUp(ev);
1509    if (ev.code == 'Enter') {
1510      if (ev.shiftKey) {
1511        this.dispatchEvent(
1512          new CustomEvent('previous-data', {
1513            detail: {},
1514            composed: false,
1515          })
1516        );
1517      } else {
1518        this.dispatchEvent(
1519          new CustomEvent('next-data', {
1520            detail: {},
1521            composed: false,
1522          })
1523        );
1524      }
1525    }
1526  };
1527
1528  isMouseInSheet = (ev: MouseEvent) => {
1529    this.isMousePointInSheet =
1530      this.traceSheetEL?.getAttribute('mode') != 'hidden' &&
1531      ev.offsetX > this.traceSheetEL!.offsetLeft &&
1532      ev.offsetY > this.traceSheetEL!.offsetTop;
1533    return this.isMousePointInSheet;
1534  };
1535
1536  favoriteChangeHandler = (row: TraceRow<any>) => {
1537    info('favoriteChangeHandler', row.frame, row.offsetTop, row.offsetHeight);
1538  };
1539
1540  selectChangeHandler = (rows: Array<TraceRow<any>>) => {
1541    this.isSelectClick = true;
1542    this.rangeSelect.rangeTraceRow = rows;
1543    let changeTraceRows: Array<TraceRow<any>> = [];
1544    if (this.rangeTraceRow!.length < rows.length) {
1545      rows!.forEach((currentTraceRow: TraceRow<any>) => {
1546        let changeFilter = this.rangeTraceRow!.filter(
1547          (prevTraceRow: TraceRow<any>) => prevTraceRow === currentTraceRow
1548        );
1549        if (changeFilter.length < 1) {
1550          changeTraceRows.push(currentTraceRow);
1551        }
1552      });
1553      if (changeTraceRows.length > 0) {
1554        changeTraceRows!.forEach((changeTraceRow: TraceRow<any>) => {
1555          let pointEvent = this.createPointEvent(changeTraceRow);
1556          SpStatisticsHttpUtil.addOrdinaryVisitAction({
1557            action: 'trace_row',
1558            event: pointEvent,
1559          });
1560        });
1561      }
1562    }
1563    this.rangeTraceRow = rows;
1564    this.rangeSelect.selectHandler?.(this.rangeSelect.rangeTraceRow, false);
1565  };
1566  inFavoriteArea: boolean | undefined;
1567  documentOnMouseMove = (ev: MouseEvent) => {
1568    if (!this.loadTraceCompleted || (window as any).flagInputFocus) return;
1569    if (this.isWASDKeyPress()) {
1570      this.hoverFlag = null;
1571      ev.preventDefault();
1572      return;
1573    }
1574    this.inFavoriteArea = this.favoriteRowsEL?.containPoint(ev);
1575    if ((window as any).isSheetMove) return;
1576    if (this.isMouseInSheet(ev)) {
1577      this.hoverStructNull();
1578      return;
1579    }
1580    let isMouseInTimeShaft = this.timerShaftEL?.containPoint(ev);
1581    if (isMouseInTimeShaft) {
1582      this.tipEL!.style.display = 'none';
1583      this.hoverStructNull();
1584    }
1585    let rows = this.visibleRows;
1586    if (this.timerShaftEL?.isScaling()) {
1587      return;
1588    }
1589    this.timerShaftEL?.documentOnMouseMove(ev);
1590    if (isMouseInTimeShaft) {
1591      return;
1592    }
1593    this.rangeSelect.mouseMove(rows, ev);
1594    if (this.rangeSelect.isMouseDown) {
1595      this.refreshCanvas(true);
1596    } else {
1597      if (!this.rowsPaneEL!.containPoint(ev, { left: 248 })) {
1598        this.tipEL!.style.display = 'none';
1599        this.hoverStructNull();
1600      }
1601      rows
1602        .filter((it) => it.focusContain(ev, this.inFavoriteArea!) && it.collect === this.inFavoriteArea)
1603        .filter((it) => {
1604          if (it.collect) {
1605            return true;
1606          } else {
1607            return (
1608              it.getBoundingClientRect().bottom + it.getBoundingClientRect().height >
1609              this.favoriteRowsEL!.getBoundingClientRect().bottom
1610            );
1611          }
1612        })
1613        .forEach((tr) => {
1614          if (this.currentRowType != tr.rowType) {
1615            this.hoverStructNull();
1616            this.tipEL!.style.display = 'none';
1617            this.currentRowType = tr.rowType || '';
1618          }
1619          if (tr.rowType == TraceRow.ROW_TYPE_CPU) {
1620            CpuStruct.hoverCpuStruct = undefined;
1621            for (let re of tr.dataListCache) {
1622              if (re.frame && isFrameContainPoint(re.frame, tr.hoverX, tr.hoverY)) {
1623                CpuStruct.hoverCpuStruct = re;
1624                break;
1625              }
1626            }
1627          } else {
1628            CpuStruct.hoverCpuStruct = undefined;
1629          }
1630          tr.focusHandler?.(ev);
1631        });
1632      requestAnimationFrame(() => this.refreshCanvas(true));
1633    }
1634  };
1635
1636  hoverStructNull() {
1637    CpuStruct.hoverCpuStruct = undefined;
1638    CpuFreqStruct.hoverCpuFreqStruct = undefined;
1639    ThreadStruct.hoverThreadStruct = undefined;
1640    FuncStruct.hoverFuncStruct = undefined;
1641    HiPerfCpuStruct.hoverStruct = undefined;
1642    HiPerfProcessStruct.hoverStruct = undefined;
1643    HiPerfThreadStruct.hoverStruct = undefined;
1644    HiPerfEventStruct.hoverStruct = undefined;
1645    HiPerfReportStruct.hoverStruct = undefined;
1646    CpuStateStruct.hoverStateStruct = undefined;
1647    CpuAbilityMonitorStruct.hoverCpuAbilityStruct = undefined;
1648    DiskAbilityMonitorStruct.hoverDiskAbilityStruct = undefined;
1649    MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = undefined;
1650    NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = undefined;
1651    CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined;
1652    FpsStruct.hoverFpsStruct = undefined;
1653    ClockStruct.hoverClockStruct = undefined;
1654    IrqStruct.hoverIrqStruct = undefined;
1655    HeapStruct.hoverHeapStruct = undefined;
1656    JankStruct.hoverJankStruct = undefined;
1657    AppStartupStruct.hoverStartupStruct = undefined;
1658    SoStruct.hoverSoStruct = undefined;
1659    HeapSnapshotStruct.hoverSnapshotStruct = undefined;
1660  }
1661
1662  selectStructNull() {
1663    CpuStruct.selectCpuStruct = undefined;
1664    CpuStruct.wakeupBean = null;
1665    CpuFreqStruct.selectCpuFreqStruct = undefined;
1666    ThreadStruct.selectThreadStruct = undefined;
1667    FuncStruct.selectFuncStruct = undefined;
1668    SpHiPerf.selectCpuStruct = undefined;
1669    CpuStateStruct.selectStateStruct = undefined;
1670    CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = undefined;
1671    ClockStruct.selectClockStruct = undefined;
1672    IrqStruct.selectIrqStruct = undefined;
1673    JankStruct.selectJankStruct = undefined;
1674    HeapStruct.selectHeapStruct = undefined;
1675    AppStartupStruct.selectStartupStruct = undefined;
1676    SoStruct.selectSoStruct = undefined;
1677    HeapSnapshotStruct.selectSnapshotStruct = undefined;
1678  }
1679
1680  isWASDKeyPress() {
1681    return (
1682      this.keyPressMap.get('w') || this.keyPressMap.get('a') || this.keyPressMap.get('d') || this.keyPressMap.get('s')
1683    );
1684  }
1685
1686  documentOnClick = (ev: MouseEvent) => {
1687    if (!this.loadTraceCompleted) return;
1688    if (this.isWASDKeyPress()) {
1689      this.hoverFlag = null;
1690      ev.preventDefault();
1691      ev.stopPropagation();
1692      return;
1693    }
1694    if ((window as any).isSheetMove) return;
1695    if (this.isMouseInSheet(ev)) return;
1696    if ((window as any).isPackUpTable) {
1697      (window as any).isPackUpTable = false;
1698      return;
1699    }
1700    let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft;
1701    let y = ev.offsetY;
1702    if (this.timerShaftEL?.getRangeRuler()?.frame.contains(x, y)) {
1703      this.clickEmptyArea();
1704      return;
1705    }
1706    if (this.rangeSelect.isDrag()) {
1707      return;
1708    }
1709    if (
1710      this.timerShaftEL!.sportRuler!.frame.contains(x, y) &&
1711      x > (TraceRow.rangeSelectObject?.startX || 0) &&
1712      x < (TraceRow.rangeSelectObject?.endX || 0)
1713    ) {
1714    } else {
1715      let inFavoriteArea = this.favoriteRowsEL?.containPoint(ev);
1716      let rows = this.visibleRows.filter((it) => it.focusContain(ev, inFavoriteArea!) && it.collect == inFavoriteArea);
1717      if (JankStruct.delJankLineFlag) {
1718        this.removeLinkLinesByBusinessType('janks');
1719      }
1720      if (rows && rows[0] && this.traceRowClickJudgmentConditions.get(rows[0]!.rowType!)?.()) {
1721        this.onClickHandler(rows[0]!.rowType!, rows[0]);
1722        this.documentOnMouseMove(ev);
1723      } else {
1724        this.clickEmptyArea();
1725      }
1726    }
1727    ev.preventDefault();
1728  };
1729
1730  clickEmptyArea() {
1731    this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach((it) => {
1732      it.checkType = '-1';
1733      it.rangeSelect = false;
1734    });
1735    this.rangeSelect.rangeTraceRow = [];
1736    TraceRow.rangeSelectObject = undefined;
1737    this.selectStructNull();
1738    this.wakeupListNull();
1739    this.observerScrollHeightEnable = false;
1740    this.selectFlag = null;
1741    this.timerShaftEL?.removeTriangle('inverted');
1742    this.traceSheetEL?.setAttribute('mode', 'hidden');
1743    this.removeLinkLinesByBusinessType('task');
1744    this.refreshCanvas(true);
1745    JankStruct.delJankLineFlag = true;
1746  }
1747
1748  //泳道图点击判定条件
1749  private traceRowClickJudgmentConditions: Map<string, () => boolean> = new Map<string, () => boolean>([
1750    [TraceRow.ROW_TYPE_CPU, () => CpuStruct.hoverCpuStruct !== null && CpuStruct.hoverCpuStruct !== undefined],
1751    [
1752      TraceRow.ROW_TYPE_THREAD,
1753      () => ThreadStruct.hoverThreadStruct !== null && ThreadStruct.hoverThreadStruct !== undefined,
1754    ],
1755    [TraceRow.ROW_TYPE_FUNC, () => FuncStruct.hoverFuncStruct !== null && FuncStruct.hoverFuncStruct !== undefined],
1756    [
1757      TraceRow.ROW_TYPE_CPU_FREQ,
1758      () => CpuFreqStruct.hoverCpuFreqStruct !== null && CpuFreqStruct.hoverCpuFreqStruct !== undefined,
1759    ],
1760    [
1761      TraceRow.ROW_TYPE_CPU_STATE,
1762      () => CpuStateStruct.hoverStateStruct !== null && CpuStateStruct.hoverStateStruct !== undefined,
1763    ],
1764    [
1765      TraceRow.ROW_TYPE_CPU_FREQ_LIMIT,
1766      () =>
1767        CpuFreqLimitsStruct.selectCpuFreqLimitsStruct !== null &&
1768        CpuFreqLimitsStruct.selectCpuFreqLimitsStruct !== undefined,
1769    ],
1770    [
1771      TraceRow.ROW_TYPE_CLOCK,
1772      () => ClockStruct.hoverClockStruct !== null && ClockStruct.hoverClockStruct !== undefined,
1773    ],
1774    [TraceRow.ROW_TYPE_IRQ, () => IrqStruct.hoverIrqStruct !== null && IrqStruct.hoverIrqStruct !== undefined],
1775    [
1776      TraceRow.ROW_TYPE_APP_STARTUP,
1777      () => AppStartupStruct.hoverStartupStruct !== null && AppStartupStruct.hoverStartupStruct !== undefined,
1778    ],
1779    [TraceRow.ROW_TYPE_STATIC_INIT, () => SoStruct.hoverSoStruct !== null && SoStruct.hoverSoStruct !== undefined],
1780    [TraceRow.ROW_TYPE_JANK, () => JankStruct.hoverJankStruct !== null && JankStruct.hoverJankStruct !== undefined],
1781    [TraceRow.ROW_TYPE_HEAP, () => HeapStruct.hoverHeapStruct !== null && HeapStruct.hoverHeapStruct !== undefined],
1782    [
1783      TraceRow.ROW_TYPE_HEAP_SNAPSHOT,
1784      () => HeapSnapshotStruct.hoverSnapshotStruct !== null && HeapSnapshotStruct.hoverSnapshotStruct !== undefined,
1785    ],
1786  ]);
1787
1788  onClickHandler(clickRowType: string, row?: TraceRow<any>) {
1789    if (row) {
1790      this.setAttribute('clickRow', clickRowType);
1791      this.setAttribute('rowName', row.name!);
1792      this.setAttribute('rowId', row.rowId!);
1793    }
1794    if (!this.loadTraceCompleted) return;
1795    this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach((it) => (it.rangeSelect = false));
1796    this.selectStructNull();
1797    this.wakeupListNull();
1798    let threadClickHandler: any;
1799    let cpuClickHandler: any;
1800    let jankClickHandler: any;
1801    let snapshotClickHandler: any;
1802    let scrollToFuncHandler: any;
1803    threadClickHandler = (d: ThreadStruct) => {
1804      this.observerScrollHeightEnable = false;
1805      this.scrollToProcess(`${d.cpu}`, '', 'cpu-data', true);
1806      let cpuRow = this.shadowRoot?.querySelectorAll<TraceRow<CpuStruct>>(
1807        `trace-row[row-id='${d.cpu}'][row-type='cpu-data']`
1808      )[0];
1809      let findEntry = cpuRow!.dataList!.find((dat: any) => dat.startTime === d.startTime);
1810      if (
1811        findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS ||
1812        findEntry!.startTime! > TraceRow.range!.endNS
1813      ) {
1814        this.timerShaftEL?.setRangeNS(
1815          findEntry!.startTime! - findEntry!.dur! * 2,
1816          findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2
1817        );
1818      }
1819      this.hoverStructNull();
1820      this.selectStructNull();
1821      this.wakeupListNull();
1822      CpuStruct.hoverCpuStruct = findEntry;
1823      CpuStruct.selectCpuStruct = findEntry;
1824      this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, 'inverted');
1825      this.traceSheetEL?.displayCpuData(
1826        CpuStruct.selectCpuStruct!,
1827        (wakeUpBean) => {
1828          CpuStruct.wakeupBean = wakeUpBean;
1829          this.refreshCanvas(true);
1830        },
1831        cpuClickHandler
1832      );
1833    };
1834
1835    cpuClickHandler = (d: CpuStruct) => {
1836      let traceRow = this.shadowRoot?.querySelector<TraceRow<any>>(
1837        `trace-row[row-id='${d.processId}'][row-type='process']`
1838      );
1839      if (traceRow) {
1840        traceRow.expansion = true;
1841      }
1842      this.observerScrollHeightEnable = true;
1843      let threadRow = this.shadowRoot?.querySelectorAll<TraceRow<ThreadStruct>>(
1844        `trace-row[row-id='${d.tid}'][row-type='thread']`
1845      )[0];
1846      let task = () => {
1847        if (threadRow) {
1848          let findEntry = threadRow!.dataList!.find((dat) => dat.startTime === d.startTime);
1849          if (
1850            findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS ||
1851            findEntry!.startTime! > TraceRow.range!.endNS
1852          ) {
1853            this.timerShaftEL?.setRangeNS(
1854              findEntry!.startTime! - findEntry!.dur! * 2,
1855              findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2
1856            );
1857          }
1858          this.hoverStructNull();
1859          this.selectStructNull();
1860          this.wakeupListNull();
1861          ThreadStruct.hoverThreadStruct = findEntry;
1862          ThreadStruct.selectThreadStruct = findEntry;
1863          this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, 'inverted');
1864          this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler, cpuClickHandler);
1865          this.scrollToProcess(`${d.tid}`, `${d.processId}`, 'thread', true);
1866        }
1867      };
1868      if (threadRow) {
1869        this.scrollToProcess(`${d.tid}`, `${d.processId}`, 'process', false);
1870        this.scrollToProcess(`${d.tid}`, `${d.processId}`, 'thread', true);
1871        if (threadRow!.isComplete) {
1872          task();
1873        } else {
1874          threadRow!.onComplete = task;
1875        }
1876      }
1877    };
1878
1879    jankClickHandler = (d: any) => {
1880      this.observerScrollHeightEnable = true;
1881      let jankRowParent: any;
1882      if (d.rowId === 'actual frameTime') {
1883        jankRowParent = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(`trace-row[row-id='frameTime']`);
1884      } else {
1885        jankRowParent = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(`trace-row[row-id='${d.pid}']`);
1886      }
1887      // jankRowParent!.expansion = true;
1888      let jankRow: any;
1889      jankRowParent.childrenList.forEach((item: TraceRow<JankStruct>) => {
1890        if (item.rowId === `${d.rowId}` && item.rowType === 'janks') {
1891          jankRow = item;
1892        }
1893      });
1894      let task = () => {
1895        if (jankRow) {
1896          JankStruct.selectJankStructList.length = 0;
1897          let findJankEntry = jankRow!.dataList!.find((dat: any) => dat.name == d.name && dat.pid == d.pid);
1898          if (findJankEntry) {
1899            if (
1900              findJankEntry!.ts! + findJankEntry!.dur! < TraceRow.range!.startNS ||
1901              findJankEntry!.ts! > TraceRow.range!.endNS
1902            ) {
1903              this.timerShaftEL?.setRangeNS(
1904                findJankEntry!.ts! - findJankEntry!.dur! * 2,
1905                findJankEntry!.ts! + findJankEntry!.dur! + findJankEntry!.dur! * 2
1906              );
1907            }
1908            this.hoverStructNull();
1909            this.selectStructNull();
1910            this.wakeupListNull();
1911            JankStruct.hoverJankStruct = findJankEntry;
1912            JankStruct.selectJankStruct = findJankEntry;
1913            this.timerShaftEL?.drawTriangle(findJankEntry!.ts || 0, 'inverted');
1914            this.traceSheetEL?.displayJankData(
1915              JankStruct.selectJankStruct!,
1916              (datas) => {
1917                this.removeLinkLinesByBusinessType('janks');
1918                // 绘制跟自己关联的线
1919                datas.forEach((data) => {
1920                  let endParentRow = this.shadowRoot?.querySelector<TraceRow<any>>(
1921                    `trace-row[row-id='${data.pid}'][folder]`
1922                  );
1923                  this.drawJankLine(endParentRow, JankStruct.selectJankStruct!, data);
1924                });
1925              },
1926              jankClickHandler
1927            );
1928          }
1929          this.scrollToProcess(jankRow.rowId!, jankRow.rowParentId!, jankRow.rowType!, true);
1930        }
1931      };
1932      if (jankRow) {
1933        this.scrollToProcess(jankRow.rowId!, jankRow.rowParentId!, jankRow.rowType!, false);
1934      }
1935      task();
1936    };
1937
1938    scrollToFuncHandler = (funcStract: any) => {
1939      this.observerScrollHeightEnable = true;
1940      this.moveRangeToCenter(funcStract.startTime!, funcStract.dur!);
1941      this.scrollToActFunc(funcStract, false);
1942    };
1943
1944    snapshotClickHandler = (d: HeapSnapshotStruct) => {
1945      this.observerScrollHeightEnable = true;
1946      let snapshotRow = this.shadowRoot?.querySelector<TraceRow<HeapSnapshotStruct>>(
1947        `trace-row[row-id='heapsnapshot']`
1948      );
1949      let task = () => {
1950        if (snapshotRow) {
1951          let findEntry = snapshotRow!.dataList!.find((dat) => dat.startTs === d.startTs);
1952          this.hoverStructNull();
1953          this.selectStructNull();
1954          this.wakeupListNull();
1955          HeapSnapshotStruct.hoverSnapshotStruct = findEntry;
1956          HeapSnapshotStruct.selectSnapshotStruct = findEntry;
1957        }
1958      };
1959      if (snapshotRow) {
1960        if (snapshotRow!.isComplete) {
1961          task();
1962        } else {
1963          snapshotRow!.onComplete = task;
1964        }
1965      }
1966    };
1967    if (clickRowType === TraceRow.ROW_TYPE_CPU && CpuStruct.hoverCpuStruct) {
1968      CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct;
1969      this.timerShaftEL?.drawTriangle(CpuStruct.selectCpuStruct!.startTime || 0, 'inverted');
1970      this.traceSheetEL?.displayCpuData(
1971        CpuStruct.selectCpuStruct,
1972        (wakeUpBean) => {
1973          CpuStruct.wakeupBean = wakeUpBean;
1974          this.refreshCanvas(false);
1975        },
1976        cpuClickHandler
1977      );
1978      this.timerShaftEL?.modifyFlagList(undefined);
1979    } else if (clickRowType === TraceRow.ROW_TYPE_THREAD && ThreadStruct.hoverThreadStruct) {
1980      ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct;
1981      this.timerShaftEL?.drawTriangle(ThreadStruct.selectThreadStruct!.startTime || 0, 'inverted');
1982      this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct, threadClickHandler, cpuClickHandler);
1983      this.timerShaftEL?.modifyFlagList(undefined);
1984    } else if (clickRowType === TraceRow.ROW_TYPE_FUNC && FuncStruct.hoverFuncStruct) {
1985      TabPaneTaskFrames.TaskArray = [];
1986      this.removeLinkLinesByBusinessType('task');
1987      FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct;
1988      let hoverFuncStruct = FuncStruct.hoverFuncStruct;
1989      this.timerShaftEL?.drawTriangle(FuncStruct.selectFuncStruct!.startTs || 0, 'inverted');
1990      FuncStruct.selectFuncStruct = hoverFuncStruct;
1991      let flagConfig = FlagsConfig.getFlagsConfig('TaskPool');
1992      let showTabArray: Array<string> = ['current-selection'];
1993      if (flagConfig!.TaskPool === 'Enabled') {
1994        if (FuncStruct.selectFuncStruct !== undefined && FuncStruct.selectFuncStruct.funName !== undefined) {
1995          if (FuncStruct.selectFuncStruct.funName.indexOf('H:Task ') >= 0) {
1996            showTabArray.push('box-task-frames');
1997            this.drawTaskPollLine(row);
1998          }
1999        }
2000      }
2001      this.traceSheetEL?.displayFuncData(showTabArray, FuncStruct.selectFuncStruct, scrollToFuncHandler);
2002      this.timerShaftEL?.modifyFlagList(undefined);
2003    } else if (clickRowType === TraceRow.ROW_TYPE_CPU_FREQ && CpuFreqStruct.hoverCpuFreqStruct) {
2004      CpuFreqStruct.selectCpuFreqStruct = CpuFreqStruct.hoverCpuFreqStruct;
2005      this.traceSheetEL?.displayFreqData();
2006      this.timerShaftEL?.modifyFlagList(undefined);
2007    } else if (clickRowType === TraceRow.ROW_TYPE_CPU_STATE && CpuStateStruct.hoverStateStruct) {
2008      CpuStateStruct.selectStateStruct = CpuStateStruct.hoverStateStruct;
2009      this.traceSheetEL?.displayCpuStateData();
2010      this.timerShaftEL?.modifyFlagList(undefined);
2011    } else if (clickRowType === TraceRow.ROW_TYPE_CPU_FREQ_LIMIT && CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct) {
2012      CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct;
2013      this.traceSheetEL?.displayFreqLimitData();
2014      this.timerShaftEL?.modifyFlagList(undefined);
2015    } else if (clickRowType === TraceRow.ROW_TYPE_CLOCK && ClockStruct.hoverClockStruct) {
2016      ClockStruct.selectClockStruct = ClockStruct.hoverClockStruct;
2017      this.traceSheetEL?.displayClockData(ClockStruct.selectClockStruct);
2018      this.timerShaftEL?.modifyFlagList(undefined);
2019    } else if (clickRowType === TraceRow.ROW_TYPE_IRQ && IrqStruct.hoverIrqStruct) {
2020      IrqStruct.selectIrqStruct = IrqStruct.hoverIrqStruct;
2021      this.traceSheetEL?.displayIrqData(IrqStruct.selectIrqStruct);
2022      this.timerShaftEL?.modifyFlagList(undefined);
2023    } else if (
2024      clickRowType === TraceRow.ROW_TYPE_HEAP &&
2025      row &&
2026      row.getAttribute('heap-type') === 'native_hook_statistic' &&
2027      HeapStruct.hoverHeapStruct
2028    ) {
2029      HeapStruct.selectHeapStruct = HeapStruct.hoverHeapStruct;
2030      this.traceSheetEL?.displayNativeHookData(HeapStruct.selectHeapStruct, row.rowId!);
2031      this.timerShaftEL?.modifyFlagList(undefined);
2032    } else if (clickRowType === TraceRow.ROW_TYPE_JANK && JankStruct.hoverJankStruct) {
2033      JankStruct.selectJankStructList.length = 0;
2034      this.removeLinkLinesByBusinessType('janks');
2035      JankStruct.selectJankStruct = JankStruct.hoverJankStruct;
2036      this.timerShaftEL?.drawTriangle(JankStruct.selectJankStruct!.ts || 0, 'inverted');
2037      this.traceSheetEL?.displayJankData(
2038        JankStruct.selectJankStruct,
2039        (datas) => {
2040          datas.forEach((data) => {
2041            let endParentRow;
2042            if (data.frame_type == 'frameTime') {
2043              endParentRow = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2044                `trace-row[row-id='frameTime'][row-type='janks']`
2045              );
2046            } else {
2047              endParentRow = this.shadowRoot?.querySelector<TraceRow<any>>(`trace-row[row-id='${data.pid}'][folder]`);
2048            }
2049            this.drawJankLine(endParentRow, JankStruct.selectJankStruct!, data);
2050          });
2051        },
2052        jankClickHandler
2053      );
2054    } else if (clickRowType === TraceRow.ROW_TYPE_HEAP_SNAPSHOT && HeapSnapshotStruct.hoverSnapshotStruct) {
2055      let snapshotRow = this.shadowRoot?.querySelector<TraceRow<HeapSnapshotStruct>>(
2056        `trace-row[row-id='heapsnapshot']`
2057      );
2058      HeapSnapshotStruct.selectSnapshotStruct = HeapSnapshotStruct.hoverSnapshotStruct;
2059      this.traceSheetEL?.displaySnapshotData(
2060        HeapSnapshotStruct.selectSnapshotStruct!,
2061        snapshotRow!.dataList,
2062        snapshotClickHandler
2063      );
2064    } else if (clickRowType === TraceRow.ROW_TYPE_APP_STARTUP && AppStartupStruct.hoverStartupStruct) {
2065      AppStartupStruct.selectStartupStruct = AppStartupStruct.hoverStartupStruct;
2066      this.traceSheetEL?.displayStartupData(AppStartupStruct.selectStartupStruct, scrollToFuncHandler);
2067      this.timerShaftEL?.modifyFlagList(undefined);
2068    } else if (clickRowType === TraceRow.ROW_TYPE_STATIC_INIT && SoStruct.hoverSoStruct) {
2069      SoStruct.selectSoStruct = SoStruct.hoverSoStruct;
2070      this.traceSheetEL?.displayStaticInitData(SoStruct.selectSoStruct, scrollToFuncHandler);
2071      this.timerShaftEL?.modifyFlagList(undefined);
2072    } else {
2073      if (!JankStruct.hoverJankStruct && JankStruct.delJankLineFlag) {
2074        this.removeLinkLinesByBusinessType('janks');
2075      }
2076      this.observerScrollHeightEnable = false;
2077      this.selectFlag = null;
2078      this.timerShaftEL?.removeTriangle('inverted');
2079      if (!SportRuler.isMouseInSportRuler) {
2080        this.traceSheetEL?.setAttribute('mode', 'hidden');
2081        this.refreshCanvas(true);
2082      }
2083    }
2084    if (!JankStruct.selectJankStruct) {
2085      this.removeLinkLinesByBusinessType('janks');
2086    }
2087    if (row) {
2088      let pointEvent = this.createPointEvent(row);
2089      SpStatisticsHttpUtil.addOrdinaryVisitAction({
2090        action: 'trace_row',
2091        event: pointEvent,
2092      });
2093    }
2094  }
2095
2096  makePoint(
2097    ts: number,
2098    dur: number,
2099    translateY: number,
2100    rowStruct: any,
2101    offsetY: number,
2102    business: string,
2103    lineType: LineType,
2104    isRight: boolean
2105  ): PairPoint {
2106    return {
2107      x: ns2xByTimeShaft(ts + dur, this.timerShaftEL!),
2108      y: translateY!,
2109      offsetY: offsetY,
2110      ns: ts + dur,
2111      rowEL: rowStruct!,
2112      isRight: isRight,
2113      business: business,
2114      lineType: lineType,
2115    };
2116  }
2117
2118  drawTaskPollLine(row?: TraceRow<any>) {
2119    let executeID = TabPaneTaskFrames.getExecuteId(FuncStruct.selectFuncStruct!.funName!);
2120    TabPaneTaskFrames.TaskArray.push(FuncStruct.selectFuncStruct!);
2121    if (!row) {
2122      return;
2123    }
2124    if (FuncStruct.selectFuncStruct!.funName!.indexOf('H:Task Perform:') >= 0) {
2125      TabPaneTaskFrames.IsShowConcurrency = true;
2126      queryBySelectExecute(executeID).then((res) => {
2127        if (res.length === 1) {
2128          let allocationRowId = res[0].tid;
2129          let selectRow = this.shadowRoot?.querySelector<TraceRow<FuncStruct>>(
2130            `trace-row[row-id='${allocationRowId}'][row-type=\'func\']`
2131          );
2132          selectRow!.dataList.forEach((value) => {
2133            // allocation to execute
2134            if (value.id === res[0].allocation_task_row) {
2135              TabPaneTaskFrames.TaskArray.push(value);
2136              this.addPointPair(
2137                this.makePoint(
2138                  value.startTs!,
2139                  0,
2140                  selectRow?.translateY!,
2141                  selectRow,
2142                  (value.depth! + 0.5) * 20,
2143                  'task',
2144                  LineType.bezierCurve,
2145                  true
2146                ),
2147                this.makePoint(
2148                  FuncStruct.selectFuncStruct!.startTs!,
2149                  0,
2150                  row?.translateY!,
2151                  row,
2152                  25,
2153                  'task',
2154                  LineType.bezierCurve,
2155                  true
2156                )
2157              );
2158            }
2159            // execute to return
2160            if (value.id === res[0].return_task_row) {
2161              TabPaneTaskFrames.TaskArray.push(value);
2162              this.addPointPair(
2163                this.makePoint(
2164                  FuncStruct.selectFuncStruct!.startTs!,
2165                  FuncStruct.selectFuncStruct!.dur!,
2166                  row?.translateY!,
2167                  row,
2168                  25,
2169                  'task',
2170                  LineType.bezierCurve,
2171                  false
2172                ),
2173                this.makePoint(
2174                  value.startTs!,
2175                  value.dur!,
2176                  selectRow?.translateY!,
2177                  selectRow,
2178                  (value.depth! + 0.5) * 20,
2179                  'task',
2180                  LineType.bezierCurve,
2181                  false
2182                )
2183              );
2184            }
2185          });
2186          this.refreshCanvas(true);
2187        }
2188      });
2189    } else {
2190      TabPaneTaskFrames.IsShowConcurrency = false;
2191      queryBySelectAllocationOrReturn(executeID).then((res) => {
2192        if (FuncStruct.selectFuncStruct!.funName!.indexOf('H:Task Allocation:') >= 0 && res.length > 0) {
2193          let executeRow = this.shadowRoot?.querySelector<TraceRow<FuncStruct>>(
2194            `trace-row[row-id='${res[0].tid}'][row-type='func']`
2195          );
2196          let endStruct: FuncStruct;
2197          row!.dataList.forEach((value) => {
2198            if (value.id === res[0].return_task_row) {
2199              TabPaneTaskFrames.TaskArray.push(value);
2200              endStruct = value;
2201            }
2202          });
2203          if (!executeRow) {
2204            return;
2205          }
2206          executeRow!.dataList.forEach((value) => {
2207            if (value.id === res[0].execute_task_row) {
2208              TabPaneTaskFrames.TaskArray.push(value);
2209              this.addPointPair(
2210                this.makePoint(
2211                  FuncStruct.selectFuncStruct!.startTs!,
2212                  0,
2213                  row?.translateY!,
2214                  row,
2215                  (FuncStruct.selectFuncStruct!.depth! + 0.5) * 20,
2216                  'task',
2217                  LineType.bezierCurve,
2218                  true
2219                ),
2220                this.makePoint(
2221                  value.startTs!,
2222                  0,
2223                  executeRow?.translateY!,
2224                  executeRow,
2225                  (value.depth! + 0.5) * 20,
2226                  'task',
2227                  LineType.bezierCurve,
2228                  true
2229                )
2230              );
2231              this.addPointPair(
2232                this.makePoint(
2233                  value.startTs!,
2234                  value.dur!,
2235                  executeRow?.translateY!,
2236                  executeRow,
2237                  (value.depth! + 0.5) * 20,
2238                  'task',
2239                  LineType.bezierCurve,
2240                  false
2241                ),
2242                this.makePoint(
2243                  endStruct.startTs!,
2244                  endStruct.dur!,
2245                  row?.translateY!,
2246                  row,
2247                  (value.depth! + 0.5) * 20,
2248                  'task',
2249                  LineType.bezierCurve,
2250                  false
2251                )
2252              );
2253            }
2254          });
2255        } else if (FuncStruct.selectFuncStruct!.funName!.indexOf('H:Task PerformTask End:') >= 0) {
2256          let executeRow = this.shadowRoot?.querySelector<TraceRow<FuncStruct>>(
2257            `trace-row[row-id='${res[0].tid}'][row-type='func']`
2258          );
2259          TabPaneTaskFrames.TaskArray.push(FuncStruct.selectFuncStruct!);
2260          let startStruct: FuncStruct;
2261          row!.dataList.forEach((value) => {
2262            if (value.id === res[0].allocation_task_row) {
2263              TabPaneTaskFrames.TaskArray.push(value);
2264              startStruct = value;
2265            }
2266          });
2267          executeRow!.dataList.forEach((value) => {
2268            if (value.id === res[0].execute_task_row) {
2269              TabPaneTaskFrames.TaskArray.push(value);
2270              this.addPointPair(
2271                this.makePoint(
2272                  startStruct!.startTs!,
2273                  0,
2274                  row?.translateY!,
2275                  row,
2276                  (startStruct!.depth! + 0.5) * 20,
2277                  'task',
2278                  LineType.bezierCurve,
2279                  true
2280                ),
2281                this.makePoint(
2282                  value.startTs!,
2283                  0,
2284                  executeRow?.translateY!,
2285                  executeRow,
2286                  (value.depth! + 0.5) * 20,
2287                  'task',
2288                  LineType.bezierCurve,
2289                  true
2290                )
2291              );
2292              this.addPointPair(
2293                this.makePoint(
2294                  value.startTs!,
2295                  value.dur!,
2296                  executeRow?.translateY!,
2297                  executeRow,
2298                  (value.depth! + 0.5) * 20,
2299                  'task',
2300                  LineType.bezierCurve,
2301                  false
2302                ),
2303                this.makePoint(
2304                  FuncStruct.selectFuncStruct!.startTs!,
2305                  FuncStruct.selectFuncStruct!.dur!,
2306                  row?.translateY!,
2307                  row,
2308                  (value.depth! + 0.5) * 20,
2309                  'task',
2310                  LineType.bezierCurve,
2311                  false
2312                )
2313              );
2314            }
2315          });
2316        }
2317        this.refreshCanvas(true);
2318      });
2319    }
2320  }
2321  drawJankLine(endParentRow: any, selectJankStruct: JankStruct, data: any) {
2322    let startRow: any;
2323    if (selectJankStruct == undefined || selectJankStruct == null) {
2324      return;
2325    }
2326    if (selectJankStruct.frame_type == 'frameTime') {
2327      startRow = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2328        "trace-row[row-id='actual frameTime'][row-type='janks']"
2329      );
2330    } else {
2331      startRow = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2332        `trace-row[row-id='${`${selectJankStruct?.type}-${selectJankStruct?.pid}`}'][row-type='janks']`
2333      );
2334    }
2335    if (endParentRow) {
2336      //终点的父泳道过滤出选中的Struct
2337      let endRowStruct: any;
2338      //泳道展开的情况,查找endRowStruct
2339      if (data.frame_type == 'frameTime') {
2340        endRowStruct = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2341          "trace-row[row-id='actual frameTime'][row-type='janks']"
2342        );
2343      } else {
2344        endRowStruct = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2345          `trace-row[row-id='${`${data.type}-${data.pid}`}'][row-type='janks']`
2346        );
2347      }
2348      //泳道未展开的情况,查找endRowStruct
2349      if (!endRowStruct) {
2350        if (data.frame_type == 'frameTime') {
2351          endParentRow.childrenList.forEach((item: TraceRow<JankStruct>) => {
2352            if (item.rowId === 'actual frameTime' && item.rowType === 'janks') {
2353              endRowStruct = item;
2354            }
2355          });
2356          //frameTime未展开
2357          if (!endRowStruct) {
2358            endParentRow = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2359              "trace-row[row-id='frameTime'][folder]"
2360            );
2361            endParentRow?.childrenList?.forEach((item: TraceRow<JankStruct>) => {
2362              if (item.rowId === 'actual frameTime' && item.rowType === 'janks') {
2363                endRowStruct = item;
2364              }
2365            });
2366          }
2367        } else {
2368          endParentRow.childrenList.forEach((item: TraceRow<JankStruct>) => {
2369            if (item.rowId === `${data.type}-${data.pid}` && item.rowType === 'janks') {
2370              endRowStruct = item;
2371            }
2372          });
2373        }
2374      }
2375      if (endRowStruct) {
2376        let findJankEntry = endRowStruct!.dataList!.find((dat: any) => dat.name == data.name && dat.pid == data.pid);
2377        //连线规则:frametimeline的头----app的头,app的尾----renderservice的头
2378        let tts: number = 0;
2379        if (findJankEntry) {
2380          if (selectJankStruct.frame_type == 'app') {
2381            tts =
2382              findJankEntry.frame_type == 'frameTime'
2383                ? selectJankStruct.ts!
2384                : selectJankStruct.ts! + selectJankStruct.dur!;
2385            let startParentRow: any;
2386            // startRow为子泳道,子泳道不存在,使用父泳道
2387            if (startRow) {
2388              startParentRow = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2389                `trace-row[row-id='${startRow.rowParentId}'][folder]`
2390              );
2391            } else {
2392              startRow = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2393                `trace-row[row-id='${selectJankStruct?.pid}'][folder]`
2394              );
2395            }
2396            let endY = endRowStruct!.translateY! + 20 * (findJankEntry!.depth! + 0.5);
2397            let endRowEl = endRowStruct;
2398            let endOffSetY = 20 * (findJankEntry!.depth! + 0.5);
2399            if (!endParentRow.expansion) {
2400              endY = endParentRow!.translateY! + 10 * (findJankEntry!.depth! + 0.5);
2401              endRowEl = endParentRow;
2402              endOffSetY = 10 * (findJankEntry!.depth! + 0.5);
2403            }
2404            let startY = startRow!.translateY! + 20 * (selectJankStruct!.depth! + 0.5);
2405            let startRowEl = startRow;
2406            let startOffSetY = 20 * (selectJankStruct!.depth! + 0.5);
2407            if (startParentRow && !startParentRow.expansion) {
2408              startY = startParentRow!.translateY! + 10 * (selectJankStruct!.depth! + 0.5);
2409              startRowEl = startParentRow;
2410              startOffSetY = 10 * (selectJankStruct!.depth! + 0.5);
2411            }
2412            this.addPointPair(
2413              {
2414                x: ns2xByTimeShaft(tts, this.timerShaftEL!),
2415                y: startY,
2416                offsetY: startOffSetY,
2417                ns: tts,
2418                rowEL: startRowEl!,
2419                isRight: selectJankStruct.ts == tts,
2420                business: 'janks',
2421              },
2422              {
2423                x: ns2xByTimeShaft(findJankEntry.ts!, this.timerShaftEL!),
2424                y: endY,
2425                offsetY: endOffSetY,
2426                ns: findJankEntry.ts!,
2427                rowEL: endRowEl,
2428                isRight: true,
2429                business: 'janks',
2430              }
2431            );
2432          }
2433          if (findJankEntry.frame_type == 'app') {
2434            tts =
2435              selectJankStruct.frame_type == 'frameTime' ? findJankEntry.ts : findJankEntry.ts! + findJankEntry.dur!;
2436            let endY = endRowStruct!.translateY! + 20 * (findJankEntry!.depth! + 0.5);
2437            let endRowEl = endRowStruct;
2438            let endOffSetY = 20 * (findJankEntry!.depth! + 0.5);
2439            if (!endParentRow.expansion) {
2440              endY = endParentRow!.translateY! + 10 * (findJankEntry!.depth! + 0.5);
2441              endRowEl = endParentRow;
2442              endOffSetY = 10 * (findJankEntry!.depth! + 0.5);
2443            }
2444            let startY = startRow!.translateY! + 20 * (selectJankStruct!.depth! + 0.5);
2445            let startRowEl = startRow;
2446            let startOffsetY = 20 * (selectJankStruct!.depth! + 0.5);
2447            let startParentRow = this.shadowRoot?.querySelector<TraceRow<JankStruct>>(
2448              `trace-row[row-id='${startRow.rowParentId}'][folder]`
2449            );
2450            if (startParentRow && !startParentRow.expansion) {
2451              startY = startParentRow!.translateY! + 10 * (selectJankStruct!.depth! + 0.5);
2452              startRowEl = startParentRow;
2453              startOffsetY = 10 * (selectJankStruct!.depth! + 0.5);
2454            }
2455            this.addPointPair(
2456              {
2457                x: ns2xByTimeShaft(selectJankStruct.ts!, this.timerShaftEL!),
2458                y: startY,
2459                offsetY: startOffsetY,
2460                ns: selectJankStruct.ts!,
2461                rowEL: startRowEl!,
2462                isRight: true,
2463                business: 'janks',
2464              },
2465              {
2466                x: ns2xByTimeShaft(tts, this.timerShaftEL!),
2467                y: endY,
2468                offsetY: endOffSetY,
2469                ns: tts,
2470                rowEL: endRowEl!,
2471                isRight: selectJankStruct.ts == tts,
2472                business: 'janks',
2473              }
2474            );
2475          }
2476          if (data.children.length >= 1) {
2477            let endP;
2478            if (data.children[0].frame_type == 'frameTime') {
2479              endP = this.shadowRoot?.querySelector<TraceRow<any>>("trace-row[row-id='frameTime']");
2480            } else {
2481              endP = this.shadowRoot?.querySelector<TraceRow<any>>(
2482                `trace-row[row-id='${data.children[0].pid}'][folder]`
2483              );
2484            }
2485            this.drawJankLine(endP, findJankEntry, data.children[0]);
2486          }
2487          this.refreshCanvas(true);
2488        }
2489      }
2490    }
2491  }
2492
2493  myMouseMove = (ev: MouseEvent) => {
2494    if (ev.ctrlKey) {
2495      ev.preventDefault();
2496      SpSystemTrace.offsetMouse = ev.clientX - SpSystemTrace.mouseCurrentPosition;
2497      let eventA = new KeyboardEvent('keypress', {
2498        key: 'a',
2499        code: '65',
2500        keyCode: 65,
2501      });
2502      let eventD = new KeyboardEvent('keypress', {
2503        key: 'd',
2504        code: '68',
2505        keyCode: 68,
2506      });
2507      if (ev.button == 0) {
2508        if (SpSystemTrace.offsetMouse < 0 && SpSystemTrace.moveable) {
2509          // 向右拖动,则泳道图右移
2510          this.timerShaftEL!.documentOnKeyPress(eventD);
2511          setTimeout(() => {
2512            this.timerShaftEL!.documentOnKeyUp(eventD);
2513          }, 350);
2514        }
2515        if (SpSystemTrace.offsetMouse > 0 && SpSystemTrace.moveable) {
2516          // 向左拖动,则泳道图左移
2517          this.timerShaftEL!.documentOnKeyPress(eventA);
2518          setTimeout(() => {
2519            this.timerShaftEL!.documentOnKeyUp(eventA);
2520          }, 350);
2521        }
2522      }
2523      SpSystemTrace.moveable = false;
2524    }
2525  };
2526
2527  connectedCallback() {
2528    this.initPointToEvent();
2529    /**
2530     * 监听时间轴区间变化
2531     */
2532    this.timerShaftEL!.rangeChangeHandler = this.timerShaftELRangeChange;
2533    this.timerShaftEL!.rangeClickHandler = this.timerShaftELRangeClick;
2534    this.timerShaftEL!.flagChangeHandler = this.timerShaftELFlagChange;
2535    this.timerShaftEL!.flagClickHandler = this.timerShaftELFlagClickHandler;
2536    /**
2537     * 监听rowsEL的滚动时间,刷新可见区域的trace-row组件的时间区间(将触发trace-row组件重绘)
2538     */
2539    this.rowsPaneEL?.addEventListener('scroll', this.rowsElOnScroll, {
2540      passive: true,
2541    });
2542    this.favoriteRowsEL?.addEventListener('scroll', this.favoriteRowsElOnScroll, { passive: true });
2543    /**
2544     * 监听document的mousemove事件 坐标通过换算后找到当前鼠标所在的trace-row组件,将坐标传入
2545     */
2546    this.addEventListener('mousemove', this.documentOnMouseMove);
2547    this.addEventListener('click', this.documentOnClick);
2548    this.addEventListener('mousedown', this.documentOnMouseDown);
2549    this.addEventListener('mouseup', this.documentOnMouseUp);
2550    this.addEventListener('mouseout', this.documentOnMouseOut);
2551
2552    document.addEventListener('keypress', this.documentOnKeyPress);
2553    document.addEventListener('keyup', this.documentOnKeyUp);
2554    document.addEventListener('contextmenu', this.onContextMenuHandler);
2555
2556    /**
2557     * 获取并保存鼠标当前的x轴坐标位置,配合ctrl+鼠标左键拖动完成泳道图的左移或右移
2558     */
2559    this.addEventListener(
2560      'mousedown',
2561      (e) => {
2562        if (e.ctrlKey) {
2563          e.preventDefault();
2564          this.removeEventListener('mousemove', this.documentOnMouseMove);
2565          this.removeEventListener('click', this.documentOnClick);
2566          this.removeEventListener('mousedown', this.documentOnMouseDown);
2567          this.removeEventListener('mouseup', this.documentOnMouseUp);
2568          this.style.cursor = 'move';
2569          SpSystemTrace.moveable = true;
2570          SpSystemTrace.mouseCurrentPosition = e.clientX;
2571        }
2572      },
2573      { passive: false }
2574    );
2575    /**
2576     * ctrl+鼠标移动,实现泳道图左移或者右移。
2577     */
2578    this.addEventListener('mousemove', (ev) => throttle(this.myMouseMove, 350, ev)(), { passive: false });
2579
2580    this.addEventListener(
2581      'mouseup',
2582      (e) => {
2583        if (e.ctrlKey) {
2584          e.preventDefault();
2585          SpSystemTrace.offsetMouse = 0;
2586          SpSystemTrace.mouseCurrentPosition = 0;
2587          SpSystemTrace.moveable = false;
2588          this.style.cursor = 'default';
2589          this.addEventListener('mousemove', this.documentOnMouseMove);
2590          this.addEventListener('click', this.documentOnClick);
2591          this.addEventListener('mousedown', this.documentOnMouseDown);
2592          this.addEventListener('mouseup', this.documentOnMouseUp);
2593        }
2594      },
2595      { passive: false }
2596    );
2597
2598    /**
2599     * 泳道图中添加ctrl+鼠标滚轮事件,对泳道图进行放大缩小。
2600     * 鼠标滚轮事件转化为键盘事件,keyPress和keyUp两个事件需要配合使用,
2601     * 否则泳道图会一直放大或一直缩小。
2602     * setTimeout()函数中的时间参数可以控制鼠标滚轮的频率。
2603     */
2604    document.addEventListener(
2605      'wheel',
2606      (e) => {
2607        if (e.ctrlKey) {
2608          if (e.deltaY > 0) {
2609            e.preventDefault();
2610            e.stopPropagation();
2611            let eventS = new KeyboardEvent('keypress', {
2612              key: 's',
2613              code: '83',
2614              keyCode: 83,
2615            });
2616            this.timerShaftEL!.documentOnKeyPress(eventS);
2617            setTimeout(() => {
2618              this.timerShaftEL!.documentOnKeyUp(eventS);
2619            }, 200);
2620          }
2621          if (e.deltaY < 0) {
2622            e.preventDefault();
2623            e.stopPropagation();
2624            let eventW = new KeyboardEvent('keypress', {
2625              key: 'w',
2626              code: '87',
2627              keyCode: 87,
2628            });
2629            this.timerShaftEL!.documentOnKeyPress(eventW);
2630            setTimeout(() => {
2631              this.timerShaftEL!.documentOnKeyUp(eventW);
2632            }, 200);
2633          }
2634        }
2635      },
2636      { passive: false }
2637    );
2638
2639    SpApplication.skinChange2 = (val: boolean) => {
2640      this.timerShaftEL?.render();
2641    };
2642    window.subscribe(window.SmartEvent.UI.UploadSOFile, (data) => {
2643      this.chartManager?.importSoFileUpdate().then(() => {
2644        window.publish(window.SmartEvent.UI.Loading, false);
2645        let updateCanvas = this.traceSheetEL?.updateRangeSelect();
2646        if (updateCanvas) {
2647          this.refreshCanvas(true);
2648        }
2649      });
2650    });
2651    window.subscribe(window.SmartEvent.UI.CheckALL, (data) => {
2652      this.favoriteRowsEL?.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${data.rowId}']`).forEach((it) => {
2653        it.checkType = data.isCheck ? '2' : '0';
2654      });
2655    });
2656  }
2657
2658  scrollToProcess(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true) {
2659    let rootRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`);
2660    if (rootRow?.collect) {
2661      this.favoriteRowsEL!.scroll({
2662        top: (rootRow?.offsetTop || 0) - this.canvasFavoritePanel!.offsetHeight + (rootRow?.offsetHeight || 0),
2663        left: 0,
2664        behavior: smooth ? 'smooth' : undefined,
2665      });
2666    } else {
2667      let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowParentId}'][folder]`);
2668      if (row && !row.expansion) {
2669        row.expansion = true;
2670      }
2671      if (rootRow && rootRow.offsetTop >= 0 && rootRow.offsetHeight >= 0) {
2672        this.rowsPaneEL!.scroll({
2673          top: (rootRow?.offsetTop || 0) - this.canvasPanel!.offsetHeight + (rootRow?.offsetHeight || 0),
2674          left: 0,
2675          behavior: smooth ? 'smooth' : undefined,
2676        });
2677      }
2678    }
2679  }
2680
2681  scrollToDepth(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true, depth: number) {
2682    let rootRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`);
2683    if (rootRow && rootRow!.collect) {
2684      this.favoriteRowsEL!.scroll({
2685        top: (rootRow?.offsetTop || 0) - this.canvasFavoritePanel!.offsetHeight + (++depth * 20 || 0),
2686        left: 0,
2687        behavior: smooth ? 'smooth' : undefined,
2688      });
2689    } else {
2690      let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowParentId}'][folder]`);
2691      if (row && !row.expansion) {
2692        row.expansion = true;
2693      }
2694      if (rootRow && rootRow.offsetTop >= 0 && rootRow.offsetHeight >= 0) {
2695        this.rowsPaneEL!.scroll({
2696          top: (rootRow?.offsetTop || 0) - this.canvasPanel!.offsetHeight + (++depth * 20 || 0),
2697          left: 0,
2698          behavior: smooth ? 'smooth' : undefined,
2699        });
2700      }
2701    }
2702  }
2703
2704  scrollToFunction(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true) {
2705    let condition = `trace-row[row-id='${rowId}'][row-type='${rowType}'][row-parent-id='${rowParentId}']`;
2706    let rootRow = this.shadowRoot!.querySelector<TraceRow<any>>(condition);
2707    if (rootRow?.collect) {
2708      this.favoriteRowsEL!.scroll({
2709        top: (rootRow?.offsetTop || 0) - this.canvasFavoritePanel!.offsetHeight + (rootRow?.offsetHeight || 0),
2710        left: 0,
2711        behavior: smooth ? 'smooth' : undefined,
2712      });
2713    } else {
2714      let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowParentId}'][folder]`);
2715      if (row && !row.expansion) {
2716        row.expansion = true;
2717      }
2718      if (rootRow && rootRow.offsetTop >= 0 && rootRow.offsetHeight >= 0) {
2719        this.rowsPaneEL!.scroll({
2720          top: (rootRow?.offsetTop || 0) - this.canvasPanel!.offsetHeight + 20,
2721          left: 0,
2722          behavior: smooth ? 'smooth' : undefined,
2723        });
2724      }
2725    }
2726  }
2727
2728  rowScrollTo(offset: number, callback: Function) {
2729    const fixedOffset = offset;
2730    const onScroll = () => {
2731      if (this.rowsPaneEL!.scrollTop === fixedOffset) {
2732        this.rowsEL!.removeEventListener('scroll', onScroll);
2733        callback();
2734      }
2735    };
2736
2737    this.rowsEL!.addEventListener('scroll', onScroll);
2738    onScroll();
2739    this.rowsPaneEL!.scrollTo({
2740      top: offset,
2741      behavior: 'smooth',
2742    });
2743  }
2744
2745  disconnectedCallback() {
2746    this.timerShaftEL?.removeEventListener('range-change', this.timerShaftELRangeChange);
2747    this.rowsPaneEL?.removeEventListener('scroll', this.rowsElOnScroll);
2748    this.favoriteRowsEL?.removeEventListener('scroll', this.favoriteRowsElOnScroll);
2749    this.removeEventListener('mousemove', this.documentOnMouseMove);
2750    this.removeEventListener('click', this.documentOnClick);
2751    this.removeEventListener('mousedown', this.documentOnMouseDown);
2752    this.removeEventListener('mouseup', this.documentOnMouseUp);
2753    this.removeEventListener('mouseout', this.documentOnMouseOut);
2754    document.removeEventListener('keypress', this.documentOnKeyPress);
2755    document.removeEventListener('keyup', this.documentOnKeyUp);
2756    document.removeEventListener('contextmenu', this.onContextMenuHandler);
2757    window.unsubscribe(window.SmartEvent.UI.SliceMark, this.sliceMarkEventHandler.bind(this));
2758  }
2759
2760  sliceMarkEventHandler(ev: any) {
2761    SpSystemTrace.sliceRangeMark = ev;
2762    let startNS = ev.timestamp - (window as any).recordStartNS;
2763    let endNS = ev.maxDuration + startNS;
2764    TraceRow.rangeSelectObject = {
2765      startX: 0,
2766      startNS: startNS,
2767      endNS: endNS,
2768      endX: 0,
2769    };
2770    window.publish(window.SmartEvent.UI.MenuTrace, {});
2771    window.publish(window.SmartEvent.UI.TimeRange, {
2772      startNS: startNS - ev.maxDuration,
2773      endNS: endNS + ev.maxDuration,
2774    });
2775    this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach((it) => {
2776      it.checkType = '-1';
2777    });
2778    this.rangeSelect.rangeTraceRow = [];
2779    this.selectStructNull();
2780    this.wakeupListNull();
2781    this.traceSheetEL?.setAttribute('mode', 'hidden');
2782    this.removeLinkLinesByBusinessType('janks');
2783    TraceRow.range!.refresh = true;
2784    this.refreshCanvas(false);
2785  }
2786
2787  loadDatabaseUrl(
2788    url: string,
2789    progress: Function,
2790    complete?: ((res: { status: boolean; msg: string }) => void) | undefined
2791  ) {
2792    this.observerScrollHeightEnable = false;
2793    this.init({ url: url }, '', progress).then((res) => {
2794      if (complete) {
2795        complete(res);
2796      }
2797    });
2798  }
2799
2800  loadDatabaseArrayBuffer(
2801    buf: ArrayBuffer,
2802    thirdPartyWasmConfigUrl: string,
2803    progress: (name: string, percent: number) => void,
2804    complete?: ((res: { status: boolean; msg: string }) => void) | undefined
2805  ) {
2806    this.observerScrollHeightEnable = false;
2807    this.init({ buf }, thirdPartyWasmConfigUrl, progress).then((res) => {
2808      let scrollTop = this.rowsEL?.scrollTop || 0;
2809      let scrollHeight = this.rowsEL?.clientHeight || 0;
2810      this.rowsEL?.querySelectorAll('trace-row').forEach((it: any) => this.observer.observe(it));
2811      if (complete) {
2812        complete(res);
2813      }
2814    });
2815  }
2816
2817  search(query: string) {
2818    this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach((item) => {
2819      if (query == null || query == undefined || query == '') {
2820        if (
2821          item.rowType == TraceRow.ROW_TYPE_CPU ||
2822          item.rowType == TraceRow.ROW_TYPE_CPU_FREQ ||
2823          item.rowType == TraceRow.ROW_TYPE_NATIVE_MEMORY ||
2824          item.rowType == TraceRow.ROW_TYPE_FPS ||
2825          item.rowType == TraceRow.ROW_TYPE_PROCESS ||
2826          item.rowType == TraceRow.ROW_TYPE_CPU_ABILITY ||
2827          item.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY ||
2828          item.rowType == TraceRow.ROW_TYPE_DISK_ABILITY ||
2829          item.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY
2830        ) {
2831          item.expansion = false;
2832          item.rowHidden = false;
2833        } else {
2834          item.rowHidden = true;
2835        }
2836      } else {
2837        if (item.name.toLowerCase().indexOf(query.toLowerCase()) >= 0) {
2838          item.rowHidden = false;
2839        } else {
2840          item.rowHidden = true;
2841        }
2842      }
2843    });
2844    this.visibleRows.forEach((it) => (it.rowHidden = false && it.draw(true)));
2845  }
2846
2847  searchCPU(query: string): Array<CpuStruct> {
2848    let traceRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[scene]`);
2849    let dataAll = `trace-row[row-type='cpu-data']`;
2850    if (traceRow) {
2851      dataAll = `trace-row[row-type='cpu-data'][scene]`;
2852    }
2853    let searchResults: Array<CpuStruct> = [];
2854    this.shadowRoot!.querySelectorAll<TraceRow<any>>(`${dataAll}`).forEach((item) => {
2855      let res = item!.dataList!.filter(
2856        (it) =>
2857          (it.name && it.name.indexOf(query) >= 0) ||
2858          it.tid == query ||
2859          it.processId == query ||
2860          (it.processName && it.processName.indexOf(query) >= 0)
2861      );
2862      searchResults.push(...res);
2863    });
2864    searchResults.sort((a, b) => (a.startTime || 0) - (b.startTime || 0));
2865    return searchResults;
2866  }
2867
2868  async searchFunction(cpuList: Array<any>, query: string): Promise<Array<any>> {
2869    let processList: Array<string> = [];
2870    let traceRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[scene]`);
2871    if (traceRow) {
2872      this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='process'][scene]`).forEach((row) => {
2873        processList.push(row.rowId!);
2874      });
2875      let list = await querySceneSearchFunc(query, processList);
2876      cpuList = cpuList.concat(list);
2877      cpuList.sort((a, b) => (a.startTime || 0) - (b.startTime || 0));
2878      return cpuList;
2879    } else {
2880      let list = await querySearchFunc(query);
2881      cpuList = cpuList.concat(list);
2882      cpuList.sort((a, b) => (a.startTime || 0) - (b.startTime || 0));
2883      return cpuList;
2884    }
2885  }
2886
2887  searchSdk(dataList: Array<any>, query: string): Array<any> {
2888    let traceRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[scene]`);
2889    let dataAll = `trace-row[row-type^='sdk']`;
2890    if (traceRow) {
2891      dataAll = `trace-row[row-type^='sdk'][scene]`;
2892    }
2893    let allTraceRow: any = [];
2894    let parentRows = this.shadowRoot!.querySelectorAll<TraceRow<any>>(`${dataAll}`);
2895    parentRows.forEach((parentRow: TraceRow<any>) => {
2896      allTraceRow.push(parentRow);
2897      if (parentRow.childrenList && parentRow.childrenList.length > 0) {
2898        allTraceRow.push(...parentRow.childrenList);
2899      }
2900    });
2901    allTraceRow.forEach((row: any) => {
2902      if (row!.name.indexOf(query) >= 0) {
2903        let searchSdkBean = new SearchSdkBean();
2904        searchSdkBean.startTime = TraceRow.range!.startNS;
2905        searchSdkBean.dur = TraceRow.range!.totalNS;
2906        searchSdkBean.name = row.name;
2907        searchSdkBean.rowId = row.rowId;
2908        searchSdkBean.type = 'sdk';
2909        searchSdkBean.rowType = row.rowType;
2910        searchSdkBean.rowParentId = row.rowParentId;
2911        dataList.push(searchSdkBean);
2912      }
2913    });
2914    return dataList;
2915  }
2916
2917  searchThreadsAndProcesses(query: string): Array<any> {
2918    let searchResults: Array<any> = [];
2919    this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='thread'][row-type='process']`).forEach((item) => {
2920      if (item!.name.indexOf(query) >= 0) {
2921        let searchBean = new SearchThreadProcessBean();
2922        searchBean.name = item.name;
2923        searchBean.rowId = item.rowId;
2924        searchBean.type = 'thread||process';
2925        searchBean.rowType = item.rowType;
2926        searchBean.rowParentId = item.rowParentId;
2927        searchResults.push(searchBean);
2928      }
2929    });
2930    return searchResults;
2931  }
2932
2933  showStruct(previous: boolean, currentIndex: number, structs: Array<any>) {
2934    if (structs.length == 0) {
2935      return 0;
2936    }
2937    let findIndex = -1;
2938    if (previous) {
2939      for (let i = structs.length - 1; i >= 0; i--) {
2940        let it = structs[i];
2941        if (
2942          i < currentIndex &&
2943          it.startTime! >= TraceRow.range!.startNS &&
2944          it.startTime! + it.dur! <= TraceRow.range!.endNS
2945        ) {
2946          findIndex = i;
2947          break;
2948        }
2949      }
2950    } else {
2951      findIndex = structs.findIndex((it, idx) => {
2952        return (
2953          idx > currentIndex &&
2954          it.startTime! >= TraceRow.range!.startNS &&
2955          it.startTime! + it.dur! <= TraceRow.range!.endNS
2956        );
2957      });
2958    }
2959    let findEntry: any;
2960    if (findIndex >= 0) {
2961      findEntry = structs[findIndex];
2962    } else {
2963      if (previous) {
2964        for (let i = structs.length - 1; i >= 0; i--) {
2965          let it = structs[i];
2966          if (it.startTime! + it.dur! < TraceRow.range!.startNS) {
2967            findIndex = i;
2968            break;
2969          }
2970        }
2971        if (findIndex == -1) {
2972          findIndex = structs.length - 1;
2973        }
2974      } else {
2975        findIndex = structs.findIndex((it) => it.startTime! > TraceRow.range!.endNS);
2976        if (findIndex == -1) {
2977          findIndex = 0;
2978        }
2979      }
2980      findEntry = structs[findIndex];
2981    }
2982    this.moveRangeToCenter(findEntry.startTime!, findEntry.dur!);
2983    this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row`).forEach((item) => {
2984      item.highlight = false;
2985    });
2986    if (findEntry.type == 'thread') {
2987      CpuStruct.selectCpuStruct = findEntry;
2988      CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct;
2989      this.shadowRoot!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach((item) => {
2990        item.highlight = item.rowId == `${findEntry.cpu}`;
2991        item.draw(true);
2992      });
2993      this.scrollToProcess(`${findEntry.cpu}`, '', 'cpu-data', true);
2994      this.onClickHandler(TraceRow.ROW_TYPE_CPU);
2995    } else if (findEntry.type == 'func') {
2996      this.observerScrollHeightEnable = true;
2997      this.scrollToActFunc(findEntry, true);
2998    } else if (findEntry.type == 'thread||process') {
2999      let threadProcessRow = this.rowsEL?.querySelectorAll<TraceRow<ThreadStruct>>('trace-row')[0];
3000      if (threadProcessRow) {
3001        let filterRow = threadProcessRow.childrenList.filter(
3002          (row) => row.rowId === findEntry.rowId && row.rowId === findEntry.rowType
3003        )[0];
3004        filterRow!.highlight = true;
3005        this.closeAllExpandRows(findEntry.rowParentId);
3006        this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true);
3007        let completeEntry = () => {
3008          let searchEntry = filterRow!.dataList!.find((dat) => dat.startTime === findEntry.startTime);
3009          this.hoverStructNull();
3010          this.selectStructNull();
3011          this.wakeupListNull();
3012          ThreadStruct.hoverThreadStruct = searchEntry;
3013          ThreadStruct.selectThreadStruct = searchEntry;
3014          this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true);
3015        };
3016        if (filterRow!.isComplete) {
3017          completeEntry();
3018        } else {
3019          filterRow!.onComplete = completeEntry;
3020        }
3021      }
3022    } else if (findEntry.type == 'sdk') {
3023      let parentRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-type='sdk'][folder]`);
3024      if (parentRow) {
3025        let sdkRow = parentRow.childrenList.filter(
3026          (child) => child.rowId === findEntry.rowId && child.rowType === findEntry.rowType
3027        )[0];
3028        sdkRow!.highlight = true;
3029      }
3030      this.hoverStructNull();
3031      this.selectStructNull();
3032      this.wakeupListNull();
3033      this.onClickHandler(findEntry.rowType!);
3034      this.closeAllExpandRows(findEntry.rowParentId);
3035      this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true);
3036    }
3037    this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted');
3038    return findIndex;
3039  }
3040
3041  scrollToActFunc(funcStract: any, highlight: boolean) {
3042    const toTargetDepth = (entry: any) => {
3043      if (entry) {
3044        this.hoverStructNull();
3045        this.selectStructNull();
3046        this.wakeupListNull();
3047        FuncStruct.hoverFuncStruct = entry;
3048        FuncStruct.selectFuncStruct = entry;
3049        this.onClickHandler(TraceRow.ROW_TYPE_FUNC);
3050        this.scrollToDepth(`${funcRowID}`, `${funcStract.pid}`, funcStract.type, true, entry.depth || 0);
3051      }
3052    };
3053    let funcRowID = funcStract.cookie == null ? funcStract.tid : `${funcStract.funName}-${funcStract.pid}`;
3054    let targetRow = this.favoriteRowsEL!.querySelector<TraceRow<any>>(
3055      `trace-row[row-id='${funcRowID}'][row-type='func']`
3056    );
3057    if (targetRow) {
3058      targetRow.highlight = highlight;
3059      //如果目标泳道图在收藏上面,则跳转至收藏
3060      let searchEntry = targetRow!.dataList!.find((dat) => dat.startTs === funcStract.startTime);
3061      toTargetDepth(searchEntry);
3062      return;
3063    }
3064    let parentRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${funcStract.pid}'][folder]`);
3065    if (!parentRow) {
3066      return;
3067    }
3068    let filterRow = parentRow.childrenList.filter((child) => child.rowId == funcRowID && child.rowType == 'func')[0];
3069    if (filterRow == null) {
3070      let funcRow = this.shadowRoot?.querySelector<TraceRow<any>>(`trace-row[row-id='${funcRowID}'][row-type='func']`);
3071      if (funcRow) {
3072        filterRow = funcRow;
3073      } else {
3074        return;
3075      }
3076    }
3077    filterRow!.highlight = highlight;
3078    if (funcStract.keepOpen !== true) {
3079      this.closeAllExpandRows(funcStract.pid);
3080    }
3081    let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${funcStract.pid}'][folder]`);
3082    if (row && !row.expansion) {
3083      row.expansion = true;
3084    }
3085    const completeEntry = () => {
3086      let entry = filterRow!.dataList!.find((dat) => dat.startTs === funcStract.startTime);
3087      toTargetDepth(entry);
3088    };
3089    if (filterRow!.isComplete) {
3090      completeEntry();
3091    } else {
3092      FuncStruct.hoverFuncStruct = funcStract;
3093      FuncStruct.selectFuncStruct = funcStract;
3094      this.onClickHandler(TraceRow.ROW_TYPE_FUNC);
3095      this.scrollToProcess(`${funcStract.tid}`, `${funcStract.pid}`, 'process', false);
3096      this.scrollToFunction(`${funcStract.tid}`, `${funcStract.pid}`, 'func', true);
3097      filterRow!.onComplete = completeEntry;
3098    }
3099  }
3100
3101  closeAllExpandRows(pid: string) {
3102    let expandRows = this.rowsEL?.querySelectorAll<TraceRow<ProcessStruct>>(`trace-row[row-type='process'][expansion]`);
3103    expandRows?.forEach((row) => {
3104      if (row.rowId != pid) {
3105        row.expansion = false;
3106      }
3107    });
3108  }
3109
3110  moveRangeToCenter(startTime: number, dur: number) {
3111    let startNS = this.timerShaftEL?.getRange()?.startNS || 0;
3112    let endNS = this.timerShaftEL?.getRange()?.endNS || 0;
3113    let harfDur = Math.trunc((endNS - startNS) / 2 - dur / 2);
3114    let leftNs = startTime - harfDur;
3115    let rightNs = startTime + dur + harfDur;
3116    if (startTime - harfDur < 0) {
3117      leftNs = 0;
3118      rightNs += harfDur - startTime;
3119    }
3120    this.timerShaftEL?.setRangeNS(leftNs, rightNs);
3121    TraceRow.range!.refresh = true;
3122    this.refreshCanvas(true);
3123  }
3124
3125  showPreCpuStruct(currentIndex: number, cpuStructs: Array<CpuStruct>): number {
3126    if (cpuStructs.length == 0) {
3127      return 0;
3128    }
3129    let findIndex = -1;
3130    for (let i = cpuStructs.length - 1; i >= 0; i--) {
3131      let it = cpuStructs[i];
3132      if (
3133        i < currentIndex &&
3134        it.startTime! >= TraceRow.range!.startNS &&
3135        it.startTime! + it.dur! <= TraceRow.range!.endNS
3136      ) {
3137        findIndex = i;
3138        break;
3139      }
3140    }
3141    if (findIndex >= 0) {
3142      let findEntry = cpuStructs[findIndex];
3143      CpuStruct.selectCpuStruct = findEntry;
3144      this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach((item) => {
3145        item.highlight = item.rowId == `${findEntry.cpu}`;
3146        item.draw(true);
3147      });
3148      this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted');
3149    } else {
3150      for (let i = cpuStructs.length - 1; i >= 0; i--) {
3151        let it = cpuStructs[i];
3152        if (it.startTime! + it.dur! < TraceRow.range!.startNS) {
3153          findIndex = i;
3154          break;
3155        }
3156      }
3157      let findEntry: CpuStruct;
3158      if (findIndex == -1) {
3159        findIndex = cpuStructs.length - 1;
3160      }
3161      findEntry = cpuStructs[findIndex];
3162      CpuStruct.selectCpuStruct = findEntry;
3163      let startNS = this.timerShaftEL?.getRange()?.startNS || 0;
3164      let endNS = this.timerShaftEL?.getRange()?.endNS || 0;
3165      let harfDur = Math.trunc((endNS - startNS) / 2 - findEntry.dur! / 2);
3166      this.timerShaftEL?.setRangeNS(findEntry.startTime! - harfDur, findEntry.startTime! + findEntry.dur! + harfDur);
3167      this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach((item) => {
3168        item.highlight = item.rowId == `${findEntry.cpu}`;
3169        item.draw(true);
3170      });
3171      this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted');
3172    }
3173    CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct;
3174    this.onClickHandler(TraceRow.ROW_TYPE_CPU);
3175    return findIndex;
3176  }
3177
3178  showNextCpuStruct(currentIndex: number, cpuStructs: Array<CpuStruct>): number {
3179    if (cpuStructs.length == 0) {
3180      return 0;
3181    }
3182    let findIndex = cpuStructs.findIndex((it, idx) => {
3183      return (
3184        idx > currentIndex &&
3185        it.startTime! >= TraceRow.range!.startNS &&
3186        it.startTime! + it.dur! <= TraceRow.range!.endNS
3187      );
3188    });
3189    if (findIndex >= 0) {
3190      let findEntry = cpuStructs[findIndex];
3191      CpuStruct.selectCpuStruct = findEntry;
3192      this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach((item) => {
3193        item.highlight = item.rowId == `${findEntry.cpu}`;
3194        item.draw(true);
3195      });
3196      this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted');
3197    } else {
3198      findIndex = cpuStructs.findIndex((it) => it.startTime! > TraceRow.range!.endNS);
3199      let findEntry: CpuStruct;
3200      if (findIndex == -1) {
3201        findIndex = 0;
3202      }
3203      findEntry = cpuStructs[findIndex];
3204      CpuStruct.selectCpuStruct = findEntry;
3205      let startNS = this.timerShaftEL?.getRange()?.startNS || 0;
3206      let endNS = this.timerShaftEL?.getRange()?.endNS || 0;
3207      let harfDur = Math.trunc((endNS - startNS) / 2 - findEntry.dur! / 2);
3208      this.timerShaftEL?.setRangeNS(findEntry.startTime! - harfDur, findEntry.startTime! + findEntry.dur! + harfDur);
3209      this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach((item) => {
3210        item.highlight = item.rowId == `${findEntry.cpu}`;
3211        item.draw(true);
3212      });
3213      this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted');
3214    }
3215    CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct;
3216    this.onClickHandler(TraceRow.ROW_TYPE_CPU);
3217    return findIndex;
3218  }
3219
3220  reset(progress: Function | undefined | null) {
3221    this.visibleRows.length = 0;
3222    this.tipEL!.style.display = 'none';
3223    this.canvasPanelCtx?.clearRect(0, 0, this.canvasPanel!.clientWidth, this.canvasPanel!.offsetHeight);
3224    this.canvasFavoritePanelCtx?.clearRect(
3225      0,
3226      0,
3227      this.canvasFavoritePanel!.clientWidth,
3228      this.canvasFavoritePanel!.clientHeight
3229    );
3230    this.favoriteRowsEL!.style.height = '0';
3231    this.canvasFavoritePanel!.style.height = '0';
3232    this.loadTraceCompleted = false;
3233    this.collectRows = [];
3234    this.visibleRows = [];
3235    TraceRowConfig.allTraceRowList.forEach((it) => {
3236      it.clearMemory();
3237    });
3238    TraceRowConfig.allTraceRowList = [];
3239    if (this.favoriteRowsEL) {
3240      this.favoriteRowsEL.querySelectorAll<TraceRow<any>>(`trace-row`).forEach((row) => {
3241        row.clearMemory();
3242        this.favoriteRowsEL!.removeChild(row);
3243      });
3244    }
3245    if (this.rowsEL) {
3246      this.rowsEL.querySelectorAll<TraceRow<any>>(`trace-row`).forEach((row) => {
3247        row.clearMemory();
3248        this.rowsEL!.removeChild(row);
3249      });
3250      this.rowsEL.innerHTML = '';
3251    }
3252    this.traceSheetEL?.clearMemory();
3253    this.spacerEL!.style.height = '0px';
3254    this.rangeSelect.rangeTraceRow = [];
3255    SpSystemTrace.SDK_CONFIG_MAP = undefined;
3256    SpSystemTrace.sliceRangeMark = undefined;
3257    this.timerShaftEL?.displayCollect(false);
3258    this.timerShaftEL!.collecBtn!.removeAttribute('close');
3259    CpuStruct.wakeupBean = undefined;
3260    this.selectStructNull();
3261    this.hoverStructNull();
3262    this.wakeupListNull();
3263    this.traceSheetEL?.setAttribute('mode', 'hidden');
3264    progress && progress('rest timershaft', 8);
3265    this.timerShaftEL?.reset();
3266    progress && progress('clear cache', 10);
3267    HeapDataInterface.getInstance().clearData();
3268    procedurePool.clearCache();
3269    Utils.clearData();
3270    procedurePool.submitWithName('logic0', 'clear', {}, undefined, (res: any) => {});
3271    procedurePool.submitWithName('logic1', 'clear', {}, undefined, (res: any) => {});
3272  }
3273
3274  init = async (param: { buf?: ArrayBuffer; url?: string }, wasmConfigUri: string, progress: Function) => {
3275    progress('Load database', 6);
3276    this.rowsPaneEL!.scroll({
3277      top: 0,
3278      left: 0,
3279    });
3280    if (param.buf) {
3281      let configJson = '';
3282      try {
3283        configJson = await fetch(wasmConfigUri).then((res) => res.text());
3284      } catch (e) {
3285        error('getWasmConfigFailed', e);
3286      }
3287      let { status, msg, sdkConfigMap } = await threadPool.initSqlite(param.buf, configJson, progress);
3288      if (!status) {
3289        return { status: false, msg: msg };
3290      }
3291      SpSystemTrace.SDK_CONFIG_MAP = sdkConfigMap == undefined ? undefined : sdkConfigMap;
3292    }
3293    if (param.url) {
3294      let { status, msg } = await threadPool.initServer(param.url, progress);
3295      if (!status) {
3296        return { status: false, msg: msg };
3297      }
3298    }
3299    await this.chartManager?.init(progress);
3300    this.rowsEL?.querySelectorAll<TraceRow<any>>('trace-row').forEach((it: any) => {
3301      it.addEventListener('expansion-change', this.extracted(it));
3302    });
3303    progress('completed', 100);
3304    info('All TraceRow Data initialized');
3305    this.loadTraceCompleted = true;
3306    this.rowsEL!.querySelectorAll<TraceRow<any>>('trace-row').forEach((it) => {
3307      if (it.folder) {
3308        let offsetYTimeOut: any = undefined;
3309        it.addEventListener('expansion-change', (event: any) => {
3310          JankStruct.delJankLineFlag = false;
3311          if (offsetYTimeOut) {
3312            clearTimeout(offsetYTimeOut);
3313          }
3314          if (event.detail.expansion) {
3315            offsetYTimeOut = setTimeout(() => {
3316              this.linkNodes.forEach((linkNode) => {
3317                JankStruct.selectJankStructList?.forEach((selectStruct: any) => {
3318                  if (event.detail.rowId == selectStruct.pid) {
3319                    JankStruct.selectJankStruct = selectStruct;
3320                    JankStruct.hoverJankStruct = selectStruct;
3321                  }
3322                });
3323                if (linkNode[0].rowEL.collect) {
3324                  linkNode[0].rowEL.translateY = linkNode[0].rowEL.getBoundingClientRect().top - 195;
3325                } else {
3326                  linkNode[0].rowEL.translateY = linkNode[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
3327                }
3328                linkNode[0].y = linkNode[0].rowEL!.translateY! + linkNode[0].offsetY;
3329                if (linkNode[1].rowEL.collect) {
3330                  linkNode[1].rowEL.translateY = linkNode[1].rowEL.getBoundingClientRect().top - 195;
3331                } else {
3332                  linkNode[1].rowEL.translateY = linkNode[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
3333                }
3334                linkNode[1].y = linkNode[1].rowEL!.translateY! + linkNode[1].offsetY;
3335              });
3336            }, 300);
3337          } else {
3338            if (JankStruct!.selectJankStruct) {
3339              JankStruct.selectJankStructList?.push(<JankStruct>JankStruct!.selectJankStruct);
3340            }
3341            offsetYTimeOut = setTimeout(() => {
3342              this.linkNodes?.forEach((linkNode) => {
3343                if (linkNode[0].rowEL.collect) {
3344                  linkNode[0].rowEL.translateY = linkNode[0].rowEL.getBoundingClientRect().top - 195;
3345                } else {
3346                  linkNode[0].rowEL.translateY = linkNode[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
3347                }
3348                linkNode[0].y = linkNode[0].rowEL!.translateY! + linkNode[0].offsetY;
3349                if (linkNode[1].rowEL.collect) {
3350                  linkNode[1].rowEL.translateY = linkNode[1].rowEL.getBoundingClientRect().top - 195;
3351                } else {
3352                  linkNode[1].rowEL.translateY = linkNode[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop;
3353                }
3354                linkNode[1].y = linkNode[1].rowEL!.translateY! + linkNode[1].offsetY;
3355              });
3356            }, 300);
3357          }
3358          let refreshTimeOut = setTimeout(() => {
3359            this.refreshCanvas(true);
3360            clearTimeout(refreshTimeOut);
3361          }, 360);
3362        });
3363      }
3364      this.intersectionObserver?.observe(it);
3365    });
3366    return { status: true, msg: 'success' };
3367  };
3368
3369  private extracted(it: any) {
3370    return () => {
3371      if (it.hasAttribute('expansion')) {
3372        this.shadowRoot?.querySelectorAll<any>(`[row-parent-id='${it.rowId}']`).forEach((child) => {
3373          if (child.folder) {
3374            child.addEventListener('expansion-change', this.extracted(child));
3375          }
3376          this.intersectionObserver?.observe(child);
3377        });
3378      } else {
3379        this.shadowRoot?.querySelectorAll<any>(`[row-parent-id='${it.rowId}']`).forEach((child) => {
3380          this.intersectionObserver?.unobserve(child);
3381        });
3382      }
3383      this.refreshCanvas(false);
3384    };
3385  }
3386
3387  displayTip(row: TraceRow<any>, struct: any, html: string) {
3388    let x = row.hoverX + 248;
3389    let y = row.getBoundingClientRect().top - 195 + (this.rowsPaneEL?.scrollTop ?? 0);
3390    if ((struct == undefined || struct == null) && this.tipEL) {
3391      this.tipEL.style.display = 'none';
3392      return;
3393    }
3394    if (this.tipEL) {
3395      this.tipEL.innerHTML = html;
3396      this.tipEL.style.display = 'flex';
3397      this.tipEL.style.height = row.style.height;
3398      if (x + this.tipEL.clientWidth > (this.canvasPanel!.clientWidth ?? 0)) {
3399        this.tipEL.style.transform = `translateX(${x - this.tipEL.clientWidth - 1}px) translateY(${y}px)`;
3400      } else {
3401        this.tipEL.style.transform = `translateX(${x}px) translateY(${y}px)`;
3402      }
3403    }
3404  }
3405
3406  queryCPUWakeUpList(data: WakeupBean) {
3407    TabPaneCurrentSelection.queryCPUWakeUpListFromBean(data).then((a: any) => {
3408      if (a === null) {
3409        return null;
3410      }
3411      SpSystemTrace.wakeupList.push(a);
3412      this.queryCPUWakeUpList(a);
3413    });
3414  }
3415
3416  wakeupListNull() {
3417    SpSystemTrace.wakeupList = [];
3418  }
3419
3420  initPointToEvent() {
3421    this.eventMap = {
3422      'cpu-data': 'Cpu',
3423      'cpu-state': 'Cpu State',
3424      'cpu-freq': 'Cpu Frequency',
3425      'cpu-limit-freq': 'Cpu Freq Limit',
3426      process: 'Process',
3427      'native-memory': 'Native Memory',
3428      thread: 'Thread',
3429      func: 'Func',
3430      mem: 'Memory',
3431      'virtual-memory-cell': 'Virtual Memory',
3432      'virtual-memory-group': 'Virtual Memory',
3433      fps: 'FPS',
3434      'ability-monitor': 'Ability Monitor',
3435      'cpu-ability': 'Cpu Ability',
3436      'memory-ability': 'Memory Ability',
3437      'disk-ability': 'DiskIO Ability',
3438      'network-ability': 'Network Ability',
3439      sdk: 'Sdk',
3440      'sdk-counter': 'SDK Counter',
3441      'sdk-slice': 'Sdk Slice',
3442      energy: 'Energy',
3443      'power-energy': 'Power Event',
3444      'system-energy': 'System Event',
3445      'anomaly-energy': 'Anomaly Event',
3446      'clock-group': 'Clocks',
3447      clock: 'clock',
3448      'irq-group': 'Irqs',
3449      irq: 'irq',
3450      hiperf: 'HiPerf (All)',
3451      'hiperf-event': 'HiPerf Event',
3452      'hiperf-report': 'HiPerf Report',
3453      'hiperf-process': 'HiPerf Process',
3454      'hiperf-thread': 'HiPerf Thread',
3455      'js-memory': 'Js Memory',
3456    };
3457  }
3458
3459  initHtml(): string {
3460    return `
3461        <style>
3462        :host{
3463            display: block;
3464            width: 100%;
3465            height: 100%;
3466        }
3467        .timer-shaft{
3468            width: 100%;
3469            z-index: 2;
3470        }
3471        .rows-pane{
3472            overflow: overlay;
3473            overflow-anchor: none;
3474            /*height: 100%;*/
3475            max-height: calc(100vh - 147px - 48px);
3476        }
3477        .rows{
3478            color: #fff;
3479            display: flex;
3480            box-sizing: border-box;
3481            flex-direction: column;
3482            overflow-y: auto;
3483            flex: 1;
3484            width: 100%;
3485            background: var(--dark-background4,#ffffff);
3486            /*scroll-behavior: smooth;*/
3487        }
3488        .favorite-rows{
3489            width: 100%;
3490            position:fixed;
3491            overflow-y: auto;
3492            overflow-x: hidden;
3493            z-index:1001;
3494            background: var(--dark-background5,#ffffff);
3495            box-shadow: 0 10px 10px #00000044;
3496        }
3497        .container{
3498            width: 100%;
3499            box-sizing: border-box;
3500            height: 100%;
3501            display: grid;
3502            grid-template-columns: 1fr;
3503            grid-template-rows: min-content 1fr min-content;
3504            /*grid-template-areas:    'head'*/
3505                                    /*'body'*/
3506                                    /*'sheet';*/
3507            position:relative;
3508        }
3509        .panel-canvas{
3510            position: absolute;
3511            top: 0;
3512            right: 0px;
3513            bottom: 0px;
3514            width: 100%;
3515            /*height: calc(100vh - 195px);*/
3516            height: 100%;
3517            box-sizing: border-box;
3518            /*background: #f0f0f0;*/
3519            /*border: 1px solid #000000;*/
3520            z-index: 0;
3521        }
3522        .panel-canvas-favorite{
3523            width: 100% ;
3524            display: block;
3525            position: absolute;
3526            height: 0;
3527            top: 0;
3528            right: 0;
3529            box-sizing: border-box;
3530            z-index: 100;
3531        }
3532        .trace-sheet{
3533            cursor: default;
3534        }
3535        .tip{
3536            z-index: 1001;
3537            position: absolute;
3538            top: 0;
3539            left: 0;
3540            /*height: 100%;*/
3541            background-color: white;
3542            border: 1px solid #f9f9f9;
3543            width: auto;
3544            font-size: 8px;
3545            color: #50809e;
3546            flex-direction: column;
3547            justify-content: center;
3548            align-items: flex-start;
3549            padding: 2px 10px;
3550            box-sizing: border-box;
3551            display: none;
3552            user-select: none;
3553        }
3554
3555        </style>
3556        <div class="container">
3557            <timer-shaft-element class="timer-shaft" style="position: relative;top: 0"></timer-shaft-element>
3558            <div class="rows-pane" style="position: relative;flex-direction: column;overflow-x: hidden;">
3559                <div class="favorite-rows">
3560                    <canvas id="canvas-panel-favorite" class="panel-canvas-favorite" ondragstart="return false"></canvas>
3561                </div>
3562                <canvas id="canvas-panel" class="panel-canvas" ondragstart="return false"></canvas>
3563                <div class="spacer" ondragstart="return false"></div>
3564                <div class="rows" ondragstart="return false"></div>
3565                <div id="tip" class="tip"></div>
3566            </div>
3567            <trace-sheet class="trace-sheet" mode="hidden" ondragstart="return false"></trace-sheet>
3568        </div>
3569        `;
3570  }
3571}
3572