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 { BaseElement, element } from '../../../base-ui/BaseElement'; 17import { TraceRow } from './base/TraceRow'; 18import { dpr } from './base/Extension'; 19import { 20 drawFlagLineSegment, 21 drawLines, 22 drawLinkLines, 23 drawLogsLineSegment, 24 drawWakeUp, 25 drawWakeUpList, 26 PairPoint, 27 Rect, 28} from '../../database/ui-worker/ProcedureWorkerCommon'; 29import { Flag } from './timer-shaft/Flag'; 30import { TimerShaftElement } from './TimerShaftElement'; 31import { CpuStruct } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 32import { WakeupBean } from '../../bean/WakeupBean'; 33import { LitIcon } from '../../../base-ui/icon/LitIcon'; 34import { SpSystemTrace } from '../SpSystemTrace'; 35 36const maxScale = 0.8; //收藏最大高度为界面最大高度的80% 37const topHeight = 150; // 顶部cpu使用率部分高度固定为150px 38const minHeight = 40; //泳道最低高度为40 39const mouseMoveRange = 5; 40 41@element('sp-chart-list') 42export class SpChartList extends BaseElement { 43 private static COLLECT_G1 = '1'; 44 private static COLLECT_G2 = '2'; 45 private collectEl1: HTMLDivElement | null | undefined; 46 private collectEl2: HTMLDivElement | null | undefined; 47 private groupTitle1: HTMLDivElement | null | undefined; 48 private groupTitle2: HTMLDivElement | null | undefined; 49 private icon1: LitIcon | null | undefined; 50 private icon2: LitIcon | null | undefined; 51 private removeCollectIcon1: LitIcon | null | undefined; 52 private removeCollectIcon2: LitIcon | null | undefined; 53 private rootEl: HTMLDivElement | null | undefined; 54 private fragmentGroup1: DocumentFragment = document.createDocumentFragment(); 55 private fragmentGroup2: DocumentFragment = document.createDocumentFragment(); 56 private canvas: HTMLCanvasElement | null | undefined; //绘制收藏泳道图 57 private canvasCtx: CanvasRenderingContext2D | undefined | null; 58 private canResize: boolean = false; 59 private isPress: boolean = false; 60 private startPageY = 0; 61 private startClientHeight: number = 0; 62 private scrollTimer: unknown; 63 collect1Expand: boolean = true; 64 collect2Expand: boolean = true; 65 // @ts-ignore 66 private collectRowList1: Array<TraceRow<unknown>> = []; 67 // @ts-ignore 68 private collectRowList2: Array<TraceRow<unknown>> = []; 69 private maxHeight = 0; 70 private manualHeight = 0; 71 private spSystemTrace: SpSystemTrace | undefined | null; 72 73 initElements(): void { 74 this.spSystemTrace = document?.querySelector('body > sp-application')?.shadowRoot?.querySelector('#sp-system-trace'); 75 this.collectEl1 = this.shadowRoot?.querySelector<HTMLDivElement>('#collect-group-1'); 76 this.collectEl2 = this.shadowRoot?.querySelector<HTMLDivElement>('#collect-group-2'); 77 this.groupTitle1 = this.shadowRoot?.querySelector<HTMLDivElement>('#group-1-title'); 78 this.groupTitle2 = this.shadowRoot?.querySelector<HTMLDivElement>('#group-2-title'); 79 this.icon1 = this.shadowRoot?.querySelector<LitIcon>('#group_1_expand'); 80 this.icon2 = this.shadowRoot?.querySelector<LitIcon>('#group_2_expand'); 81 this.removeCollectIcon1 = this.shadowRoot?.querySelector<LitIcon>('#group_1_collect'); 82 this.removeCollectIcon2 = this.shadowRoot?.querySelector<LitIcon>('#group_2_collect'); 83 this.rootEl = this.shadowRoot?.querySelector<HTMLDivElement>('.root'); 84 this.canvas = this.shadowRoot?.querySelector<HTMLCanvasElement>('.panel-canvas'); 85 this.canvasCtx = this.canvas?.getContext('2d'); //@ts-ignore 86 window.subscribe(window.SmartEvent.UI.RowHeightChange, (data: { expand: number; value: number }) => { 87 this.resizeHeight(); 88 if (!data.expand) { 89 let offset = this.scrollTop - data.value; 90 offset = offset < 0 ? 0 : offset; 91 this.scrollTop = offset; 92 } 93 this.refreshFavoriteCanvas(); 94 }); 95 this.initChartListListener(); 96 } 97 98 private initChartListListener(): void { 99 let offsetYTimeOut: unknown = undefined; 100 const foldCollect1 = (): void => { 101 if (offsetYTimeOut) { 102 //@ts-ignore 103 clearTimeout(offsetYTimeOut); 104 } 105 this.collect1Expand = !this.collect1Expand; 106 if (this.collect1Expand) { 107 this.icon1!.style.transform = 'rotateZ(0deg)'; 108 this.collectEl1?.appendChild(this.fragmentGroup1); 109 if (!this.collect2Expand) { // G1展开,G2折叠时处理连线y坐标 110 this.handleCollect2LinkNodeY(); 111 } 112 } else { 113 this.icon1!.style.transform = 'rotateZ(-90deg)'; 114 this.collectRowList1.forEach((row) => this.fragmentGroup1.appendChild(row)); 115 offsetYTimeOut = setTimeout(() => { //折叠G1收藏栏,连线处理 116 this.handleCollect1LinkNodeY(); 117 if (!this.collect2Expand) { 118 this.handleCollect2LinkNodeY(); 119 } 120 this.spSystemTrace?.refreshCanvas(true); 121 }, 50); 122 } 123 this.resizeHeight(); 124 }; 125 this.icon1?.addEventListener('click', () => foldCollect1()); 126 const foldCollect2 = (): void => { 127 this.collect2Expand = !this.collect2Expand; 128 if (this.collect2Expand) { 129 this.icon2!.style.transform = 'rotateZ(0deg)'; 130 this.collectEl2?.appendChild(this.fragmentGroup2); 131 this.scrollTop = this.scrollHeight; 132 } else { 133 this.icon2!.style.transform = 'rotateZ(-90deg)'; 134 this.collectRowList2.forEach((row) => this.fragmentGroup2.appendChild(row)); 135 this.scrollTop = 0; 136 offsetYTimeOut = setTimeout(() => { 137 this.handleCollect2LinkNodeY(); 138 this.spSystemTrace?.refreshCanvas(true); 139 }, 50); 140 } 141 this.resizeHeight(); 142 }; 143 this.icon2?.addEventListener('click', () => foldCollect2()); 144 document.addEventListener('keyup', (e) => { 145 if (e.key.toLowerCase() === 'b' && e.ctrlKey === false && this.spSystemTrace?.keyboardEnable) { 146 // 收藏夹有泳道时 为true 147 const hasChildNode1 = this.collectEl1?.hasChildNodes() || this.fragmentGroup1.hasChildNodes(); 148 const hasChildNode2 = this.collectEl2?.hasChildNodes() || this.fragmentGroup2.hasChildNodes(); 149 // 两个收藏夹都有泳道时 150 if (hasChildNode1 && hasChildNode2) { 151 const flag = this.collect1Expand === this.collect2Expand; 152 if (flag) { 153 foldCollect1(); 154 foldCollect2(); 155 } else { 156 // 两收藏夹的折叠状态不一致 优先一起折叠 157 if (this.collect1Expand) { 158 foldCollect1(); 159 } 160 else { 161 foldCollect2(); 162 } 163 } 164 return; 165 } 166 // 只影响有泳道的收藏夹 167 if (hasChildNode1) { 168 foldCollect1(); 169 } 170 if (hasChildNode2) { 171 foldCollect2(); 172 } 173 } 174 }); 175 176 this.removeCollectIcon1?.addEventListener('click', () => { 177 Array.from(this.collectRowList1).forEach(row => { 178 row.collectEL?.click(); 179 }); 180 }); 181 this.removeCollectIcon2?.addEventListener('click', () => { 182 Array.from(this.collectRowList2).forEach(row => { 183 row.collectEL?.click(); 184 }); 185 }); 186 } 187 188 // 处理G1收藏栏折叠时,连线的y坐标 189 private handleCollect1LinkNodeY(): void { 190 this.spSystemTrace?.linkNodes?.forEach(linkItem => { 191 if (linkItem[0].rowEL.collectGroup === linkItem[1].rowEL.collectGroup && linkItem[1].rowEL.collectGroup === '1') { // 起点终点都在G1 192 linkItem[0].rowEL.translateY = 23; 193 linkItem[1].rowEL.translateY = 23; 194 } else if (linkItem[0].rowEL.collectGroup !== linkItem[1].rowEL.collectGroup) { // 起点终点不在同个收藏栏 195 if (linkItem[0].rowEL.collectGroup === '1') { 196 linkItem[0].rowEL.translateY = 23; 197 } else if (linkItem[1].rowEL.collectGroup === '1') { 198 linkItem[1].rowEL.translateY = 23; 199 } 200 } 201 }); 202 } 203 204 // 处理G2收藏栏折叠时,连线的y坐标 205 private handleCollect2LinkNodeY(): void { 206 this.spSystemTrace?.linkNodes?.forEach(linkItem => { 207 if (linkItem[0].rowEL.collectGroup === linkItem[1].rowEL.collectGroup && linkItem[1].rowEL.collectGroup === '2') { // 起点终点都在G2 208 linkItem[0].rowEL.translateY = 23; 209 linkItem[1].rowEL.translateY = 23; 210 } else if (linkItem[0].rowEL.collectGroup !== linkItem[1].rowEL.collectGroup) { // 起点终点不在同个收藏栏 211 if (linkItem[0].rowEL.collectGroup === '2') { 212 linkItem[0].rowEL.translateY = Number(this.groupTitle1?.clientHeight) + Number(this.collectEl1?.clientHeight) + 27; 213 } else if (linkItem[1].rowEL.collectGroup === '2') { 214 linkItem[1].rowEL.translateY = Number(this.groupTitle1?.clientHeight) + Number(this.collectEl1?.clientHeight) + 27; 215 } 216 } 217 }); 218 } 219 220 removeAllCollectRow(): void { 221 Array.from(this.collectRowList1).forEach(row => { 222 row.collectEL?.click(); 223 }); 224 Array.from(this.collectRowList2).forEach(row => { 225 row.collectEL?.click(); 226 }); 227 } 228 229 private resizeHeight(): void { 230 this.maxHeight = 0; 231 // @ts-ignore 232 this.collectEl1!.childNodes.forEach((item) => (this.maxHeight += (item as unknown).clientHeight)); 233 // @ts-ignore 234 this.collectEl2!.childNodes.forEach((item) => (this.maxHeight += (item as unknown).clientHeight)); 235 if (this.groupTitle1) { 236 this.maxHeight += this.groupTitle1.clientHeight; 237 } 238 if (this.groupTitle2) { 239 this.maxHeight += this.groupTitle2.clientHeight; 240 } 241 242 this.maxHeight = Math.min(this.getMaxLimitHeight(), this.maxHeight); 243 if (this.manualHeight > 0) { 244 this.style.height = `${Math.min(this.maxHeight, this.manualHeight)}px`; 245 } else { 246 this.style.height = `${this.maxHeight}px`; 247 } 248 } 249 250 private getMaxLimitHeight(): number { 251 return (this.parentElement!.clientHeight - topHeight) * maxScale; 252 } 253 254 // @ts-ignore 255 getCollectRows(filter?: (row: TraceRow<unknown>) => boolean): Array<TraceRow<unknown>> | [] { 256 if (filter) { 257 return [...this.collectRowList1.filter(filter), ...this.collectRowList2.filter(filter)]; 258 } else { 259 return this.getAllCollectRows(); 260 } 261 } 262 263 getRowScrollTop(): number { 264 return this.rootEl?.scrollTop || 0; 265 } 266 267 // @ts-ignore 268 expandSearchRowGroup(row: TraceRow<unknown>): void { 269 this.updateGroupDisplay(); 270 if (row.collectGroup === SpChartList.COLLECT_G1) { 271 if (!this.collect1Expand) { 272 this.collect1Expand = true; 273 this.icon1!.style.transform = 'rotateZ(0deg)'; 274 this.collectEl1?.appendChild(this.fragmentGroup1); 275 } 276 } else { 277 if (!this.collect2Expand) { 278 this.collect2Expand = true; 279 this.icon2!.style.transform = 'rotateZ(0deg)'; 280 this.collectEl2?.appendChild(this.fragmentGroup2); 281 this.scrollTop = this.scrollHeight; 282 } 283 } 284 this.resizeHeight(); 285 } 286 287 // @ts-ignore 288 getCollectRow(filter: (row: TraceRow<unknown>) => boolean): TraceRow<unknown> | undefined { 289 return this.collectRowList1.find(filter) || this.collectRowList2.find(filter); 290 } 291 292 // @ts-ignore 293 getAllCollectRows(): Array<TraceRow<unknown>> { 294 return [...this.collectRowList1, ...this.collectRowList2]; 295 } 296 297 getCollectRowsInfo(group: string): unknown { 298 return (group === SpChartList.COLLECT_G1 ? this.collectRowList1 : this.collectRowList2).map((row) => { 299 let rowJson = { 300 type: row.rowType, 301 name: row.name, 302 id: row.rowId, 303 parents: [], 304 }; 305 this.getRowParent(rowJson, row); 306 rowJson.parents.reverse(); 307 return rowJson; 308 }); 309 } 310 311 // @ts-ignore 312 getRowParent(obj: unknown, row: TraceRow<unknown>): void { 313 if (row.parentRowEl) { 314 // @ts-ignore 315 if (obj.parents) { 316 let parent: unknown = { 317 type: row.parentRowEl.rowType, 318 name: row.parentRowEl.name, 319 id: row.parentRowEl.rowId, 320 }; 321 // @ts-ignore 322 (obj.parents as Array<unknown>).push(parent); 323 } else { 324 // @ts-ignore 325 obj.parents = [parent]; 326 } 327 this.getRowParent(obj, row.parentRowEl); 328 } 329 } 330 331 // @ts-ignore 332 getAllSelectCollectRows(): Array<TraceRow<unknown>> { 333 // @ts-ignore 334 const rows: Array<TraceRow<unknown>> = []; 335 for (const row of this.collectRowList1) { 336 if (row.checkType === '2') { 337 rows.push(row); 338 } 339 } 340 for (const row of this.collectRowList2) { 341 if (row.checkType === '2') { 342 rows.push(row); 343 } 344 } 345 return rows; 346 } 347 348 insertRowBefore(node: Node, child: Node): void { 349 // @ts-ignore 350 if (child === null || (child as TraceRow<unknown>).collectGroup === (node as TraceRow<unknown>).collectGroup) { 351 // @ts-ignore 352 if ((node as TraceRow<unknown>).collectGroup === SpChartList.COLLECT_G1) { 353 this.collectEl1!.insertBefore(node, child); 354 // @ts-ignore 355 this.collectRowList1 = Array.from(this.collectEl1!.children) as TraceRow<unknown>[]; 356 } else { 357 this.collectEl2!.insertBefore(node, child); 358 // @ts-ignore 359 this.collectRowList2 = Array.from(this.collectEl2!.children) as TraceRow<unknown>[]; 360 } 361 } 362 } 363 364 reset(): void { 365 this.maxHeight = 0; 366 this.clearRect(); 367 this.collect1Expand = true; 368 this.collect2Expand = true; 369 this.icon1!.style.transform = 'rotateZ(0deg)'; 370 this.icon2!.style.transform = 'rotateZ(0deg)'; 371 this.collectRowList1.forEach((row) => { 372 row.clearMemory(); 373 }); 374 this.collectRowList2.forEach((row) => { 375 row.clearMemory(); 376 }); 377 this.collectRowList1 = []; 378 this.collectRowList2 = []; 379 this.fragmentGroup1 = document.createDocumentFragment(); 380 this.fragmentGroup2 = document.createDocumentFragment(); 381 this.collectEl1!.innerHTML = ''; 382 this.collectEl2!.innerHTML = ''; 383 this.updateGroupDisplay(); 384 this.style.height = 'auto'; 385 } 386 387 context(): CanvasRenderingContext2D | undefined | null { 388 return this.canvasCtx; 389 } 390 391 getCanvas(): HTMLCanvasElement | null | undefined { 392 return this.canvas; 393 } 394 395 connectedCallback(): void { 396 super.connectedCallback(); 397 const vessel = this.parentNode as HTMLDivElement; 398 vessel.addEventListener('mousedown', this.onMouseDown); 399 vessel.addEventListener('mouseup', this.onMouseUp); 400 vessel.addEventListener('mousemove', this.onMouseMove); 401 this.addEventListener('scroll', this.onScroll, { passive: true }); 402 } 403 404 disconnectedCallback(): void { 405 super.disconnectedCallback(); 406 const vessel = this.parentNode as HTMLDivElement; 407 vessel.removeEventListener('mousedown', this.onMouseDown); 408 vessel.removeEventListener('mouseup', this.onMouseUp); 409 vessel.removeEventListener('mousemove', this.onMouseMove); 410 this.removeEventListener('scroll', this.onScroll); 411 } 412 413 onScroll = (ev: Event): void => { 414 this.canvas!.style.transform = `translateY(${this.scrollTop}px)`; 415 if (this.scrollTimer) { 416 // @ts-ignore 417 clearTimeout(this.scrollTimer); 418 } 419 this.scrollTimer = setTimeout(() => { 420 TraceRow.range!.refresh = true; 421 window.publish(window.SmartEvent.UI.RefreshCanvas, {}); 422 }, 100); 423 window.publish(window.SmartEvent.UI.RefreshCanvas, {}); 424 }; 425 426 onMouseDown = (ev: MouseEvent): void => { 427 this.isPress = true; 428 this.startPageY = ev.pageY; 429 this.startClientHeight = this.clientHeight; 430 if (this.containPoint(ev)) { 431 if ( 432 this.getBoundingClientRect().bottom > ev.pageY - mouseMoveRange && 433 this.getBoundingClientRect().bottom < ev.pageY + mouseMoveRange 434 ) { 435 this.style.cursor = 'row-resize'; 436 this.canResize = true; 437 } else { 438 this.style.cursor = 'default'; 439 this.canResize = false; 440 } 441 // @ts-ignore 442 (window as unknown).collectResize = this.canResize; 443 } 444 }; 445 446 onMouseMove = (ev: MouseEvent): void => { 447 if (this.containPoint(ev)) { 448 let inResizeArea = 449 this.getBoundingClientRect().bottom > ev.pageY - mouseMoveRange && 450 this.getBoundingClientRect().bottom < ev.pageY + mouseMoveRange; 451 if ((this.isPress && this.canResize) || inResizeArea) { 452 this.style.cursor = 'row-resize'; 453 } else { 454 this.style.cursor = 'default'; 455 } 456 } 457 //防止点击触发move时间 458 if (Math.abs(ev.pageY - this.startPageY) < 2) { 459 return; 460 } 461 if (this.canResize && this.isPress) { 462 // @ts-ignore 463 (window as unknown).collectResize = true; 464 // 拖动超过所有泳道最大高度 或小于一个泳道的高度,不支持拖动 465 let newHeight = this.startClientHeight + ev.pageY - this.startPageY; 466 if (newHeight > this.maxHeight) { 467 newHeight = this.maxHeight; 468 } 469 if (newHeight > this.getMaxLimitHeight()) { 470 newHeight = this.getMaxLimitHeight(); 471 } 472 if (newHeight < minHeight) { 473 newHeight = minHeight; 474 } 475 this!.style.height = `${newHeight}px`; 476 this.manualHeight = newHeight; 477 } else { 478 // @ts-ignore 479 (window as unknown).collectResize = false; 480 } 481 }; 482 483 onMouseUp = (ev: MouseEvent): void => { 484 this.isPress = false; 485 this.canResize = false; 486 this.style.cursor = 'default'; 487 // @ts-ignore 488 (window as unknown).collectResize = false; 489 if (this.style.display === 'flex') { 490 this.refreshFavoriteCanvas(); 491 } 492 }; 493 494 // @ts-ignore 495 insertRow(row: TraceRow<unknown>, group: string, updateGroup: boolean): void { 496 this.style.display = 'flex'; 497 let collectGroup = !updateGroup && row.collectGroup ? row.collectGroup : group; 498 if (row.collectGroup !== SpChartList.COLLECT_G1 && row.collectGroup !== SpChartList.COLLECT_G2) { 499 row.collectGroup = group; 500 } 501 if (updateGroup) { 502 row.collectGroup = group; 503 } 504 if (collectGroup === SpChartList.COLLECT_G1) { 505 if (!this.collect1Expand) { 506 this.collect1Expand = true; 507 this.icon1!.style.transform = 'rotateZ(0deg)'; 508 } 509 if (this.collectRowList1.indexOf(row) === -1) { 510 this.collectRowList1.push(row); 511 } 512 if (!this.fragmentGroup1.contains(row)) { 513 this.fragmentGroup1.appendChild(row); 514 } 515 this.collectEl1?.appendChild(this.fragmentGroup1); 516 this.scrollTo({ top: this.collectEl1?.clientHeight }); 517 } else { 518 if (!this.collect2Expand) { 519 this.collect2Expand = true; 520 this.icon2!.style.transform = 'rotateZ(0deg)'; 521 } 522 if (this.collectRowList2.indexOf(row) === -1) { 523 this.collectRowList2.push(row); 524 } 525 if (!this.fragmentGroup2.contains(row)) { 526 this.fragmentGroup2.appendChild(row); 527 } 528 this.collectEl2!.appendChild(this.fragmentGroup2); 529 this.scrollTo({ top: this.scrollHeight }); 530 } 531 this.updateGroupDisplay(); 532 this.resizeHeight(); 533 this.refreshFavoriteCanvas(); 534 row.currentContext = this.canvasCtx; 535 } 536 537 // @ts-ignore 538 deleteRow(row: TraceRow<unknown>, clearCollectGroup: boolean): void { 539 if (row.collectGroup === SpChartList.COLLECT_G1) { 540 this.collectRowList1.splice(this.collectRowList1.indexOf(row), 1); 541 if (!this.fragmentGroup1.contains(row)) { 542 this.fragmentGroup1.appendChild(row); 543 } 544 this.fragmentGroup1.removeChild(row); 545 } else { 546 this.collectRowList2.splice(this.collectRowList2.indexOf(row), 1); 547 if (!this.fragmentGroup2.contains(row)) { 548 this.fragmentGroup2.appendChild(row); 549 } 550 this.fragmentGroup2.removeChild(row); 551 } 552 if (clearCollectGroup) { 553 row.collectGroup = undefined; 554 } 555 this.updateGroupDisplay(); 556 this.resizeHeight(); 557 this.scrollTop = 0; 558 this.refreshFavoriteCanvas(); 559 row.currentContext = undefined; 560 if (this.collectRowList1.length === 0 && this.collectRowList2.length === 0) { 561 this.style.height = 'auto'; 562 this.style.display = 'none'; 563 this.manualHeight = 0; 564 } 565 } 566 567 hideCollectArea(): void { 568 if (this.collect1Expand) { 569 this.collectRowList1.forEach((row) => this.fragmentGroup1.appendChild(row)); 570 } 571 if (this.collect2Expand) { 572 this.collectRowList2.forEach((row) => this.fragmentGroup2.appendChild(row)); 573 } 574 this.groupTitle1!.style.display = 'none'; 575 this.groupTitle2!.style.display = 'none'; 576 this.resizeHeight(); 577 } 578 579 showCollectArea(): void { 580 if (this.collect1Expand) { 581 this.collectEl1?.appendChild(this.fragmentGroup1); 582 } 583 if (this.collect2Expand) { 584 this.collectEl2?.appendChild(this.fragmentGroup2); 585 } 586 this.updateGroupDisplay(); 587 this.resizeHeight(); 588 } 589 590 updateGroupDisplay(): void { 591 this.groupTitle1!.style.display = this.collectRowList1.length === 0 ? 'none' : 'flex'; 592 this.groupTitle2!.style.display = this.collectRowList2.length === 0 ? 'none' : 'flex'; 593 } 594 595 hasCollectRow(): boolean { 596 return this.collectRowList2.length > 0 || this.collectRowList1.length > 0; 597 } 598 599 clearRect(): void { 600 this.canvasCtx?.clearRect(0, 0, this.canvas?.clientWidth ?? 0, this.canvas?.clientHeight ?? 0); 601 } 602 603 drawLines(xs: number[] | undefined, color: string): void { 604 drawLines(this.canvasCtx!, xs ?? [], this.clientHeight, color); 605 } 606 607 drawFlagLineSegment( 608 hoverFlag: Flag | undefined | null, 609 selectFlag: Flag | undefined | null, 610 tse: TimerShaftElement 611 ): void { 612 drawFlagLineSegment( 613 this.canvasCtx, 614 hoverFlag, 615 selectFlag, 616 new Rect(0, 0, TraceRow.FRAME_WIDTH, this.canvas?.clientHeight!), 617 tse 618 ); 619 } 620 621 drawWakeUp(): void { 622 drawWakeUp( 623 this.canvasCtx, 624 CpuStruct.wakeupBean, 625 TraceRow.range!.startNS, 626 TraceRow.range!.endNS, 627 TraceRow.range!.totalNS, 628 new Rect(0, 0, TraceRow.FRAME_WIDTH, this.canvas?.clientHeight!) 629 ); 630 } 631 632 drawWakeUpList(bean: WakeupBean): void { 633 drawWakeUpList(this.canvasCtx, bean, TraceRow.range!.startNS, TraceRow.range!.endNS, TraceRow.range!.totalNS, { 634 x: 0, 635 y: 0, 636 width: TraceRow.FRAME_WIDTH, 637 height: this.canvas!.clientHeight!, 638 } as Rect); 639 } 640 641 drawLogsLineSegment(bean: Flag | null | undefined, timeShaft: TimerShaftElement): void { 642 drawLogsLineSegment( 643 this.canvasCtx, 644 bean, 645 { 646 x: 0, 647 y: 0, 648 width: TraceRow.FRAME_WIDTH, 649 height: this.canvas!.clientHeight, 650 }, 651 timeShaft 652 ); 653 } 654 655 drawLinkLines(nodes: PairPoint[][], tse: TimerShaftElement, isFavorite: boolean, favoriteHeight: number): void { 656 drawLinkLines(this.canvasCtx!, nodes, tse, isFavorite, favoriteHeight); 657 } 658 659 refreshFavoriteCanvas(): void { 660 this.canvas!.style.width = `${this.clientWidth - 248}px`; 661 this.canvas!.style.left = `248px`; 662 this.canvas!.width = this.canvas?.clientWidth! * dpr(); 663 this.canvas!.height = this.clientHeight * dpr(); 664 this.canvas!.getContext('2d')!.scale(dpr(), dpr()); 665 window.publish(window.SmartEvent.UI.RefreshCanvas, {}); 666 } 667 668 private getHtmlCss(): string { 669 return `<style> 670 :host{ 671 display: none; 672 width: 100%; 673 height: auto; 674 overflow-anchor: none; 675 z-index: 3; 676 box-shadow: 0 10px 10px #00000044; 677 position: relative; 678 overflow: auto; 679 overflow-x: hidden; 680 scroll-behavior: smooth; 681 } 682 .root{ 683 width: 100%; 684 box-sizing: border-box; 685 } 686 .panel-canvas{ 687 position: absolute; 688 top: 0; 689 right: 0; 690 bottom: 0; 691 box-sizing: border-box; 692 } 693 .icon:hover { 694 color:#ecb93f; 695 } 696 .icon { 697 margin-right: 10px; 698 cursor: pointer; 699 } 700 </style>`; 701 } 702 703 initHtml(): string { 704 return ` 705 ${this.getHtmlCss()} 706<canvas id="canvas-panel" class="panel-canvas" ondragstart="return false"></canvas> 707<div class="root"> 708 <div id="group-1-title" style="background-color: #efefef;padding: 10px;align-items: center"> 709 <lit-icon id="group_1_expand" class="icon" name="caret-down" size="19"></lit-icon> 710 <span style="width: 184px;font-size: 10px;color: #898989">G1</span> 711 <lit-icon id="group_1_collect" name="star-fill" style="color: #5291FF;cursor: pointer" size="19"></lit-icon> 712 </div> 713 <div id="collect-group-1"></div> 714 <div id="group-2-title" style="background-color: #efefef;padding: 10px;align-items: center"> 715 <lit-icon id="group_2_expand" class="icon" name="caret-down" size="19"></lit-icon> 716 <span style="width: 184px;font-size: 10px;color: #898989">G2</span> 717 <lit-icon id="group_2_collect" name="star-fill" style="color: #f56940;cursor: pointer" size="19"></lit-icon> 718 </div> 719 <div id="collect-group-2"></div> 720</div> 721`; 722 } 723} 724