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 { TraceRow } from '../trace/base/TraceRow'; 17import { renders } from '../../database/ui-worker/ProcedureWorker'; 18import { JankRender, JankStruct } from '../../database/ui-worker/ProcedureWorkerJank'; 19import { SpSystemTrace } from '../SpSystemTrace'; 20import { JanksStruct } from '../../bean/JanksStruct'; 21import { ns2xByTimeShaft, type PairPoint } from '../../database/ui-worker/ProcedureWorkerCommon'; 22import { FrameDynamicRender, FrameDynamicStruct } from '../../database/ui-worker/ProcedureWorkerFrameDynamic'; 23import { FrameAnimationRender, FrameAnimationStruct } from '../../database/ui-worker/ProcedureWorkerFrameAnimation'; 24import { type BaseStruct } from '../../bean/BaseStruct'; 25import { FrameSpacingRender, FrameSpacingStruct } from '../../database/ui-worker/ProcedureWorkerFrameSpacing'; 26import { FlagsConfig, type Params } from '../SpFlags'; 27import { type AnimationRanges, type DeviceStruct } from '../../bean/FrameComponentBean'; 28import { type EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 29import { TreeItemData } from '../../../base-ui/tree/LitTree'; 30import { QueryEnum } from '../../database/data-trafic/utils/QueryEnum'; 31import { 32 frameAnimationSender, 33 frameDynamicSender, 34 frameSpacingSender, 35} from '../../database/data-trafic/FrameDynamicEffectSender'; 36import { frameJanksSender } from '../../database/data-trafic/FrameJanksSender'; 37import { 38 queryAnimationIdAndNameData, 39 queryAnimationTimeRangeData, 40 queryDynamicIdAndNameData, 41 queryFrameApp, 42 queryFrameTimeData, 43 queryPhysicalData, 44} from '../../database/sql/SqlLite.sql'; 45import { queryAllProcessNames } from '../../database/sql/ProcessThread.sql'; 46 47export class SpFrameTimeChart { 48 private trace: SpSystemTrace; 49 private flagConfig: Params | undefined; 50 private pidToProcessNameMap: Map<number, string> = new Map(); 51 private idToProcessNameMap: Map<number, string> = new Map(); 52 53 constructor(trace: SpSystemTrace) { 54 this.trace = trace; 55 } 56 57 async init(): Promise<void> { 58 let frameTimeData = await queryFrameTimeData(); 59 this.pidToProcessNameMap.clear(); 60 this.idToProcessNameMap.clear(); 61 if (frameTimeData.length > 0) { 62 let processNamesArray = await queryAllProcessNames(); 63 processNamesArray.forEach((it) => { 64 //@ts-ignore 65 this.pidToProcessNameMap.set(it.pid, it.name); //@ts-ignore 66 this.idToProcessNameMap.set(it.id, it.name); 67 }); 68 let frameTimeLineRow: TraceRow<JanksStruct> = await this.initFrameTimeLine(); 69 await this.initExpectedChart(frameTimeLineRow); 70 await this.initActualChart(frameTimeLineRow); 71 } 72 } 73 74 async initFrameTimeLine(): Promise<TraceRow<JanksStruct>> { 75 let frameTimeLineRow: TraceRow<JanksStruct> = TraceRow.skeleton<JanksStruct>(); 76 frameTimeLineRow.rowId = 'frameTime'; 77 frameTimeLineRow.rowType = TraceRow.ROW_TYPE_JANK; 78 frameTimeLineRow.rowParentId = ''; 79 frameTimeLineRow.style.width = '100%'; 80 frameTimeLineRow.style.height = '40px'; 81 frameTimeLineRow.folder = true; 82 frameTimeLineRow.name = 'FrameTimeline'; 83 frameTimeLineRow.setAttribute('children', ''); 84 frameTimeLineRow.supplier = (): Promise<JanksStruct[]> => 85 new Promise((resolve) => { 86 resolve([]); 87 }); 88 frameTimeLineRow.addTemplateTypes('AppStartup'); 89 frameTimeLineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 90 frameTimeLineRow.selectChangeHandler = this.trace.selectChangeHandler; 91 frameTimeLineRow.onThreadHandler = (useCache: boolean): void => { 92 let context: CanvasRenderingContext2D; 93 if (frameTimeLineRow.currentContext) { 94 context = frameTimeLineRow.currentContext; 95 } else { 96 context = frameTimeLineRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 97 } 98 frameTimeLineRow!.canvasSave(context); 99 (renders.jank as JankRender).renderMainThread( 100 { 101 context: context, 102 useCache: useCache, 103 type: 'expected_frame_timeline_slice', 104 }, 105 frameTimeLineRow! 106 ); 107 frameTimeLineRow!.canvasRestore(context, this.trace); 108 }; 109 this.trace.rowsEL?.appendChild(frameTimeLineRow); 110 return frameTimeLineRow; 111 } 112 113 private expectedChartSupplierFrame(expectedTimeLineRow: TraceRow<JanksStruct>): void { 114 expectedTimeLineRow.supplierFrame = async (): Promise<JanksStruct[]> => { 115 const res = await frameJanksSender(QueryEnum.FrameExpectedData, expectedTimeLineRow); 116 let maxDepth: number = 1; 117 let unitHeight: number = 20; 118 res.forEach((item) => { 119 if (item.depth! >= maxDepth) { 120 maxDepth = item.depth! + 1; 121 } 122 item.frameType = 'frameTime'; 123 item.cmdline = this.pidToProcessNameMap.get(item.pid!); 124 item.rs_name = this.idToProcessNameMap.get(Number(item.rs_name)!); 125 }); 126 if (expectedTimeLineRow && !expectedTimeLineRow.isComplete && res.length > 0) { 127 let maxHeight: number = maxDepth * unitHeight; 128 expectedTimeLineRow.style.height = `${maxHeight}px`; 129 expectedTimeLineRow.setAttribute('height', `${maxHeight}`); 130 } 131 return res; 132 }; 133 } 134 135 async initExpectedChart(frameTimeLineRow: TraceRow<JanksStruct>): Promise<void> { 136 let expectedTimeLineRow = TraceRow.skeleton<JanksStruct>(); 137 expectedTimeLineRow.rowId = 'expected frameTime'; 138 expectedTimeLineRow.rowType = TraceRow.ROW_TYPE_JANK; 139 expectedTimeLineRow.rowHidden = !frameTimeLineRow.expansion; 140 expectedTimeLineRow.rowParentId = 'frameTime'; 141 expectedTimeLineRow.style.width = '100%'; 142 expectedTimeLineRow.name = 'Expected Timeline'; 143 expectedTimeLineRow.addTemplateTypes('FrameTimeline'); 144 expectedTimeLineRow.setAttribute('children', ''); 145 this.expectedChartSupplierFrame(expectedTimeLineRow); 146 expectedTimeLineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 147 expectedTimeLineRow.selectChangeHandler = this.trace.selectChangeHandler; 148 expectedTimeLineRow.onThreadHandler = (useCache: boolean): void => { 149 let context: CanvasRenderingContext2D; 150 if (expectedTimeLineRow.currentContext) { 151 context = expectedTimeLineRow.currentContext; 152 } else { 153 context = expectedTimeLineRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 154 } 155 expectedTimeLineRow!.canvasSave(context); 156 (renders.jank as JankRender).renderMainThread( 157 { 158 context: context, 159 useCache: useCache, 160 type: 'expected_frame_timeline_slice', 161 }, 162 expectedTimeLineRow! 163 ); 164 expectedTimeLineRow!.canvasRestore(context, this.trace); 165 }; 166 frameTimeLineRow.addChildTraceRow(expectedTimeLineRow); 167 } 168 169 private actualChartSupplierFrame(row: TraceRow<JanksStruct>): void { 170 row.supplierFrame = async (): Promise<JanksStruct[]> => { 171 const res = await frameJanksSender(QueryEnum.FrameActualData, row); 172 let maxDepth: number = 1; 173 let unitHeight: number = 20; 174 res.forEach((item) => { 175 if (item.depth! >= maxDepth) { 176 maxDepth = item.depth! + 1; 177 } 178 item.frameType = 'frameTime'; 179 item.cmdline = this.pidToProcessNameMap.get(item.pid!); 180 item.rs_name = this.idToProcessNameMap.get(Number(item.rs_name)!); 181 item.type = '0'; 182 }); 183 if (row && !row.isComplete && res.length > 0) { 184 let maxHeight: number = maxDepth * unitHeight; 185 row.style.height = `${maxHeight}px`; 186 row.setAttribute('height', `${maxHeight}`); 187 } 188 return res; 189 }; 190 } 191 192 async initActualChart(frameTimeLineRow: TraceRow<JanksStruct>): Promise<void> { 193 let actualTimeLineRow = TraceRow.skeleton<JanksStruct>(); 194 actualTimeLineRow.rowId = 'actual frameTime'; 195 actualTimeLineRow.rowType = TraceRow.ROW_TYPE_JANK; 196 actualTimeLineRow.rowHidden = !frameTimeLineRow.expansion; 197 actualTimeLineRow.rowParentId = 'frameTime'; 198 actualTimeLineRow.style.width = '100%'; 199 actualTimeLineRow.name = 'Actual Timeline'; 200 actualTimeLineRow.addTemplateTypes('FrameTimeline'); 201 actualTimeLineRow.setAttribute('children', ''); 202 this.actualChartSupplierFrame(actualTimeLineRow); 203 actualTimeLineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 204 actualTimeLineRow.selectChangeHandler = this.trace.selectChangeHandler; 205 actualTimeLineRow.onThreadHandler = (useCache: boolean): void => { 206 let context: CanvasRenderingContext2D; 207 if (actualTimeLineRow.currentContext) { 208 context = actualTimeLineRow.currentContext; 209 } else { 210 context = actualTimeLineRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 211 } 212 actualTimeLineRow!.canvasSave(context); 213 (renders.jank as JankRender).renderMainThread( 214 { 215 context: context, 216 useCache: useCache, 217 type: 'expected_frame_timeline_slice', 218 }, 219 actualTimeLineRow! 220 ); 221 actualTimeLineRow!.canvasRestore(context, this.trace); 222 }; 223 frameTimeLineRow.addChildTraceRow(actualTimeLineRow); 224 let offsetYTimeOut: number = 0; 225 frameTimeLineRow.addEventListener('expansion-change', (customEventInit: CustomEventInit) => { 226 JankStruct.delJankLineFlag = false; 227 if (offsetYTimeOut) { 228 clearTimeout(offsetYTimeOut); 229 } 230 if (customEventInit.detail?.expansion) { 231 offsetYTimeOut = this.frameExpandTimeOut(customEventInit, actualTimeLineRow); 232 } else { 233 offsetYTimeOut = this.frameNoExpandTimeOut(customEventInit, frameTimeLineRow); 234 } 235 }); 236 } 237 238 async initAnimatedScenesChart( 239 processRow: TraceRow<BaseStruct>, 240 process: { pid: number | null; processName: string | null }, 241 firstRow: TraceRow<BaseStruct>, 242 secondRow: TraceRow<BaseStruct> 243 ): Promise<void> { 244 this.flagConfig = FlagsConfig.getFlagsConfig('AnimationAnalysis'); 245 let appNameMap: Map<number, string> = new Map(); 246 if (this.flagConfig?.AnimationAnalysis === 'Enabled') { 247 if (process.processName?.startsWith('render_service')) { 248 let targetRowList = processRow.childrenList.filter( 249 (childRow) => childRow.rowType === 'thread' && childRow.name.startsWith('render_service') 250 ); 251 let nameArr: { name: string }[] = await queryFrameApp(); 252 if (nameArr && nameArr.length > 0) { 253 let currentName = nameArr[0].name; 254 let frameChart = await this.initFrameChart(processRow, nameArr); 255 if (firstRow !== null) { 256 processRow.addChildTraceRowBefore(frameChart, firstRow); 257 } else if (secondRow !== null) { 258 processRow.addChildTraceRowBefore(frameChart, secondRow); 259 } else { 260 // @ts-ignore 261 processRow.addChildTraceRowBefore(frameChart, targetRowList[0]); 262 } 263 let appNameList = await queryDynamicIdAndNameData(); 264 appNameList.forEach((item) => { 265 appNameMap.set(item.id, item.appName); 266 }); 267 let animationRanges = await this.initAnimationChart(processRow); 268 await this.initDynamicCurveChart(appNameMap, frameChart, currentName, animationRanges); 269 await this.initFrameSpacing(appNameMap, frameChart, currentName, animationRanges); 270 } 271 } 272 } 273 } 274 275 private async initFrameChart( 276 processRow: TraceRow<BaseStruct>, 277 nameArr: { name: string }[] 278 ): Promise<TraceRow<BaseStruct>> { 279 let frameChart: TraceRow<BaseStruct> = TraceRow.skeleton<BaseStruct>(); 280 let labelName = frameChart.shadowRoot?.querySelector('.name') as HTMLLabelElement; 281 labelName.style.marginRight = '77px'; 282 this.addSystemConfigButton(frameChart, nameArr, 'model-name', true); 283 frameChart.rowId = 'frame'; 284 frameChart.rowType = TraceRow.ROW_TYPE_FRAME; 285 frameChart.rowHidden = !processRow.expansion; 286 frameChart.rowParentId = processRow.rowId; 287 frameChart.style.width = '100%'; 288 frameChart.style.height = '40px'; 289 frameChart.folder = true; 290 frameChart.name = nameArr[0].name; 291 frameChart.setAttribute('children', ''); 292 frameChart.supplier = (): Promise<BaseStruct[]> => 293 new Promise((resolve) => { 294 resolve([]); 295 }); 296 frameChart.favoriteChangeHandler = this.trace.favoriteChangeHandler; 297 frameChart.selectChangeHandler = this.trace.selectChangeHandler; 298 frameChart.onThreadHandler = (useCache: boolean): void => { 299 let context: CanvasRenderingContext2D = frameChart!.collect 300 ? this.trace.canvasFavoritePanelCtx! 301 : this.trace.canvasPanelCtx!; 302 frameChart!.canvasSave(context); 303 (renders.empty as EmptyRender).renderMainThread( 304 { 305 context: context, 306 useCache: useCache, 307 type: 'frame', 308 }, 309 frameChart! 310 ); 311 frameChart!.canvasRestore(context, this.trace); 312 }; 313 this.trace.rowsEL?.appendChild(frameChart); 314 return frameChart; 315 } 316 317 private animationChartSupplierFrame( 318 row: TraceRow<FrameAnimationStruct>, 319 animationIdNameMap: Map<number, string>, 320 animationIdInfoMap: Map<number, string> 321 ): void { 322 const unitIndex: number = 1; 323 const unitHeight: number = 20; 324 row.supplierFrame = async (): Promise<FrameAnimationStruct[]> => { 325 const result = await frameAnimationSender(row); 326 let maxDepth = 0; 327 result.forEach((item) => { 328 if (`${item.status}` === '1') { 329 item.status = 'Completion delay'; 330 } else if (`${item.status}` === '0') { 331 item.status = 'Response delay'; 332 } 333 if (item.depth > maxDepth) { 334 maxDepth = item.depth; 335 } 336 if (animationIdNameMap.has(item.animationId!)) { 337 item.name = animationIdNameMap.get(item.animationId!); 338 item.frameInfo = item.status === 'Completion delay' ? animationIdInfoMap.get(item.animationId!) : '0'; 339 } 340 }); 341 let maxHeight: number = (maxDepth + unitIndex) * unitHeight; 342 row.style.height = `${maxHeight}px`; 343 row.setAttribute('height', `${maxHeight}`); 344 return result; 345 }; 346 } 347 private animationThreadHandler(row: TraceRow<FrameAnimationStruct>): void { 348 row.onThreadHandler = (useCache): void => { 349 let context: CanvasRenderingContext2D = row!.collect 350 ? this.trace.canvasFavoritePanelCtx! 351 : this.trace.canvasPanelCtx!; 352 row!.canvasSave(context); 353 (renders.frameAnimation as FrameAnimationRender).renderMainThread( 354 { 355 context: context, 356 useCache: useCache, 357 type: 'frameAnimation', 358 }, 359 row! 360 ); 361 row!.canvasRestore(context, this.trace); 362 }; 363 } 364 365 async initAnimationChart(processRow: TraceRow<BaseStruct>): Promise<AnimationRanges[]> { 366 let animationRanges: AnimationRanges[] = []; 367 let frameAnimationRow = TraceRow.skeleton<FrameAnimationStruct>(); 368 369 frameAnimationRow.rowId = 'Animation'; 370 frameAnimationRow.rowType = TraceRow.ROW_TYPE_FRAME_ANIMATION; 371 frameAnimationRow.rowHidden = !processRow.expansion; 372 frameAnimationRow.rowParentId = processRow.rowId; 373 frameAnimationRow.style.width = '100%'; 374 frameAnimationRow.name = 'Animation'; 375 frameAnimationRow.addTemplateTypes('AnimationEffect'); 376 frameAnimationRow.setAttribute('children', ''); 377 let timeRangeData = await queryAnimationTimeRangeData(); 378 timeRangeData.forEach((rangeTime) => { 379 if (rangeTime.status === 'Completion delay') { 380 animationRanges.push({ 381 start: rangeTime.startTs, 382 end: rangeTime.endTs, 383 }); 384 } 385 }); 386 let animationIdNameMap: Map<number, string> = new Map<number, string>(); 387 let animationIdInfoMap: Map<number, string> = new Map<number, string>(); 388 let animationNameData = await queryAnimationIdAndNameData(); 389 animationNameData.forEach((item) => { 390 animationIdNameMap.set(item.id, item.name); 391 animationIdInfoMap.set(item.id, item.info); 392 }); 393 this.animationChartSupplierFrame(frameAnimationRow, animationIdNameMap, animationIdInfoMap); 394 frameAnimationRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 395 frameAnimationRow.selectChangeHandler = this.trace.selectChangeHandler; 396 this.animationThreadHandler(frameAnimationRow); 397 processRow.addChildTraceRowSpecifyLocation(frameAnimationRow, 0); 398 return animationRanges; 399 } 400 401 private dynamicCurveChartThreadHandler( 402 dynamicCurveRow: TraceRow<FrameDynamicStruct>, 403 animationRanges: AnimationRanges[] 404 ): void { 405 dynamicCurveRow.onThreadHandler = (useCache: boolean): void => { 406 let context: CanvasRenderingContext2D = dynamicCurveRow!.collect 407 ? this.trace.canvasFavoritePanelCtx! 408 : this.trace.canvasPanelCtx!; 409 dynamicCurveRow!.canvasSave(context); 410 (renders.frameDynamicCurve as FrameDynamicRender).renderMainThread( 411 { 412 context: context, 413 useCache: useCache, 414 type: 'dynamicEffectCurve', 415 animationRanges: animationRanges, 416 }, 417 dynamicCurveRow! 418 ); 419 dynamicCurveRow!.canvasRestore(context, this.trace); 420 }; 421 } 422 423 async initDynamicCurveChart( 424 appNameMap: Map<number, string>, 425 frameChart: TraceRow<BaseStruct>, 426 name: string, 427 animationRanges: AnimationRanges[] 428 ): Promise<void> { 429 let systemConfigList: { 430 name: string; 431 }[] = [{ name: 'x' }, { name: 'y' }, { name: 'width' }, { name: 'height' }, { name: 'alpha' }]; 432 let dynamicCurveRow: TraceRow<FrameDynamicStruct> = TraceRow.skeleton<FrameDynamicStruct>(); 433 this.addSystemConfigButton(dynamicCurveRow, systemConfigList, 'model-type'); 434 dynamicCurveRow.setAttribute('model-type', systemConfigList[0].name); 435 dynamicCurveRow.rowId = 'animation-Effect-Curve'; 436 dynamicCurveRow.rowType = TraceRow.ROW_TYPE_FRAME_DYNAMIC; 437 dynamicCurveRow.rowHidden = !frameChart.expansion; 438 dynamicCurveRow.rowParentId = frameChart.rowId; 439 dynamicCurveRow.style.width = '100%'; 440 dynamicCurveRow.style.height = '40px'; 441 dynamicCurveRow.style.height = '100px'; 442 let labelName = dynamicCurveRow.shadowRoot?.querySelector('.name') as HTMLLabelElement; 443 labelName.style.marginRight = '77px'; 444 dynamicCurveRow.name = 'Animation Effect Curve'; 445 dynamicCurveRow.addTemplateTypes('AnimationEffect'); 446 dynamicCurveRow.setAttribute('height', '100px'); 447 dynamicCurveRow.setAttribute('children', ''); 448 dynamicCurveRow.setAttribute('model-type', systemConfigList[0].name); 449 dynamicCurveRow.setAttribute('model-name', name); 450 dynamicCurveRow.supplierFrame = async (): Promise<FrameDynamicStruct[]> => { 451 const result = await frameDynamicSender(dynamicCurveRow); 452 result.forEach((dataItem) => { 453 if (appNameMap.has(dataItem.id!)) { 454 dataItem.appName = appNameMap.get(dataItem.id!); 455 } 456 }); 457 return result; 458 }; 459 dynamicCurveRow.selectChangeHandler = this.trace.selectChangeHandler; 460 this.dynamicCurveChartThreadHandler(dynamicCurveRow, animationRanges); 461 frameChart.addChildTraceRow(dynamicCurveRow); 462 } 463 464 private FrameSpacingThreadHandler( 465 frameSpacingRow: TraceRow<FrameSpacingStruct>, 466 animationRanges: AnimationRanges[], 467 rate: number 468 ): void { 469 frameSpacingRow.onThreadHandler = (useCache: boolean): void => { 470 let context = frameSpacingRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 471 frameSpacingRow!.canvasSave(context); 472 (renders.frameSpacing as FrameSpacingRender).renderMainThread( 473 { 474 context: context, 475 useCache: useCache, 476 type: 'frame_spacing_slice', 477 frameRate: rate, 478 animationRanges: animationRanges, 479 }, 480 frameSpacingRow! 481 ); 482 frameSpacingRow!.canvasRestore(context, this.trace); 483 }; 484 } 485 486 async initFrameSpacing( 487 appNameMap: Map<number, string>, 488 frameChart: TraceRow<BaseStruct>, 489 name: string, 490 animationRanges: AnimationRanges[] 491 ): Promise<void> { 492 let deviceStructArray = await queryPhysicalData(); 493 let deviceStruct: DeviceStruct = deviceStructArray[0]; 494 let frameSpacingRow = TraceRow.skeleton<FrameSpacingStruct>(); 495 frameSpacingRow.rowId = 'frame spacing'; 496 frameSpacingRow.rowType = TraceRow.ROW_TYPE_FRAME_SPACING; 497 frameSpacingRow.rowHidden = !frameChart.expansion; 498 frameSpacingRow.rowParentId = frameChart.rowId; 499 frameSpacingRow.style.width = '100%'; 500 frameSpacingRow.style.height = '140px'; 501 frameSpacingRow.name = 'Frame spacing'; 502 frameSpacingRow.addTemplateTypes('AnimationEffect'); 503 frameSpacingRow.setAttribute('height', '140'); 504 frameSpacingRow.setAttribute('children', ''); 505 frameSpacingRow.setAttribute('model-name', name); 506 let physicalConfigWidth = Number(this.flagConfig!.physicalWidth); 507 let physicalConfigHeight = Number(this.flagConfig!.physicalHeight); 508 let physicalWidth = physicalConfigWidth !== 0 ? physicalConfigWidth : deviceStruct.physicalWidth; 509 let physicalHeight = physicalConfigHeight !== 0 ? physicalConfigHeight : deviceStruct.physicalHeight; 510 frameSpacingRow.supplierFrame = async (): Promise<FrameSpacingStruct[]> => { 511 const result = await frameSpacingSender(physicalWidth, physicalHeight, frameSpacingRow); 512 result.forEach((dataItem) => { 513 if (appNameMap.has(dataItem.id!)) { 514 dataItem.nameId = appNameMap.get(dataItem.id!); 515 } 516 dataItem.physicalWidth = physicalWidth; 517 dataItem.physicalHeight = physicalHeight; 518 }); 519 return result; 520 }; 521 frameSpacingRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 522 frameSpacingRow.selectChangeHandler = this.trace.selectChangeHandler; 523 this.FrameSpacingThreadHandler(frameSpacingRow, animationRanges, deviceStruct.physicalFrameRate); 524 frameChart.addChildTraceRow(frameSpacingRow); 525 } 526 527 addSystemConfigButton( 528 systemTraceRow: TraceRow<BaseStruct>, 529 systemConfigList: { name: string }[], 530 attributeKey: string, 531 allowChangeName: boolean = false 532 ): void { 533 let componentList: Array<TreeItemData> = []; 534 for (let index = 0; index < systemConfigList.length; index++) { 535 let componentName = systemConfigList[index].name; 536 componentList.push({ 537 key: `${componentName}`, 538 title: `${componentName}`, 539 checked: index === 0, 540 }); 541 } 542 systemTraceRow.addRowSettingPop(); 543 systemTraceRow.rowSetting = 'enable'; 544 systemTraceRow.rowSettingPopoverDirection = 'bottomLeft'; 545 systemTraceRow.rowSettingList = componentList; 546 systemTraceRow.onRowSettingChangeHandler = (value: string[]): void => { 547 if (allowChangeName) { 548 systemTraceRow.name = value[0]; 549 } 550 systemTraceRow.setAttribute(attributeKey, `${value[0]}`); 551 systemTraceRow.childrenList.forEach((row): void => { 552 row.setAttribute(attributeKey, `${value[0]}`); 553 }); 554 this.trace.refreshCanvas(false); 555 }; 556 } 557 558 private frameNoExpandTimeOut(event: CustomEventInit<unknown>, frameTimeLineRow: TraceRow<JanksStruct>): number { 559 if (JankStruct!.selectJankStruct) { 560 JankStruct.selectJankStructList?.push(<JankStruct>JankStruct!.selectJankStruct); 561 } 562 let topPadding: number = 195; 563 let halfNumber: number = 2; 564 let offsetYTime: number = 300; 565 let refreshTime: number = 360; 566 let offsetYTimeOut: number = window.setTimeout(() => { 567 this.trace.linkNodes.forEach((linkNode: PairPoint[]) => { 568 if (linkNode[0].rowEL.collect) { 569 linkNode[0].rowEL.translateY = linkNode[0].rowEL.getBoundingClientRect().top - topPadding; 570 } else { 571 linkNode[0].rowEL.translateY = linkNode[0].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; 572 } 573 linkNode[0].y = linkNode[0].rowEL!.translateY! + linkNode[0].offsetY; 574 if (linkNode[1].rowEL.collect) { 575 linkNode[1].rowEL.translateY = linkNode[1].rowEL.getBoundingClientRect().top - topPadding; 576 } else { 577 linkNode[1].rowEL.translateY = linkNode[1].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; 578 } 579 linkNode[1].y = linkNode[1].rowEL!.translateY! + linkNode[1].offsetY; //@ts-ignore 580 if (linkNode[0].rowEL.rowParentId === event.detail?.rowId) { 581 if (!linkNode[0].rowEL.collect) { 582 linkNode[0].x = ns2xByTimeShaft(linkNode[0].ns, this.trace.timerShaftEL!); 583 linkNode[0].y = frameTimeLineRow!.translateY! + linkNode[0].offsetY / halfNumber; 584 linkNode[0].offsetY = linkNode[0].offsetY / halfNumber; //@ts-ignore 585 linkNode[0].rowEL = frameTimeLineRow; 586 } //@ts-ignore 587 } else if (linkNode[1].rowEL.rowParentId === event.detail?.rowId) { 588 if (!linkNode[1].rowEL.collect) { 589 linkNode[1].x = ns2xByTimeShaft(linkNode[1].ns, this.trace.timerShaftEL!); 590 linkNode[1].y = frameTimeLineRow!.translateY! + linkNode[1].offsetY / halfNumber; 591 linkNode[1].offsetY = linkNode[1].offsetY / halfNumber; //@ts-ignore 592 linkNode[1].rowEL = frameTimeLineRow!; 593 } 594 } 595 }); 596 }, offsetYTime); 597 let refreshTimeOut: number = window.setTimeout(() => { 598 this.trace.refreshCanvas(true); 599 clearTimeout(refreshTimeOut); 600 }, refreshTime); 601 return offsetYTimeOut; 602 } 603 604 private frameExpandTimeOut( 605 event: CustomEventInit<{ expansion: boolean; rowType: string; rowId: string; rowParentId: string }>, 606 actualTimeLineRow: TraceRow<JanksStruct> 607 ): number { 608 let topPadding: number = 195; 609 let halfNumber: number = 2; 610 let offsetYTime: number = 300; 611 let refreshTime: number = 360; 612 let offsetYTimeOut: number = window.setTimeout(() => { 613 this.trace.linkNodes.forEach((linkFrameNode: PairPoint[]) => { 614 JankStruct.selectJankStructList?.forEach((dat: JankStruct) => { 615 if (event.detail?.rowId === dat.pid) { 616 JankStruct.selectJankStruct = dat; 617 JankStruct.hoverJankStruct = dat; 618 } 619 }); 620 if (linkFrameNode[0].rowEL.collect) { 621 linkFrameNode[0].rowEL.translateY = linkFrameNode[0].rowEL.getBoundingClientRect().top - topPadding; 622 } else { 623 linkFrameNode[0].rowEL.translateY = linkFrameNode[0].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; 624 } 625 linkFrameNode[0].y = linkFrameNode[0].rowEL!.translateY! + linkFrameNode[0].offsetY; 626 if (linkFrameNode[1].rowEL.collect) { 627 linkFrameNode[1].rowEL.translateY = linkFrameNode[1].rowEL.getBoundingClientRect().top - topPadding; 628 } else { 629 linkFrameNode[1].rowEL.translateY = linkFrameNode[1].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; 630 } 631 linkFrameNode[1].y = linkFrameNode[1].rowEL!.translateY! + linkFrameNode[1].offsetY; 632 if (linkFrameNode[0].rowEL.rowId === event.detail?.rowId) { 633 linkFrameNode[0].x = ns2xByTimeShaft(linkFrameNode[0].ns, this.trace.timerShaftEL!); 634 linkFrameNode[0].y = actualTimeLineRow!.translateY! + linkFrameNode[0].offsetY * halfNumber; 635 linkFrameNode[0].offsetY = linkFrameNode[0].offsetY * halfNumber; 636 //@ts-ignore 637 linkFrameNode[0].rowEL = actualTimeLineRow; 638 } else if (linkFrameNode[1].rowEL.rowId === event.detail?.rowId) { 639 linkFrameNode[1].x = ns2xByTimeShaft(linkFrameNode[1].ns, this.trace.timerShaftEL!); 640 linkFrameNode[1].y = actualTimeLineRow!.translateY! + linkFrameNode[1].offsetY * halfNumber; 641 linkFrameNode[1].offsetY = linkFrameNode[1].offsetY * halfNumber; 642 //@ts-ignore 643 linkFrameNode[1].rowEL = actualTimeLineRow!; 644 } 645 }); 646 }, offsetYTime); 647 let refreshTimeOut: number = window.setTimeout(() => { 648 this.trace.refreshCanvas(true); 649 clearTimeout(refreshTimeOut); 650 }, refreshTime); 651 return offsetYTimeOut; 652 } 653} 654