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