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