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