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