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