• 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 { element } from '../../../../base-ui/BaseElement';
17import { TimeRange } from '../timer-shaft/RangeRuler';
18import '../../../../base-ui/icon/LitIcon';
19import { Rect } from '../timer-shaft/Rect';
20import { BaseStruct } from '../../../bean/BaseStruct';
21import { ns2x } from '../TimerShaftElement';
22import { TraceRowObject } from './TraceRowObject';
23import { LitCheckBox } from '../../../../base-ui/checkbox/LitCheckBox';
24import { LitIcon } from '../../../../base-ui/icon/LitIcon';
25import '../../../../base-ui/popover/LitPopoverV';
26import '../../../../base-ui/tree/LitTree';
27import { LitPopover } from '../../../../base-ui/popover/LitPopoverV';
28import { info } from '../../../../log/Log';
29import { ColorUtils } from './ColorUtils';
30import { drawSelectionRange, isFrameContainPoint } from '../../../database/ui-worker/ProcedureWorkerCommon';
31import { TraceRowConfig } from './TraceRowConfig';
32import { type TreeItemData, LitTree } from '../../../../base-ui/tree/LitTree';
33import { SpSystemTrace } from '../../SpSystemTrace';
34import { TraceRowHtml } from './TraceRow.html';
35import { Utils } from './Utils';
36
37export class RangeSelectStruct {
38  startX: number | undefined;
39  endX: number | undefined;
40  startNS: number | undefined;
41  endNS: number | undefined;
42}
43
44let collectList: Array<TraceRow<BaseStruct>> = [];
45let rowDragId: string | undefined | null;
46let dragDirection: string = '';
47
48@element('trace-row')
49export class TraceRow<T extends BaseStruct> extends HTMLElement {
50  sharedArrayBuffers: unknown;
51  intersectionRatio: number = 0;
52  static ROW_TYPE_SPSEGNENTATION = 'spsegmentation';
53  static ROW_TYPE_CPU_COMPUTILITY = 'cpu-computility';
54  static ROW_TYPE_GPU_COMPUTILITY = 'gpu-computility';
55  static ROW_TYPE_BINDER_COUNT = 'binder-count';
56  static ROW_TYPE_SCHED_SWITCH = 'sched-switch';
57  static ROW_TYPE_CPU = 'cpu-data';
58  static ROW_TYPE_CPU_STATE = 'cpu-state';
59  static ROW_TYPE_CPU_FREQ = 'cpu-freq';
60  static ROW_TYPE_CPU_FREQ_LIMIT = 'cpu-limit-freq';
61  static ROW_TYPE_CPU_FREQ_ALL = 'cpu-frequency';
62  static ROW_TYPE_IMPORT = 'import-match-file';
63  static ROW_TYPE_CPU_STATE_ALL = 'cpu-State';
64  static ROW_TYPE_CPU_FREQ_LIMITALL = 'cpu-frequency-limit';
65  static ROW_TYPE_FPS = 'fps';
66  static ROW_TYPE_NATIVE_MEMORY = 'native-memory';
67  static ROW_TYPE_HIPERF = 'hiperf';
68  static ROW_TYPE_HIPERF_THREADTYPE: Array<number> = [-2];
69  static ROW_TYPE_DELIVER_INPUT_EVENT = 'DeliverInputEvent';
70  static ROW_TYPE_TOUCH_EVENT_DISPATCH = 'TouchEventDispatch';
71  static ROW_TYPE_HIPERF_CPU = 'hiperf-cpu';
72  static ROW_TYPE_PERF_CALLCHART = 'hiperf-callchart';
73  static ROW_TYPE_HIPERF_PROCESS = 'hiperf-process';
74  static ROW_TYPE_HIPERF_THREAD = 'hiperf-thread';
75  static ROW_TYPE_HIPERF_REPORT = 'hiperf-report';
76  static ROW_TYPE_HIPERF_EVENT = 'hiperf-event';
77  static ROW_TYPE_PROCESS = 'process';
78  static ROW_TYPE_APP_STARTUP = 'app-startup';
79  static ROW_TYPE_STATIC_INIT = 'static-init';
80  static ROW_TYPE_THREAD = 'thread';
81  static ROW_TYPE_THREAD_NAME = 'sameThread_process';
82  static ROW_TYPE_MEM = 'mem';
83  static ROW_TYPE_VIRTUAL_MEMORY_GROUP = 'virtual-memory-group';
84  static ROW_TYPE_VIRTUAL_MEMORY = 'virtual-memory-cell';
85  static ROW_TYPE_FILE_SYSTEM_GROUP = 'file-system-group';
86  static ROW_TYPE_FILE_SYSTEM = 'file-system-cell';
87  static ROW_TYPE_HEAP = 'heap';
88  static ROW_TYPE_ARK_TS = 'ark-ts';
89  static ROW_TYPE_HEAP_SNAPSHOT = 'heap-snapshot';
90  static ROW_TYPE_HEAP_TIMELINE = 'heap-timeline';
91  static ROW_TYPE_FUNC = 'func';
92  static ROW_TYPE_MONITOR = 'ability-monitor';
93  static ROW_TYPE_CPU_ABILITY = 'cpu-ability';
94  static ROW_TYPE_MEMORY_ABILITY = 'memory-ability';
95  static ROW_TYPE_DISK_ABILITY = 'disk-ability';
96  static ROW_TYPE_NETWORK_ABILITY = 'network-ability';
97  static ROW_TYPE_DMA_ABILITY = 'dma-ability';
98  static ROW_TYPE_DMA_FENCE = 'dma-fence';
99  static ROW_TYPE_GPU_MEMORY_ABILITY = 'gpu-memory-ability';
100  static ROW_TYPE_SDK = 'sdk';
101  static ROW_TYPE_SDK_COUNTER = 'sdk-counter';
102  static ROW_TYPE_SDK_SLICE = 'sdk-slice';
103  static ROW_TYPE_ENERGY = 'energy';
104  static ROW_TYPE_ANOMALY_ENERGY = 'anomaly-energy';
105  static ROW_TYPE_SYSTEM_ENERGY = 'system-energy';
106  static ROW_TYPE_POWER_ENERGY = 'power-energy';
107  static ROW_TYPE_STATE_ENERGY = 'state-energy';
108  static ROW_TYPE_SYS_MEMORY_GPU = 'sys-memory-gpu';
109  static ROW_TYPE_SYS_MEMORY_GPU_GL = 'sys-memory-gpu-gl';
110  static ROW_TYPE_SYS_MEMORY_GPU_GRAPH = 'sys-memory-gpu-graph';
111  static ROW_TYPE_SYS_MEMORY_GPU_TOTAL = 'sys-memory-gpu-total';
112  static ROW_TYPE_SYS_MEMORY_GPU_WINDOW = 'sys-memory-gpu-window';
113  static ROW_TYPE_VM_TRACKER_SMAPS = 'smaps';
114  static ROW_TYPE_VM_TRACKER = 'VmTracker';
115  static ROW_TYPE_DMA_VMTRACKER = 'dma-vmTracker';
116  static ROW_TYPE_GPU_MEMORY_VMTRACKER = 'gpu-memory-vmTracker';
117  static ROW_TYPE_GPU_RESOURCE_VMTRACKER = 'sys-memory-gpu-resource';
118  static ROW_TYPE_VMTRACKER_SHM = 'VmTracker-shm';
119  static ROW_TYPE_HANG_GROUP = 'hang-group';
120  static ROW_TYPE_CLOCK_GROUP = 'clock-group';
121  static ROW_TYPE_COLLECT_GROUP = 'collect-group';
122  static ROW_TYPE_HANG = 'hang';
123  static ROW_TYPE_HANG_INNER = 'hang-inner';
124  static ROW_TYPE_CLOCK = 'clock';
125  static ROW_TYPE_XPOWER = 'xpower';
126  static ROW_TYPE_XPOWER_SYSTEM_GROUP = 'xpower-system-group';
127  static ROW_TYPE_XPOWER_BUNDLE_NAME_GROUP = 'xpower-bundle-name-group';
128  static ROW_TYPE_XPOWER_STATISTIC = 'xpower-statistic';
129  static ROW_TYPE_XPOWER_APP_DETAIL_DISPLAY = 'xpower-app-detail-display';
130  static ROW_TYPE_XPOWER_WIFI_PACKETS = 'xpower-wifi-packets';
131  static ROW_TYPE_XPOWER_WIFI_BYTES = 'xpower-wifi-bytes';
132  static ROW_TYPE_XPOWER_SYSTEM = 'xpower-system';
133  static ROW_TYPE_XPOWER_THREAD_COUNT = 'xpower-thread-count';
134  static ROW_TYPE_XPOWER_THREAD_INFO = 'xpower-thread-info';
135  static ROW_TYPE_XPOWER_GPU_COUNT = 'xpower-gpu-count';
136  static ROW_TYPE_XPOWER_GPU_FREQUENCY = 'xpower-gpu-frequency';
137  static ROW_TYPE_IRQ_GROUP = 'irq-group';
138  static ROW_TYPE_IRQ = 'irq';
139  static ROW_TYPE_JANK = 'janks';
140  static ROW_TYPE_FRAME = 'frame';
141  static ROW_TYPE_FRAME_ANIMATION = 'frame-animation';
142  static ROW_TYPE_FRAME_DYNAMIC = 'frame-dynamic';
143  static ROW_TYPE_FRAME_SPACING = 'frame-spacing';
144  static ROW_TYPE_JS_CPU_PROFILER = 'js-cpu-profiler-cell';
145  static ROW_TYPE_PURGEABLE_TOTAL_ABILITY = 'purgeable-total-ability';
146  static ROW_TYPE_PURGEABLE_PIN_ABILITY = 'purgeable-pin-ability';
147  static ROW_TYPE_PURGEABLE_TOTAL_VM = 'purgeable-total-vm';
148  static ROW_TYPE_PURGEABLE_PIN_VM = 'purgeable-pin-vm';
149  static ROW_TYPE_LOGS = 'logs';
150  static ROW_TYPE_SAMPLE = 'bpftrace';
151  static ROW_TYPE_ALL_APPSTARTUPS = 'all-appstartups';
152  static ROW_TYPE_PERF_TOOL_GROUP = 'perf-tool-group';
153  static ROW_TYPE_PERF_TOOL = 'perf-tool';
154  static ROW_TYPE_GPU_COUNTER_GROUP = 'gpu-counter-group';
155  static ROW_TYPE_GPU_COUNTER = 'gpu-counter';
156  static ROW_TYPE_SNAPSHOT = 'snapShots';
157  static FRAME_WIDTH: number = 0;
158  static range: TimeRange | undefined | null;
159  static rangeSelectObject: RangeSelectStruct | undefined;
160  static ROW_TYPE_HI_SYSEVENT = 'hi-sysevent'; // @ts-ignore
161  public obj: TraceRowObject<unknown> | undefined | null;
162  isHover: boolean = false;
163  hoverX: number = 0;
164  hoverY: number = 0;
165  index: number = 0;
166  public must: boolean = false;
167  public isTransferCanvas = false;
168  onComplete: Function | undefined;
169  isComplete: boolean = false;
170  public dataList: Array<T> = [];
171  public dataList2: Array<T> = [];
172  public dataListCache: Array<T> = [];
173  public fixedList: Array<T> = [];
174  public sliceCache: number[] = [-1, -1];
175  public describeEl: HTMLElement | null | undefined;
176  public canvas: Array<HTMLCanvasElement> = [];
177  public canvasVessel: HTMLDivElement | null | undefined;
178  public tipEL: HTMLDivElement | null | undefined;
179  public checkBoxEL: LitCheckBox | null | undefined;
180  public collectEL: LitIcon | null | undefined;
181  public onThreadHandler: ((useCache: boolean, buf: ArrayBuffer | undefined | null) => void) | undefined | null;
182  public onRowSettingChangeHandler: ((keys: Array<string>, nodes: Array<unknown>) => void) | undefined | null;
183  public onRowSettingCheckBoxChangeHandler: ((keys: boolean[]) => void) | undefined | null;
184  public onRowCheckFileChangeHandler: (() => void) | undefined | null;
185  public supplier: (() => Promise<Array<T>>) | undefined | null; // @ts-ignore
186  public favoriteChangeHandler: ((fav: TraceRow<unknown>) => void) | undefined | null; // @ts-ignore
187  public selectChangeHandler: ((traceRow: TraceRow<unknown>) => void) | undefined | null;
188  dpr = window.devicePixelRatio || 1;
189  // @ts-ignore
190  offscreen: Array<OffscreenCanvas | undefined> = [];
191  canvasWidth = 0;
192  canvasHeight = 0;
193  private _collectGroup: string | undefined;
194  public _frame: Rect | undefined;
195  public isLoading: boolean = false;
196  public tampName: string = '';
197  public readonly args: unknown;
198  public templateType: Set<string> = new Set<string>();
199  private rootEL: HTMLDivElement | null | undefined;
200  private nameEL: HTMLLabelElement | null | undefined;
201  private rowSettingTree: LitTree | null | undefined;
202  private rowSettingPop: LitPopover | null | undefined;
203  private rowSettingCheckBoxPop: LitPopover | null | undefined;
204  private _rowSettingCheckBoxList: string[] | null | undefined;
205  private _rowSettingCheckedBoxList: boolean[] | null | undefined;
206  private fileEL: unknown;
207  private rowCheckFilePop: LitPopover | null | undefined;
208  private _rangeSelect: boolean = false;
209  private _drawType: number = 0;
210  private _enableCollapseChart: boolean = false;
211  online: boolean = false;
212  static isUserInteraction: boolean;
213  asyncFuncName: string | Array<string> | undefined | null;
214  asyncFuncNamePID: number | undefined | null;
215  asyncFuncThreadName: Array<unknown> | string | undefined | null;
216  translateY: number = 0; //single canvas offsetY;
217  // @ts-ignore
218  childrenList: Array<TraceRow<unknown>> = []; // @ts-ignore
219  parentRowEl: TraceRow<unknown> | undefined;
220  _rowSettingList: Array<TreeItemData> | null | undefined;
221  public supplierFrame: (() => Promise<Array<T>>) | undefined | null; //实时查询
222  public getCacheData: ((arg: unknown) => Promise<Array<unknown>> | undefined) | undefined; //实时查询
223  public loadingFrame: boolean = false; //实时查询,正在查询中
224  public needRefresh: boolean = true;
225  _frameRateList: Array<number> | undefined; //存储平均帧率数据
226  _avgRateTxt: string | undefined | null; //存储帧率显示文字
227  public folderIcon: LitIcon | null | undefined;
228  private sampleUploadEl: HTMLDivElement | null | undefined;
229  private jsonFileEl: HTMLInputElement | null | undefined;
230
231  focusHandler?: (ev: MouseEvent) => void | undefined;
232  findHoverStruct?: () => void | undefined;
233  public funcMaxHeight: number = 0;
234  currentContext: CanvasRenderingContext2D | undefined | null;
235  static ROW_TYPE_LTPO: string | null | undefined;
236  static ROW_TYPE_HITCH_TIME: string | null | undefined;
237  asyncFuncStartTID!: number | undefined;
238  protoParentId: string | null | undefined;
239  protoPid: string | undefined;
240  summaryProtoPid: Array<string> | undefined;
241
242  constructor(
243    args: {
244      canvasNumber: number;
245      alpha: boolean;
246      contextId: string;
247      isOffScreen: boolean;
248      skeleton?: boolean;
249    } = {
250        canvasNumber: 1,
251        alpha: false,
252        contextId: '2d',
253        isOffScreen: true,
254        skeleton: false,
255      },
256    traceId?: string
257  ) {
258    super();
259    this.args = args;
260    this.attachShadow({ mode: 'open' }).innerHTML = this.initHtml();
261    if (traceId) {
262      this.traceId = traceId;
263    }
264    this.initElements();
265  }
266
267  static skeleton<T extends BaseStruct>(traceId?: string): TraceRow<T> {
268    let tr = new TraceRow<T>(
269      {
270        alpha: false,
271        canvasNumber: 0,
272        contextId: '',
273        isOffScreen: false,
274        skeleton: true,
275      },
276      traceId
277    );
278    tr.isTransferCanvas = true;
279    return tr;
280  }
281
282  static get observedAttributes(): string[] {
283    return [
284      'folder',
285      'sticky',
286      'name',
287      'expansion',
288      'children',
289      'height',
290      'row-type',
291      'row-id',
292      'row-parent-id',
293      'sleeping',
294      'check-type',
295      'collect-type',
296      'collect-group',
297      'disabled-check',
298      'row-discard',
299      'func-expand',
300      'row-setting',
301      'row-setting-list',
302      'row-setting-popover-direction',
303    ];
304  }
305
306  get uploadEl(): HTMLDivElement | null | undefined {
307    return this.sampleUploadEl;
308  }
309
310  get frameRateList(): Array<number> | undefined {
311    return this._frameRateList;
312  }
313
314  set frameRateList(value: Array<number> | undefined) {
315    this._frameRateList = value;
316  }
317
318  get avgRateTxt(): string | undefined | null {
319    return this._avgRateTxt;
320  }
321
322  set avgRateTxt(value: string | undefined | null) {
323    this._avgRateTxt = value;
324  }
325
326  get funcExpand(): boolean {
327    return this.getAttribute('func-expand') === 'true';
328  }
329
330  set funcExpand(b: boolean) {
331    this.setAttribute('func-expand', b ? 'true' : 'false');
332  }
333
334  get sticky(): boolean {
335    return this.hasAttribute('sticky');
336  }
337
338  set sticky(fixed: boolean) {
339    if (fixed) {
340      this.setAttribute('sticky', '');
341    } else {
342      this.removeAttribute('sticky');
343    }
344  }
345
346  get hasParentRowEl(): boolean {
347    return this.parentRowEl !== undefined;
348  }
349
350  get rowDiscard(): boolean {
351    return this.hasAttribute('row-discard');
352  }
353
354  set rowDiscard(value: boolean) {
355    if (value) {
356      this.setAttribute('row-discard', '');
357      this.style.display = 'none';
358    } else {
359      this.removeAttribute('row-discard');
360      this.style.display = 'block';
361    }
362  }
363
364  get collectGroup(): string | undefined {
365    return this._collectGroup;
366  }
367
368  set collectGroup(value: string | undefined) {
369    this._collectGroup = value;
370    this.setAttribute('collect-group', value || '');
371  }
372
373  set rowSetting(value: string) {
374    this.setAttribute('row-setting', value);
375  }
376
377  get rowSetting(): string {
378    return this.getAttribute('row-setting') || 'disable';
379  }
380
381  set rowSettingPopoverDirection(value: string) {
382    if (this.rowSettingPop) {
383      this.rowSettingPop.placement = value;
384    }
385    if (this.rowSettingPop) {
386      this.rowSettingPop.placement = value;
387    }
388  }
389
390  get rowSettingPopoverDirection(): string {
391    return this.rowSettingPop?.placement || 'bottomLeft';
392  }
393
394  set rowSettingList(value: Array<TreeItemData> | null | undefined) {
395    this._rowSettingList = value;
396    if (this.rowSettingTree) {
397      this.rowSettingTree.treeData = value || [];
398    }
399    if (this.rowSettingTree) {
400      this.rowSettingTree.treeData = value || [];
401    }
402  }
403
404  set rowSettingMultiple(value: boolean) {
405    if (this.rowSettingTree) {
406      this.rowSettingTree.multiple = value;
407    }
408  }
409
410  get rowSettingList(): TreeItemData[] | null | undefined {
411    return this._rowSettingList;
412  }
413
414  set rowSettingCheckBoxList(value: Array<string> | null | undefined) {
415    this._rowSettingCheckBoxList = value;
416  }
417
418  get rowSettingCheckBoxList(): Array<string> | null | undefined {
419    return this._rowSettingCheckBoxList;
420  }
421
422  get rowSettingCheckedBoxList(): Array<boolean> | null | undefined {
423    return this._rowSettingCheckedBoxList;
424  }
425
426  get collect(): boolean {
427    return this.hasAttribute('collect-type');
428  }
429
430  set collect(value: boolean) {
431    if (value) {
432      this.setAttribute('collect-type', '');
433    } else {
434      this.removeAttribute('collect-type');
435    }
436  }
437
438  get rangeSelect(): boolean {
439    return this._rangeSelect;
440  }
441
442  set rangeSelect(value: boolean) {
443    this._rangeSelect = value && this.traceId === Utils.currentSelectTrace;
444  }
445
446  sleeping: boolean = false;
447
448  get rowType(): string | undefined | null {
449    return this.getAttribute('row-type');
450  }
451
452  set rowType(val) {
453    this.setAttribute('row-type', val || '');
454  }
455
456  get traceId(): string | undefined | null {
457    return this.getAttribute('trace-id');
458  }
459
460  set traceId(val) {
461    this.setAttribute('trace-id', val || '');
462  }
463
464  get rowId(): string | undefined | null {
465    return this.getAttribute('row-id');
466  }
467
468  set rowId(val) {
469    let id = this.traceId ? `${val || ''}-${this.traceId}` : `${val || ''}`;
470    this.setAttribute('row-id', id);
471  }
472
473  get rowParentId(): string | undefined | null {
474    return this.getAttribute('row-parent-id');
475  }
476
477  set rowParentId(val) {
478    this.setAttribute('row-parent-id', val || '');
479  }
480
481  get namePrefix(): string | undefined | null {
482    return this.getAttribute('name-prefix');
483  }
484
485  set namePrefix(val) {
486    this.setAttribute('name-prefix', val || '');
487  }
488
489  set rowHidden(val: boolean) {
490    let height = 0;
491    if (val) {
492      this.setAttribute('row-hidden', '');
493      height = 0;
494    } else {
495      this.removeAttribute('row-hidden');
496      height = this.clientHeight;
497    }
498    if (this.collect) {
499      window.publish(window.SmartEvent.UI.RowHeightChange, {
500        expand: this.funcExpand,
501        value: height,
502      });
503    }
504  }
505
506  get name(): string {
507    return this.getAttribute('name') || '';
508  }
509
510  set name(value: string) {
511    this.setAttribute('name', value);
512  }
513
514  get folder(): boolean {
515    return this.hasAttribute('folder');
516  }
517
518  set folder(value: boolean) {
519    if (value) {
520      this.setAttribute('folder', '');
521      this.folderIcon = document.createElement('lit-icon') as LitIcon;
522      this.folderIcon.classList.add('icon');
523      this.folderIcon.setAttribute('name', 'caret-down');
524      this.folderIcon.setAttribute('size', '19');
525      this.folderIcon.style.display = 'flex';
526      this.describeEl?.insertBefore(this.folderIcon, this.describeEl.children[0]);
527    } else {
528      this.removeAttribute('folder');
529    }
530  }
531
532  get expansion(): boolean {
533    return this.hasAttribute('expansion');
534  }
535
536  fragment: DocumentFragment = document.createDocumentFragment();
537
538  set expansion(value) {
539    if (value === this.expansion) {
540      return;
541    }
542    if (value) {
543      this.updateChildRowStatus();
544    } else {
545      this.sticky = false;
546      this.childRowToFragment(false);
547    }
548    if (value) {
549      this.setAttribute('expansion', '');
550    } else {
551      this.removeAttribute('expansion');
552    }
553    this.dispatchEvent(
554      new CustomEvent('expansion-change', {
555        detail: {
556          expansion: this.expansion,
557          rowType: this.rowType,
558          rowId: this.rowId,
559          rowParentId: this.rowParentId,
560        },
561      })
562    );
563  }
564
565  childRowToFragment(expansion: boolean): void {
566    for (const childrenRow of this.childrenList) {
567      if (!childrenRow.collect) {
568        this.fragment.append(childrenRow);
569      }
570      if (!expansion) {
571        if (childrenRow.childrenList && childrenRow.folder && childrenRow.expansion) {
572          childrenRow.expansion = false;
573        }
574      }
575    }
576  }
577
578  updateChildRowStatus(): void {
579    this.fragment = document.createDocumentFragment();
580    this.childRowToFragment(true);
581    this.insertAfter(this.fragment, this);
582  }
583
584  clearMemory(): void {
585    this.dataList2 = [];
586    this.dataList = [];
587    this.dataListCache = [];
588    this.fixedList = [];
589    if (this.rootEL) {
590      this.rootEL.innerHTML = '';
591    }
592    if (this.folder) {
593      this.childrenList.forEach((child) => {
594        if (child.clearMemory !== undefined) {
595          child.clearMemory();
596        }
597      });
598      this.childrenList = [];
599    }
600  }
601
602  addTemplateTypes(...type: string[]): void {
603    type.forEach((item) => {
604      this.templateType.add(item);
605    });
606    if (this.hasParentRowEl) {
607      this.toParentAddTemplateType(this);
608    }
609  }
610  // @ts-ignore
611  toParentAddTemplateType = (currentRowEl: TraceRow<unknown>): void => {
612    let parentRow = currentRowEl.parentRowEl;
613    if (parentRow !== undefined) {
614      currentRowEl.templateType.forEach((item) => {
615        parentRow!.templateType.add(item);
616      });
617      if (parentRow.parentRowEl !== undefined) {
618        this.toParentAddTemplateType(parentRow);
619      }
620    }
621  };
622
623  getHoverStruct(
624    strict: boolean = true,
625    offset: boolean = false,
626    maxKey: string | undefined = undefined
627  ): T | undefined {
628    let item: T | undefined;
629    if (this.isHover) {
630      if (maxKey) {
631        let arr = this.dataListCache
632          .filter((re) => re.frame && isFrameContainPoint(re.frame, this.hoverX, this.hoverY, strict, offset)) // @ts-ignore
633          .sort((targetA, targetB) => (targetB as unknown)[maxKey] - (targetA as unknown)[maxKey]);
634        item = arr[0];
635      } else {
636        item = this.dataListCache.find(
637          (re) => re.frame && isFrameContainPoint(re.frame, this.hoverX, this.hoverY, strict, offset)
638        );
639      }
640    }
641    return item;
642  }
643
644  // @ts-ignore
645  addChildTraceRow(child: TraceRow<unknown>): void {
646    // @ts-ignore
647    TraceRowConfig.allTraceRowList.push(child);
648    child.parentRowEl = this;
649    this.toParentAddTemplateType(child);
650    child.setAttribute('scene', '');
651    this.childrenList.push(child);
652    child.rowHidden = false;
653    this.fragment.appendChild(child);
654  }
655
656  // @ts-ignore
657  addChildTraceRowAfter(child: TraceRow<unknown>, targetRow: TraceRow<unknown>): void {
658    // @ts-ignore
659    TraceRowConfig.allTraceRowList.push(child);
660    child.parentRowEl = this;
661    this.toParentAddTemplateType(child);
662    let index = this.childrenList.indexOf(targetRow);
663    child.setAttribute('scene', '');
664    if (index !== -1) {
665      this.childrenList.splice(index + 1, 0, child);
666      child.rowHidden = false;
667      this.fragment.insertBefore(child, this.fragment.childNodes.item(index + 1));
668    } else {
669      this.childrenList.push(child);
670      child.rowHidden = false;
671      this.fragment.append(child);
672    }
673  }
674
675  addChildTraceRowBefore(child: TraceRow<BaseStruct>, targetRow: TraceRow<BaseStruct>): void {
676    TraceRowConfig.allTraceRowList.push(child);
677    child.parentRowEl = this;
678    this.toParentAddTemplateType(child);
679    let index = this.childrenList.indexOf(targetRow);
680    child.setAttribute('scene', '');
681    if (index !== -1) {
682      this.childrenList.splice(index, 0, child);
683      this.fragment.insertBefore(child, this.fragment.childNodes.item(index));
684    } else {
685      this.childrenList.push(child);
686      child.rowHidden = false;
687      this.fragment.appendChild(child);
688    }
689  }
690
691  addRowSampleUpload(type: string = 'application/json'): void {
692    this.sampleUploadEl = document.createElement('div');
693    this.sampleUploadEl!.className = 'upload';
694    this.sampleUploadEl!.innerHTML = `
695    <input id="file" class="file" accept="${type}"  type="file" style="display:none;pointer-events:none"/>
696    <label for="file" style="cursor:pointer">
697      <lit-icon class="folder" name="copy-csv" size="19"></lit-icon>
698    </label>`;
699    this.jsonFileEl = this.sampleUploadEl!.querySelector('.file') as HTMLInputElement;
700    this.sampleUploadEl!.addEventListener('change', () => {
701      let files = this.jsonFileEl!.files;
702      if (files && files.length > 0) {
703        this.sampleUploadEl!.dispatchEvent(
704          new CustomEvent('sample-file-change', {
705            detail: files[0],
706          })
707        );
708        if (this.jsonFileEl) {
709          this.jsonFileEl.value = '';
710        }
711      }
712    });
713    this.sampleUploadEl!.addEventListener('click', (e): void => {
714      e.stopPropagation();
715    });
716    this.describeEl?.appendChild(this.sampleUploadEl!);
717  }
718  // @ts-ignore
719  addChildTraceRowSpecifyLocation(child: TraceRow<unknown>, index: number): void {
720    // @ts-ignore
721    TraceRowConfig.allTraceRowList.push(child);
722    child.parentRowEl = this;
723    child.setAttribute('scene', '');
724    this.childrenList.splice(index, 0, child);
725    child.rowHidden = false;
726    this.fragment.insertBefore(child, this.fragment.childNodes.item(index));
727  }
728
729  insertAfter(newEl: DocumentFragment, targetEl: HTMLElement): void {
730    let parentEl = targetEl.parentNode;
731    if (parentEl) {
732      if (parentEl!.lastChild === targetEl) {
733        parentEl!.appendChild(newEl);
734      } else {
735        parentEl!.insertBefore(newEl, targetEl.nextSibling);
736      }
737    }
738  }
739
740  sortRenderServiceData(
741    child: TraceRow<BaseStruct>,
742    targetRow: TraceRow<BaseStruct>,
743    threadRowArr: Array<TraceRow<BaseStruct>>,
744    flag: boolean
745  ): void {
746    if (child.rowType === 'thread') {
747      threadRowArr.push(child);
748    } else {
749      let index: number = threadRowArr.indexOf(targetRow);
750      if (index !== -1) {
751        threadRowArr.splice(index + 1, 0, child);
752      } else {
753        threadRowArr.push(child);
754      }
755    }
756    if (flag) {
757      let order: string[] = [
758        'VSyncGenerator',
759        'VSync-rs',
760        'VSync-app',
761        'render_service',
762        'RSUniRenderThre',
763        'Release Fence',
764        'Acquire Fence',
765        'RSHardwareThrea',
766        'Present Fence',
767      ];
768      let filterOrderArr: Array<TraceRow<BaseStruct>> = [];
769      let filterNotOrderArr: Array<TraceRow<BaseStruct>> = [];
770      for (let i = 0; i < threadRowArr.length; i++) {
771        // @ts-ignore
772        const element: TraceRow<unknown> = threadRowArr[i];
773        let renderFlag: boolean =
774          element.name.startsWith('render_service') && element.rowId === element.rowParentId ? true : false;
775        if (renderFlag) {
776          // @ts-ignore
777          filterOrderArr.push(element);
778        } else if (order.includes(element.namePrefix!) && !element.name.startsWith('render_service')) {
779          // @ts-ignore
780          filterOrderArr.push(element);
781        } else if (!order.includes(element.namePrefix!) || !renderFlag) {
782          // @ts-ignore
783          filterNotOrderArr.push(element);
784        }
785      }
786      filterOrderArr.sort((star, next) => {
787        return order.indexOf(star.namePrefix!) - order.indexOf(next.namePrefix!);
788      });
789      let combinedArr = [...filterOrderArr, ...filterNotOrderArr];
790      combinedArr.forEach((item): void => {
791        this.addChildTraceRow(item);
792      });
793    }
794  }
795
796  set tip(value: string) {
797    if (this.tipEL) {
798      this.tipEL.innerHTML = value;
799    }
800  }
801
802  get frame(): Rect {
803    if (this._frame) {
804      this._frame.width = TraceRow.FRAME_WIDTH;
805      this._frame.height = this.clientHeight;
806      return this._frame;
807    } else {
808      this._frame = new Rect(0, 0, TraceRow.FRAME_WIDTH, this.clientHeight || 40);
809      return this._frame;
810    }
811  }
812
813  set frame(f: Rect) {
814    this._frame = f;
815  }
816
817  get checkType(): string {
818    return this.getAttribute('check-type') || '';
819  }
820
821  set checkType(value: string) {
822    if (!value || value.length === 0) {
823      this.removeAttribute('check-type');
824      return;
825    }
826    if (this.getAttribute('check-type') === value) {
827      return;
828    }
829    if (this.folder) {
830      this.childrenList.forEach((it) => (it.checkType = value));
831    }
832    if (this.refreshCheckType()) {
833      return;
834    }
835    this.setAttribute('check-type', value);
836    if (this.hasAttribute('disabled-check')) {
837      this.checkBoxEL!.style.display = 'none';
838      return;
839    }
840    switch (value) {
841      case '-1':
842        this.checkBoxEL!.style.display = 'none';
843        this.rangeSelect = false;
844        break;
845      case '0':
846        this.checkBoxEL!.style.display = 'flex';
847        this.checkBoxEL!.checked = false;
848        this.checkBoxEL!.indeterminate = false;
849        this.rangeSelect = false;
850        break;
851      case '1':
852        this.checkBoxEL!.style.display = 'flex';
853        this.checkBoxEL!.checked = false;
854        this.checkBoxEL!.indeterminate = true;
855        this.rangeSelect = false;
856        break;
857      case '2':
858        this.rangeSelect = true;
859        this.checkBoxEL!.style.display = 'flex';
860        this.checkBoxEL!.checked = true;
861        this.checkBoxEL!.indeterminate = false;
862        break;
863    }
864  }
865
866  get drawType(): number {
867    return this._drawType;
868  }
869
870  set drawType(value: number) {
871    this._drawType = value; // @ts-ignore
872    let radioList: NodeListOf<unknown> = this.shadowRoot!.querySelectorAll('input[type=radio][name=status]');
873    if (radioList!.length > 0) {
874      // @ts-ignore
875      radioList[Number(value)].checked = true;
876    }
877  }
878
879  get highlight(): boolean {
880    return this.hasAttribute('expansion');
881  }
882
883  set highlight(value: boolean) {
884    if (value) {
885      this.setAttribute('highlight', '');
886    } else {
887      this.removeAttribute('highlight');
888    }
889  }
890
891  set folderPaddingLeft(value: number) {
892    if (this.folderIcon) {
893      this.folderIcon.style.marginLeft = `${value}px`;
894    }
895  }
896
897  set folderTextLeft(value: number) {
898    this.nameEL!.style.marginLeft = `${value}px`;
899  }
900
901  set xpowerRowTitle(value: string) {
902    this.nameEL!.title = `${value}`;
903  }
904
905  initElements(): void {
906    this.rootEL = this.shadowRoot?.querySelector('.root');
907    this.checkBoxEL = this.shadowRoot?.querySelector<LitCheckBox>('.lit-check-box');
908    this.collectEL = this.shadowRoot?.querySelector<LitIcon>('.collect');
909    this.describeEl = this.shadowRoot?.querySelector('.describe');
910    this.nameEL = this.shadowRoot?.querySelector('.name');
911    this.canvasVessel = this.shadowRoot?.querySelector('.panel-vessel');
912    this.tipEL = this.shadowRoot?.querySelector('.tip'); // @ts-ignore
913    let canvasNumber = this.args.canvasNumber; // @ts-ignore
914    if (!this.args.skeleton) {
915      for (let i = 0; i < canvasNumber; i++) {
916        let canvas = document.createElement('canvas');
917        canvas.className = 'panel';
918        this.canvas.push(canvas);
919        if (this.canvasVessel) {
920          this.canvasVessel.appendChild(canvas);
921        }
922      }
923    }
924    this.checkBoxEvent();
925    this.describeEl?.addEventListener('click', () => {
926      if (this.folder) {
927        this.expansion = !this.expansion;
928        this.sticky = this.expansion;
929      }
930    });
931    this.funcExpand = true;
932    if (this.rowSettingTree) {
933      this.rowSettingTree.onChange = (e: unknown): void => {
934        // @ts-ignore
935        this.rowSettingPop!.visible = false;
936        if (this.rowSettingTree?.multiple) {
937          // @ts-ignore
938          this.rowSettingPop!.visible = true;
939        } else {
940          // @ts-ignore
941          this.rowSettingPop!.visible = false;
942        } //@ts-ignore
943        this.onRowSettingChangeHandler?.(this.rowSettingTree!.getCheckdKeys(), this.rowSettingTree!.getCheckdNodes());
944      };
945    }
946    this.checkType = '-1';
947  }
948
949  private checkBoxEvent(): void {
950    this.checkBoxEL!.onchange = (ev: unknown): void => {
951      info('checkBoxEL onchange '); // @ts-ignore
952      if (!ev.target.checked) {
953        info('checkBoxEL target not checked');
954        this.rangeSelect = false;
955        this.checkType = '0';
956      } else {
957        this.rangeSelect = true;
958        this.checkType = '2';
959      } // @ts-ignore
960      this.setCheckBox(ev.target.checked); // @ts-ignore
961      ev.stopPropagation();
962    };
963    // 防止事件冒泡触发两次describeEl的点击事件
964    this.checkBoxEL!.onclick = (ev: unknown): void => {
965      // @ts-ignore
966      ev.stopPropagation();
967    };
968  }
969
970  addRowCheckFilePop(): void {
971    this.rowCheckFilePop = document.createElement('litpopover') as LitPopover;
972    this.rowCheckFilePop.innerHTML = `<div slot="content" id="jsonFile" style="display: block;height: auto;max-height:200px;overflow-y:auto">
973    </div>
974    <lit-icon name="copy-csv" size="19" id="myfolder"></lit-icon>
975    <input type="file" id="jsoninput" style="width:0px;height:0px"placeholder=''/>`;
976    this.rowCheckFilePop.id = 'rowCheckFile';
977    this.rowCheckFilePop.className = 'popover checkFile';
978    this.rowCheckFilePop.setAttribute('trigger', 'click');
979    this.rowCheckFilePop?.addEventListener('mouseenter', (e): void => {
980      window.publish(window.SmartEvent.UI.HoverNull, undefined);
981    });
982    this.fileEL = this.rowCheckFilePop.querySelector('#jsoninput');
983    this.rowCheckFilePop.addEventListener('click', (e): void => {
984      // @ts-ignore
985      this.fileEL.click();
986    }); // @ts-ignore
987    this.fileEL.addEventListener('click', (event: Event) => {
988      event.stopPropagation();
989    });
990
991    window.addEventListener('storage', (e): void => {
992      if (e.storageArea === sessionStorage) {
993        if (e.key === 'freqInfoData') {
994          this.onRowCheckFileChangeHandler?.();
995        }
996      }
997    }); // @ts-ignore
998    this.fileEL.addEventListener(
999      'change',
1000      (e: unknown): void => {
1001        // @ts-ignore
1002        let file = e.target.files[0];
1003        if (file && file.type === 'application/json') {
1004          let file_reader = new FileReader();
1005          file_reader.readAsText(file, 'UTF-8');
1006          file_reader.onload = (): void => {
1007            let fc = file_reader.result;
1008            window.sessionStorage.setItem('freqInfoData', JSON.stringify(fc));
1009            this.onRowCheckFileChangeHandler?.();
1010            alert('json文件上传成功!'); // @ts-ignore
1011            this.fileEL.value = '';
1012          };
1013        } else {
1014          return;
1015        }
1016      },
1017      false
1018    );
1019    this.describeEl?.appendChild(this.rowCheckFilePop);
1020  }
1021
1022  addRowSettingCheckBox(): void {
1023    let nameEl = this.shadowRoot && (this.shadowRoot.querySelector('.name') as HTMLLabelElement);
1024    nameEl && (nameEl.style.maxWidth = '160px');
1025    let collectEl = (this.shadowRoot && this.shadowRoot.querySelector('.collect') as LitIcon);
1026    collectEl && (collectEl.style.marginRight = '20px');
1027    this.rowSettingCheckBoxPop = document.createElement('lit-popover') as LitPopover;
1028    let checkboxHtml = '';
1029    checkboxHtml += `<div class="checkboxAll" style="margin-bottom: 2px;">
1030        <lit-check-box class="lit-checkbox" value="All" checked></lit-check-box></div>`;
1031    this._rowSettingCheckBoxList && this._rowSettingCheckBoxList.forEach((item) => {
1032      checkboxHtml += `<div class="checkboxItem" style="margin-bottom: 2px;">
1033      <lit-check-box class="lit-checkbox" checked style="margin-left: 20px;" not-close value="${item}"></lit-check-box>
1034      </div>`; });
1035    this._rowSettingCheckedBoxList = new Array(this._rowSettingCheckBoxList?.length).fill(true);
1036    this.rowSettingCheckBoxPop.innerHTML = `<div slot="content" id="settingList"
1037      style="display: block;height: auto;max-height:200px;overflow-y:auto">
1038      ${checkboxHtml} </div>
1039      <lit-icon name="setting" size="19" id="setting"></lit-icon>`;
1040    let allCheckBox = this.rowSettingCheckBoxPop!.querySelector('.checkboxAll>.lit-checkbox') as LitCheckBox;
1041    let checkBoxItems = this.rowSettingCheckBoxPop.querySelectorAll('.checkboxItem>.lit-checkbox');
1042    checkBoxItems.forEach(item => {
1043      // @ts-ignore
1044      item.onchange = (e: unknown): void => {
1045        // @ts-ignore
1046        this._rowSettingCheckedBoxList[this._rowSettingCheckBoxList?.indexOf(item.value)] = item.checked;
1047        const allChecked = this._rowSettingCheckedBoxList!.every(item => item);
1048        allCheckBox.checked = allChecked;
1049        this.onRowSettingCheckBoxChangeHandler?.(this._rowSettingCheckedBoxList!);
1050      };
1051    });
1052    allCheckBox.onchange = (e: unknown): void => {
1053      checkBoxItems.forEach(item => {
1054        // @ts-ignore
1055        item.checked = allCheckBox.checked;
1056      });
1057      this._rowSettingCheckedBoxList!.forEach((_, index) => {
1058        this._rowSettingCheckedBoxList![index] = allCheckBox.checked;
1059      });
1060      this.onRowSettingCheckBoxChangeHandler?.(this._rowSettingCheckedBoxList!);
1061    };
1062    this.rowSettingCheckBoxPop.id = 'rowSetting';
1063    this.rowSettingCheckBoxPop.className = 'popover setting';
1064    this.rowSettingCheckBoxPop.setAttribute('placement', 'bottomLeft');
1065    this.rowSettingCheckBoxPop.setAttribute('trigger', 'click');
1066    this.rowSettingCheckBoxPop.setAttribute('haveCheckbox', 'true');
1067    this.rowSettingCheckBoxPop?.addEventListener('mouseenter', (): void => {
1068      window.publish(window.SmartEvent.UI.HoverNull, undefined);
1069    });
1070    this.describeEl?.appendChild(this.rowSettingCheckBoxPop);
1071  }
1072
1073  addRowSettingPop(): void {
1074    let nameEl = this.shadowRoot && (this.shadowRoot.querySelector('.name') as HTMLLabelElement);
1075    nameEl && (nameEl.style.maxWidth = '160px');
1076    let collectEl = (this.shadowRoot && this.shadowRoot.querySelector('.collect') as LitIcon);
1077    collectEl && (collectEl.style.marginRight = '20px');
1078    this.rowSettingPop = document.createElement('lit-popover') as LitPopover;
1079    this.rowSettingPop.innerHTML = `<div slot="content" id="settingList"
1080      style="display: block;height: auto;max-height:200px;overflow-y:auto">
1081      <lit-tree id="rowSettingTree" checkable="true"></lit-tree>
1082      </div>
1083      <lit-icon name="setting" size="19" id="setting"></lit-icon>`;
1084    this.rowSettingPop.id = 'rowSetting';
1085    this.rowSettingPop.className = 'popover setting';
1086    this.rowSettingPop.setAttribute('placement', 'bottomLeft');
1087    this.rowSettingPop.setAttribute('trigger', 'click');
1088    this.rowSettingPop.setAttribute('haveRadio', 'true');
1089    this.rowSettingTree = this.rowSettingPop.querySelector('#rowSettingTree') as LitTree;
1090    this.rowSettingTree.onChange = (): void => {
1091      TraceRow.ROW_TYPE_HIPERF_THREADTYPE = [];
1092      let isVisible = false;
1093      // @ts-ignore
1094      this.rowSettingPop!.visible = isVisible;
1095      if (this.rowSettingTree?.multiple) {
1096        isVisible = true;
1097      }
1098      // @ts-ignore
1099      this.rowSettingPop!.visible = isVisible;
1100      TraceRow.ROW_TYPE_HIPERF_THREADTYPE.push(Number(this.rowSettingTree!.getCheckdKeys())); //@ts-ignore
1101      this.onRowSettingChangeHandler?.(this.rowSettingTree!.getCheckdKeys(), this.rowSettingTree!.getCheckdNodes());
1102    };
1103    this.rowSettingPop?.addEventListener('mouseenter', (): void => {
1104      window.publish(window.SmartEvent.UI.HoverNull, undefined);
1105    });
1106    this.describeEl?.appendChild(this.rowSettingPop);
1107  }
1108
1109  getRowSettingKeys(): Array<string> {
1110    if (this.rowSetting === 'enable') {
1111      //@ts-ignore
1112      return this.rowSettingTree!.getCheckdKeys();
1113    }
1114    return [];
1115  }
1116
1117  //@ts-ignore
1118  expandFunc(rootRow: TraceRow<unknown>, sp: SpSystemTrace): void {
1119    if (this._enableCollapseChart && !this.funcExpand) {
1120      let foldHeight = Number(this.style.height.substring(0, this.style.height.length - 2));
1121      this.style.height = `${this.funcMaxHeight}px`;
1122      this.funcExpand = true;
1123      rootRow.needRefresh = true;
1124      sp.refreshCanvas(true);
1125      if (this.collect) {
1126        window.publish(window.SmartEvent.UI.RowHeightChange, {
1127          expand: this.funcExpand,
1128          value: this.funcMaxHeight - foldHeight,
1129        });
1130      }
1131    }
1132  }
1133
1134  enableCollapseChart(H: number, trace: unknown): void {
1135    this._enableCollapseChart = true;
1136    this.nameEL!.onclick = (): void => {
1137      if (this.funcMaxHeight > H || this.clientHeight > H) {
1138        if (this.funcExpand) {
1139          this.funcMaxHeight = this.clientHeight;
1140          this.style.height = H + 'px';
1141          this.funcExpand = false;
1142        } else {
1143          this.style.height = `${this.funcMaxHeight}px`;
1144          this.funcExpand = true;
1145        }
1146        TraceRow.range!.refresh = true;
1147        this.needRefresh = true;
1148        //@ts-ignore
1149        trace.refreshCanvas(true);
1150        if (this.collect) {
1151          window.publish(window.SmartEvent.UI.RowHeightChange, {
1152            expand: this.funcExpand,
1153            value: this.funcMaxHeight - H,
1154          });
1155        }
1156      }
1157    };
1158  }
1159
1160  initCanvas(list: Array<HTMLCanvasElement>): void {
1161    let timerShaftEL = document!
1162      .querySelector('body > sp-application')!
1163      .shadowRoot!.querySelector('#sp-system-trace')!
1164      .shadowRoot!.querySelector('div > timer-shaft-element');
1165    let timerShaftCanvas = timerShaftEL!.shadowRoot!.querySelector<HTMLCanvasElement>('canvas');
1166    let tempHeight: number = 0;
1167    if (this.rowType === TraceRow.ROW_TYPE_FUNC) {
1168      tempHeight = 20;
1169    } else if (this.rowType === TraceRow.ROW_TYPE_THREAD) {
1170      tempHeight = 30;
1171    } else if (this.rowType === TraceRow.ROW_TYPE_SYSTEM_ENERGY) {
1172      tempHeight = 80;
1173    } else if (this.rowType === TraceRow.ROW_TYPE_POWER_ENERGY) {
1174      tempHeight = 200;
1175    } else if (this.rowType === TraceRow.ROW_TYPE_ANOMALY_ENERGY) {
1176      tempHeight = 55;
1177    } else {
1178      tempHeight = 40;
1179    }
1180    this.dpr = window.devicePixelRatio || 1;
1181    list.forEach((canvas): void => {
1182      this.rootEL!.style.height = `${this.getAttribute('height') || '40'}px`;
1183      canvas.style.width = timerShaftCanvas!.style.width;
1184      canvas.style.height = `${tempHeight}px`;
1185      this.canvasWidth = timerShaftCanvas!.width;
1186      this.canvasHeight = Math.ceil(tempHeight * this.dpr);
1187      canvas.width = this.canvasWidth;
1188      canvas.height = this.canvasHeight;
1189      // @ts-ignore
1190      this.offscreen.push(canvas!.transferControlToOffscreen());
1191    });
1192  }
1193
1194  updateWidth(width: number): void {
1195    this.dpr = window.devicePixelRatio || 1;
1196    let tempHeight: number = 0;
1197    if (this.rowType === TraceRow.ROW_TYPE_FUNC) {
1198      tempHeight = 20;
1199    } else if (this.rowType === TraceRow.ROW_TYPE_THREAD) {
1200      tempHeight = 30;
1201    } else if (this.rowType === TraceRow.ROW_TYPE_SYSTEM_ENERGY) {
1202      tempHeight = 90;
1203    } else if (this.rowType === TraceRow.ROW_TYPE_POWER_ENERGY) {
1204      tempHeight = 200;
1205    } else if (this.rowType === TraceRow.ROW_TYPE_ANOMALY_ENERGY) {
1206      tempHeight = 55;
1207    } else {
1208      tempHeight = 40;
1209    }
1210    if (this.canvas.length > 1) {
1211      tempHeight = 20;
1212    }
1213    this.canvas.forEach((it): void => {
1214      this.canvasWidth = Math.ceil((width - (this.describeEl?.clientWidth || 248)) * this.dpr);
1215      this.canvasHeight = Math.ceil(tempHeight * this.dpr);
1216      it!.style.width = `${width - (this.describeEl?.clientWidth || 248)}px`; // @ts-ignore
1217      if (this.args.isOffScreen) {
1218        this.draw(true);
1219      }
1220    });
1221  }
1222
1223  drawLine(item: HTMLDivElement, direction: string /*string[top|bottom]*/): void {
1224    if (!item) {
1225      return;
1226    }
1227    switch (direction) {
1228      case 'top':
1229        item.classList.remove('line-bottom');
1230        item.classList.add('line-top');
1231        break;
1232      case 'bottom':
1233        item.classList.remove('line-top');
1234        item.classList.add('line-bottom');
1235        break;
1236      case '':
1237        item.classList.remove('line-top');
1238        item.classList.remove('line-bottom');
1239        break;
1240    }
1241  }
1242
1243  connectedCallback(): void {
1244    this.describeEl!.ondragstart = (ev: DragEvent): void => this.rowDragstart(ev);
1245    this.describeEl!.ondragleave = (ev: unknown): void => {
1246      // @ts-ignore
1247      this.drawLine(ev.currentTarget, '');
1248      return undefined;
1249    };
1250    this.describeElEvent();
1251    this.collectEL!.onclick = (e): void => {
1252      this.collect = !this.collect;
1253      if (this.collect) {
1254        this.describeEl!.draggable = false;
1255      } else {
1256        this.describeEl!.draggable = false;
1257      }
1258      document.dispatchEvent(
1259        new CustomEvent('collect', {
1260          detail: {
1261            type: e.type,
1262            row: this,
1263          },
1264        })
1265      );
1266      this.favoriteChangeHandler?.(this);
1267    }; // @ts-ignore
1268    if (!this.args.skeleton) {
1269      this.initCanvas(this.canvas);
1270    }
1271  }
1272
1273  private describeElEvent(): void {
1274    this.describeEl!.ondragend = (ev: unknown): void => {
1275      rowDragId = null; // @ts-ignore
1276      ev.target.classList.remove('drag'); // @ts-ignore
1277      this.drawLine(ev.currentTarget, '');
1278      return undefined;
1279    };
1280    this.describeEl!.ondragover = (ev: unknown): undefined => {
1281      if (!this.collect || rowDragId === this.rowId) {
1282        return;
1283      } // @ts-ignore
1284      let rect = ev.currentTarget.getBoundingClientRect(); // @ts-ignore
1285      if (ev.clientY >= rect.top && ev.clientY < rect.top + rect.height / 2) {
1286        //上面
1287        dragDirection = 'top'; // @ts-ignore
1288        this.drawLine(ev.currentTarget, 'top'); // @ts-ignore
1289      } else if (ev.clientY <= rect.bottom && ev.clientY > rect.top + rect.height / 2) {
1290        //下面
1291        dragDirection = 'bottom'; // @ts-ignore
1292        this.drawLine(ev.currentTarget, 'bottom');
1293      }
1294      return undefined;
1295    };
1296    this.describeEl!.ondrop = (ev: unknown): void => {
1297      if (!this.collect) {
1298        return;
1299      } // @ts-ignore
1300      this.drawLine(ev.currentTarget, '');
1301      let spacer = this.parentElement!.previousElementSibling! as HTMLDivElement;
1302      let startDragNode = collectList.findIndex((it): boolean => it.rowId === rowDragId);
1303      let endDragNode = collectList.findIndex((it): boolean => it === this);
1304      if (startDragNode === -1 || endDragNode === -1) {
1305        return;
1306      }
1307      if (startDragNode < endDragNode && dragDirection === 'top') {
1308        endDragNode--;
1309      } else if (startDragNode > endDragNode && dragDirection === 'bottom') {
1310        endDragNode++;
1311      }
1312      collectList.splice(endDragNode, 0, ...collectList.splice(startDragNode, 1));
1313      collectList.forEach((it, i): void => {
1314        if (i === 0) {
1315          // @ts-ignore
1316          it.style.top = `${spacer.offsetTop + 48}px`;
1317        } else {
1318          it.style.top = `${collectList[i - 1].offsetTop + collectList[i - 1].offsetHeight}px`;
1319        }
1320      });
1321    };
1322  }
1323
1324  rowDragstart(ev: unknown): void {
1325    rowDragId = this.rowId; // @ts-ignore
1326    ev.target.classList.add('drag');
1327  }
1328
1329  setCheckBox(isCheck: boolean): void {
1330    if (this.folder) {
1331      // favorite row  check change;
1332      window.publish(window.SmartEvent.UI.CheckALL, {
1333        rowId: this.rowId,
1334        isCheck: isCheck,
1335      });
1336      this.childrenList!.forEach((ck): void => {
1337        ck.setAttribute('check-type', isCheck ? '2' : '0');
1338        let allCheck: LitCheckBox | null | undefined = ck?.shadowRoot?.querySelector('.lit-check-box');
1339        if (allCheck) {
1340          allCheck!.checked = isCheck;
1341        }
1342      });
1343    }
1344    this.selectChangeHandler?.(this);
1345  }
1346
1347  onMouseHover(x: number, y: number, tip: boolean = true): T | undefined | null {
1348    if (this.tipEL) {
1349      this.tipEL.style.display = 'none';
1350    }
1351    return null;
1352  }
1353
1354  setTipLeft(x: number, struct: unknown): void {
1355    if (struct === null && this.tipEL) {
1356      this.tipEL.style.display = 'none';
1357      return;
1358    }
1359    if (this.tipEL) {
1360      this.tipEL.style.display = 'flex';
1361      if (x + this.tipEL.clientWidth > (this.canvasVessel!.clientWidth || 0)) {
1362        this.tipEL.style.transform = `translateX(${x - this.tipEL.clientWidth - 1}px)`;
1363      } else {
1364        this.tipEL.style.transform = `translateX(${x}px)`;
1365      }
1366    }
1367  }
1368
1369  onMouseLeave(x: number, y: number): void {
1370    if (this.tipEL) {
1371      this.tipEL.style.display = 'none';
1372    }
1373  }
1374
1375  loadingPin1: number = 0;
1376  loadingPin2: number = 0;
1377  static currentActiveRows: Array<string> = [];
1378
1379  drawFrame(): void {
1380    if (!this.hasAttribute('row-hidden')) {
1381      if (!this.loadingFrame || window.isLastFrame || !this.isComplete) {
1382        if (this.needRefresh || window.isLastFrame) {
1383          this.loadingFrame = true;
1384          this.needRefresh = false;
1385          this.loadingPin1 = TraceRow.range?.startNS || 0;
1386          this.loadingPin2 = TraceRow.range?.endNS || 0;
1387          TraceRow.currentActiveRows.push(`${this.rowType}-${this.rowId}`);
1388          this.supplierFrame!().then((res) => {
1389            if (this.onComplete) {
1390              this.onComplete();
1391              this.onComplete = undefined;
1392            }
1393            this.dataListCache = res;
1394            this.dataListCache.push(...this.fixedList);
1395            this.isComplete = true;
1396            this.loadingFrame = false;
1397            let idx = TraceRow.currentActiveRows.findIndex((it): boolean => it === `${this.rowType}-${this.rowId}`);
1398            if (idx !== -1) {
1399              TraceRow.currentActiveRows.splice(idx, 1);
1400            }
1401            requestAnimationFrame(() => {
1402              this.onThreadHandler?.(true, null);
1403              if (TraceRow.currentActiveRows) {
1404                window.publish(window.SmartEvent.UI.LoadFinish, '');
1405              }
1406              window.publish(window.SmartEvent.UI.LoadFinishFrame, '');
1407            });
1408          });
1409        } else if (this.fixedList.length > 0 && !this.dataListCache.includes(this.fixedList[0])) {
1410          this.dataListCache.push(this.fixedList[0]);
1411        }
1412      }
1413      this.onThreadHandler?.(true, null);
1414    }
1415  }
1416
1417  refreshCheckType(): boolean {
1418    if (!this.rangeSelect && this.traceId !== Utils.currentSelectTrace) {
1419      this.checkBoxEL!.style.display = 'none';
1420      this.rangeSelect = false;
1421      this.removeAttribute('check-type');
1422      return true;
1423    }
1424    return false;
1425  }
1426
1427  draw(useCache: boolean = false): void {
1428    this.dpr = window.devicePixelRatio || 1;
1429    if (this.sleeping) {
1430      return;
1431    }
1432    this.refreshCheckType();
1433    if (this.supplierFrame) {
1434      //如果设置了实时渲染,则调用drawFrame
1435      this.drawFrame();
1436      return;
1437    }
1438    if (this.online) {
1439      if (!useCache && !TraceRow.isUserInteraction) {
1440        this.supplier?.().then((res) => {
1441          // @ts-ignore
1442          this.onThreadHandler?.(useCache, res as unknown);
1443        });
1444      }
1445      this.onThreadHandler?.(useCache, null);
1446      return;
1447    }
1448    if (!this.isComplete) {
1449      if (this.supplier && !this.isLoading) {
1450        this.isLoading = true;
1451        this.must = true;
1452        let promise = this.supplier();
1453        if (promise) {
1454          promise.then((res): void => {
1455            this.dataList = res;
1456            if (this.onComplete) {
1457              this.onComplete();
1458            }
1459            window.publish(window.SmartEvent.UI.TraceRowComplete, this);
1460            this.isComplete = true;
1461            this.isLoading = false;
1462            this.draw(false);
1463          });
1464        } else {
1465          this.isLoading = false;
1466          this.draw(false);
1467        }
1468      }
1469    } else {
1470      if (!this.hasAttribute('row-hidden')) {
1471        if (this.onThreadHandler && this.dataList) {
1472          this.onThreadHandler!(false, null);
1473        }
1474      }
1475    }
1476  }
1477
1478  canvasSave(ctx: CanvasRenderingContext2D): void {
1479    ctx.save();
1480    ctx.translate(0, this.translateY);
1481    const clipRect = new Path2D(); // @ts-ignore
1482    clipRect.rect(0, 0, this.frame.width, this.frame.height);
1483    ctx.clip(clipRect);
1484  }
1485
1486  canvasRestore(ctx: CanvasRenderingContext2D, trace?: SpSystemTrace | null): void {
1487    drawSelectionRange(ctx, this);
1488    ctx.restore();
1489  }
1490
1491  clearCanvas(ctx: CanvasRenderingContext2D): void {
1492    if (ctx) {
1493      this.canvas.forEach((it): void => {
1494        ctx.clearRect(0, 0, it!.clientWidth || 0, it!.clientHeight || 0);
1495      });
1496    }
1497  }
1498
1499  drawLines(ctx: CanvasRenderingContext2D): void {
1500    if (ctx) {
1501      ctx.lineWidth = 1;
1502      ctx.strokeStyle = this.getLineColor();
1503      TraceRow.range?.xs.forEach((it): void => {
1504        ctx.moveTo(Math.floor(it), 0);
1505        ctx.lineTo(Math.floor(it), this.shadowRoot?.host.clientHeight || 0);
1506      });
1507      ctx.stroke();
1508    }
1509  }
1510
1511  getLineColor(): string {
1512    return window.getComputedStyle(this.rootEL!, null).getPropertyValue('border-bottom-color');
1513  }
1514
1515  drawSelection(ctx: CanvasRenderingContext2D): void {
1516    if (this.rangeSelect) {
1517      TraceRow.rangeSelectObject!.startX = Math.floor(
1518        ns2x(
1519          TraceRow.rangeSelectObject!.startNS!,
1520          TraceRow.range!.startNS,
1521          TraceRow.range!.endNS,
1522          TraceRow.range!.totalNS!, // @ts-ignore
1523          this.frame
1524        )
1525      );
1526      TraceRow.rangeSelectObject!.endX = Math.floor(
1527        ns2x(
1528          TraceRow.rangeSelectObject!.endNS!,
1529          TraceRow.range!.startNS,
1530          TraceRow.range!.endNS,
1531          TraceRow.range!.totalNS!, // @ts-ignore
1532          this.frame
1533        )
1534      );
1535      if (ctx) {
1536        ctx.globalAlpha = 0.5;
1537        ctx.fillStyle = '#666666';
1538        ctx.fillRect(
1539          TraceRow.rangeSelectObject!.startX!, // @ts-ignore
1540          this.frame.y,
1541          TraceRow.rangeSelectObject!.endX! - TraceRow.rangeSelectObject!.startX!, // @ts-ignore
1542          this.frame.height
1543        );
1544        ctx.globalAlpha = 1;
1545      }
1546    }
1547  }
1548
1549  isInTimeRange(startTime: number, duration: number): boolean {
1550    return (
1551      (startTime || 0) + (duration || 0) > (TraceRow.range?.startNS || 0) &&
1552      (startTime || 0) < (TraceRow.range?.endNS || 0)
1553    );
1554  }
1555
1556  buildArgs(obj: unknown): unknown {
1557    let result: unknown = {
1558      list: this.must ? this.dataList : undefined,
1559      offscreen: !this.isTransferCanvas ? this.offscreen[0] : undefined, //是否离屏
1560      dpr: this.dpr, //屏幕dpr值
1561      xs: TraceRow.range?.xs, //线条坐标信息
1562      isHover: this.isHover,
1563      hoverX: this.hoverX,
1564      hoverY: this.hoverY,
1565      canvasWidth: this.canvasWidth,
1566      canvasHeight: this.canvasHeight,
1567      isRangeSelect: this.rangeSelect,
1568      rangeSelectObject: TraceRow.rangeSelectObject,
1569      lineColor: this.getLineColor(),
1570      chartColor: ColorUtils.MD_PALETTE[0],
1571      startNS: TraceRow.range?.startNS || 0,
1572      endNS: TraceRow.range?.endNS || 0,
1573      totalNS: TraceRow.range?.totalNS || 0,
1574      slicesTime: TraceRow.range?.slicesTime,
1575      range: TraceRow.range,
1576      frame: this.frame,
1577      flagMoveInfo: null,
1578      flagSelectedInfo: null,
1579      wakeupBean: null,
1580    }; // @ts-ignore
1581    Reflect.ownKeys(obj).forEach((it): void => {
1582      // @ts-ignore
1583      result[it] = obj[it];
1584    });
1585    return result;
1586  }
1587
1588  getTransferArray(): unknown[] {
1589    let tsf = [];
1590    if (!this.isTransferCanvas) {
1591      tsf.push(this.offscreen[0]);
1592    }
1593    if (this.must && this.dataList instanceof ArrayBuffer) {
1594      tsf.push(this.dataList);
1595    }
1596    return tsf;
1597  }
1598
1599  attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
1600    switch (name) {
1601      case 'name':
1602        if (this.nameEL) {
1603          this.nameEL.textContent = newValue;
1604          this.nameEL.title = newValue;
1605        }
1606        break;
1607      case 'height':
1608        if (newValue !== oldValue) {
1609          // @ts-ignore
1610          if (!this.args.isOffScreen) {
1611          }
1612        }
1613        break;
1614      case 'check-type':
1615        if (newValue === 'check') {
1616          this.checkBoxEL?.setAttribute('checked', '');
1617        } else {
1618          this.checkBoxEL?.removeAttribute('checked');
1619        }
1620        break;
1621    }
1622  }
1623
1624  focusContain(e: MouseEvent, inFavoriteArea: boolean, prevScrollY: number = 0, favoriteHeight: number): boolean {
1625    let _y = (e.currentTarget as HTMLElement).getBoundingClientRect().y;
1626    let myRect = this.getBoundingClientRect();
1627    let x = e.offsetX;
1628    let y = e.offsetY + _y;
1629    let rectY = myRect.y;
1630    let rectHeight = myRect.height;
1631    if (!inFavoriteArea && favoriteHeight !== undefined) {
1632      let expand = sessionStorage.getItem('expand');
1633      let foldHeight = Number(sessionStorage.getItem('foldHeight'));
1634      y = expand === 'true' ?
1635        (e.offsetY + prevScrollY - 148 - favoriteHeight!) :
1636        (e.offsetY + prevScrollY - (148 - foldHeight) - favoriteHeight!);
1637      rectY = this.offsetTop;
1638      rectHeight = this.clientHeight;
1639    }
1640    if (x >= myRect.x && x <= myRect.x + myRect.width && y >= rectY &&
1641      y <= rectY + rectHeight) {
1642      this.hoverX = x - this.describeEl!.clientWidth;
1643      this.hoverY = y - rectY;
1644      this.isHover = this.collect === inFavoriteArea;
1645      return true;
1646    } else {
1647      this.isHover = false;
1648      if (this.tipEL) {
1649        this.tipEL.style.display = 'none';
1650      }
1651      return false;
1652    }
1653  }
1654
1655  initHtml(): string {
1656    return TraceRowHtml;
1657  }
1658}
1659