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