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