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 '../../component/trace/base/TraceRow'; 17import { 18 BaseStruct, 19 computeUnitWidth, 20 drawLoadingFrame, 21 isSurroundingPoint, 22 ns2x, 23 Rect, 24 Render, 25} from './ProcedureWorkerCommon'; 26import { type AnimationRanges } from '../../bean/FrameComponentBean'; 27import { ColorUtils } from '../../component/trace/base/ColorUtils'; 28import {SpSystemTrace} from "../../component/SpSystemTrace"; 29 30export class FrameSpacingRender extends Render { 31 renderMainThread( 32 req: { 33 useCache: boolean; 34 context: CanvasRenderingContext2D; 35 type: string; 36 frameRate: number; 37 animationRanges: AnimationRanges[]; 38 }, 39 row: TraceRow<FrameSpacingStruct> 40 ): void { 41 let frameSpacingList = row.dataList; 42 let frameSpacingFilter = row.dataListCache; 43 this.frameSpacing( 44 frameSpacingList, 45 frameSpacingFilter, 46 TraceRow.range!.startNS, 47 TraceRow.range!.endNS, 48 TraceRow.range!.totalNS, 49 row, 50 req.animationRanges, 51 req.useCache || !TraceRow.range!.refresh 52 ); 53 drawLoadingFrame(req.context, row.dataListCache, row); 54 this.render(req, frameSpacingList, row); 55 } 56 57 private render( 58 req: { 59 useCache: boolean; 60 context: CanvasRenderingContext2D; 61 type: string; 62 frameRate: number; 63 animationRanges: AnimationRanges[]; 64 }, 65 frameSpacingFilter: Array<FrameSpacingStruct>, 66 row: TraceRow<FrameSpacingStruct> 67 ): void { 68 if (req.animationRanges.length > 0 && req.animationRanges[0] && frameSpacingFilter.length > 0) { 69 let minValue = 0; 70 let maxValue = 0; 71 let smallTickStandard = { 72 firstLine: 0, 73 secondLine: 0, 74 thirdLine: 0, 75 }; 76 if (req.frameRate) { 77 // @ts-ignore 78 smallTickStandard = smallTick[req.frameRate]; 79 [minValue, maxValue] = this.maxMinData( 80 smallTickStandard.firstLine, 81 smallTickStandard.thirdLine, 82 frameSpacingFilter 83 ); 84 } else { 85 minValue = Math.min.apply( 86 Math, 87 frameSpacingFilter.map((filterData) => { 88 return filterData.frameSpacingResult!; 89 }) 90 ); 91 maxValue = Math.max.apply( 92 Math, 93 frameSpacingFilter.map((filterData) => { 94 return filterData.frameSpacingResult!; 95 }) 96 ); 97 } 98 let selectUnitWidth: number = 0; 99 this.drawTraceRow(frameSpacingFilter, selectUnitWidth, req, row, minValue, maxValue, smallTickStandard); 100 let findStructList = frameSpacingFilter.filter( 101 (filter) => row.isHover && isSurroundingPoint(row.hoverX, filter.frame!, selectUnitWidth / multiple) 102 ); 103 this.setHoverStruct(findStructList, row); 104 } 105 } 106 private drawTraceRow( 107 frameSpacingFilter: Array<FrameSpacingStruct>, 108 selectUnitWidth: number, 109 req: any, 110 row: TraceRow<FrameSpacingStruct>, 111 minValue: number, 112 maxValue: number, 113 smallTickStandard: any 114 ) { 115 let preFrameSpacing: FrameSpacingStruct = frameSpacingFilter[0]; 116 let isDraw = false; 117 for (let index: number = 0; index < frameSpacingFilter.length; index++) { 118 let currentStruct = frameSpacingFilter[index]; 119 selectUnitWidth = computeUnitWidth( 120 preFrameSpacing.currentTs, 121 currentStruct.currentTs, 122 row.frame.width, 123 selectUnitWidth 124 ); 125 FrameSpacingStruct.refreshHoverStruct(preFrameSpacing, currentStruct, row, minValue, maxValue); 126 if (currentStruct.groupId === 0) { 127 if (currentStruct.currentTs > TraceRow.range!.startNS && currentStruct.currentTs < TraceRow.range!.endNS) { 128 isDraw = true; 129 this.drawPoint(req.context, currentStruct, row, minValue, maxValue); 130 } 131 } else if ( 132 currentStruct.groupId !== invalidGroupId && 133 index > 0 && 134 currentStruct.groupId === preFrameSpacing!.groupId 135 ) { 136 isDraw = true; 137 FrameSpacingStruct.draw(req.context, preFrameSpacing, currentStruct, row, minValue, maxValue); 138 } 139 FrameSpacingStruct.drawSelect(currentStruct, req.context, row); 140 preFrameSpacing = currentStruct; 141 } 142 if (req.frameRate) { 143 if (isDraw) { 144 this.drawDashedLines(Object.values(smallTickStandard), req, row, minValue, maxValue); 145 } 146 } 147 } 148 private setHoverStruct(findStructList: Array<FrameSpacingStruct>, row: TraceRow<FrameSpacingStruct>) { 149 let find = false; 150 if (findStructList.length > 0) { 151 find = true; 152 let hoverIndex: number = 0; 153 if (findStructList.length > unitIndex) { 154 hoverIndex = Math.ceil(findStructList.length / multiple); 155 } 156 FrameSpacingStruct.hoverFrameSpacingStruct = findStructList[hoverIndex]; 157 } 158 if (!find && row.isHover) { 159 FrameSpacingStruct.hoverFrameSpacingStruct = undefined; 160 } 161 } 162 163 private drawPoint( 164 ctx: CanvasRenderingContext2D, 165 currentStruct: FrameSpacingStruct, 166 row: TraceRow<FrameSpacingStruct>, 167 minValue: number, 168 maxValue: number 169 ): void { 170 let currentPointY = 171 row.frame.height - 172 Math.floor( 173 ((currentStruct.frameSpacingResult! - minValue) * (row.frame.height - padding * multiple)) / 174 (maxValue - minValue) 175 ) - 176 padding; 177 ctx.beginPath(); 178 ctx.lineWidth = 1; 179 ctx.globalAlpha = 1; 180 ctx.arc(currentStruct.frame!.x, currentPointY, multiple, 0, multiple * Math.PI); 181 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2]; 182 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[2]; 183 ctx.stroke(); 184 ctx.fill(); 185 ctx.closePath(); 186 } 187 188 private drawDashedLines( 189 dashedLines: number[], 190 req: { useCache: boolean; context: CanvasRenderingContext2D; type: string; frameRate: number }, 191 row: TraceRow<FrameSpacingStruct>, 192 minVale: number, 193 maxValue: number 194 ): void { 195 for (let i = 0; i < dashedLines.length; i++) { 196 FrameSpacingStruct.drawParallelLine(req.context, row.frame, dashedLines, i, minVale, maxValue); 197 } 198 } 199 200 private frameSpacing( 201 frameSpacingList: Array<FrameSpacingStruct>, 202 frameSpacingFilter: Array<FrameSpacingStruct>, 203 startNS: number, 204 endNS: number, 205 totalNS: number, 206 row: TraceRow<FrameSpacingStruct>, 207 animationRanges: AnimationRanges[], 208 use: boolean 209 ): void { 210 let frame: Rect = row.frame; 211 let modelName: string | undefined | null = row.getAttribute('model-name'); 212 if ((use || !TraceRow.range!.refresh) && frameSpacingFilter.length > 0) { 213 frameSpacingList.length = 0; 214 let groupIdList: number[] = []; 215 for (let index = 0; index < frameSpacingFilter.length; index++) { 216 let item = frameSpacingFilter[index]; 217 if (modelName === item.nameId) { 218 item.groupId = invalidGroupId; 219 for (let rangeIndex = 0; rangeIndex < animationRanges.length; rangeIndex++) { 220 let currentRange = animationRanges[rangeIndex]; 221 if (item.currentTs >= currentRange.start && item.currentTs <= currentRange.end) { 222 item.groupId = currentRange.start; 223 break; 224 } 225 } 226 if ( 227 item.currentTs < startNS && 228 index + unitIndex < frameSpacingFilter.length && 229 frameSpacingFilter[index + unitIndex].currentTs >= startNS && 230 item.groupId !== invalidGroupId 231 ) { 232 this.refreshFrame(frameSpacingList, item, startNS, endNS, totalNS, frame, groupIdList); 233 } 234 if (item.currentTs >= startNS && item.currentTs <= endNS && item.groupId !== invalidGroupId) { 235 this.refreshFrame(frameSpacingList, item, startNS, endNS, totalNS, frame, groupIdList); 236 } 237 if (item.currentTs > endNS && item.groupId !== invalidGroupId) { 238 this.refreshFrame(frameSpacingList, item, startNS, endNS, totalNS, frame, groupIdList); 239 break; 240 } 241 } 242 } 243 this.grouping(groupIdList, frameSpacingList); 244 return; 245 } 246 } 247 248 private grouping(groupIdList: number[], frameSpacingFilter: Array<FrameSpacingStruct>): void { 249 let simpleGroup = groupIdList.filter((groupId) => { 250 return groupId !== invalidGroupId && groupIdList.indexOf(groupId) === groupIdList.lastIndexOf(groupId); 251 }); 252 frameSpacingFilter.forEach((frameSpacing) => { 253 if (simpleGroup.indexOf(frameSpacing.groupId!) > invalidGroupId) { 254 frameSpacing.groupId = 0; 255 frameSpacing.frameSpacingResult = 0; 256 frameSpacing.preFrameWidth = 0; 257 frameSpacing.preFrameHeight = 0; 258 frameSpacing.preTs = 0; 259 frameSpacing.preX = 0; 260 frameSpacing.preY = 0; 261 } 262 }); 263 } 264 265 private refreshFrame( 266 frameSpacingFilter: Array<FrameSpacingStruct>, 267 item: FrameSpacingStruct, 268 startNS: number, 269 endNS: number, 270 totalNS: number, 271 frame: Rect, 272 groupIdList: number[] 273 ): void { 274 frameSpacingFilter.push(item); 275 FrameSpacingStruct.setFrameSpacingFrame(item, startNS, endNS, totalNS, frame); 276 groupIdList.push(item.groupId!); 277 } 278 279 private maxMinData(tickStandardMin: number, tickStandardMax: number, filter: FrameSpacingStruct[]): [number, number] { 280 let min = Math.min.apply( 281 Math, 282 filter.map((filterData) => { 283 return filterData.frameSpacingResult!; 284 }) 285 ); 286 let max = Math.max.apply( 287 Math, 288 filter.map((filterData) => { 289 return filterData.frameSpacingResult!; 290 }) 291 ); 292 if (max < tickStandardMax) { 293 max = tickStandardMax + padding; 294 } 295 if (min > tickStandardMin) { 296 min = tickStandardMin; 297 } 298 return [min, max]; 299 } 300} 301export function FrameSpacingStructOnClick(clickRowType: string, sp: SpSystemTrace) { 302 return new Promise((resolve,reject) => { 303 if (clickRowType === TraceRow.ROW_TYPE_FRAME_SPACING && FrameSpacingStruct.hoverFrameSpacingStruct) { 304 FrameSpacingStruct.selectFrameSpacingStruct = FrameSpacingStruct.hoverFrameSpacingStruct; 305 sp.traceSheetEL?.displayFrameSpacingData(FrameSpacingStruct.selectFrameSpacingStruct); 306 sp.timerShaftEL?.modifyFlagList(undefined); 307 reject(); 308 }else{ 309 resolve(null); 310 } 311 }); 312} 313export class FrameSpacingStruct extends BaseStruct { 314 static hoverFrameSpacingStruct: FrameSpacingStruct | undefined; 315 static selectFrameSpacingStruct: FrameSpacingStruct | undefined; 316 physicalWidth: number | undefined; 317 physicalHeight: number | undefined; 318 preTs: number | undefined; 319 currentTs: number = 0; 320 frameSpacingResult: number | undefined; 321 id: number = 0; 322 groupId: number | undefined; 323 currentFrameWidth: number | undefined; 324 preFrameWidth: number | undefined; 325 currentFrameHeight: number | undefined; 326 preFrameHeight: number | undefined; 327 x: number | undefined; 328 y: number | undefined; 329 preX: number | undefined; 330 preY: number | undefined; 331 nameId: string | undefined; 332 333 static setFrameSpacingFrame( 334 frameSpacingNode: FrameSpacingStruct, 335 startNS: number, 336 endNS: number, 337 totalNS: number, 338 row: Rect 339 ): void { 340 let pointX = ns2x(frameSpacingNode.currentTs || 0, startNS, endNS, totalNS, row); 341 if (!frameSpacingNode.frame) { 342 frameSpacingNode.frame = new Rect(0, 0, 0, 0); 343 } 344 frameSpacingNode.frame.x = Math.floor(pointX); 345 } 346 347 static isSelect(currSpacingStruct: FrameSpacingStruct): boolean | 0 | undefined { 348 return ( 349 TraceRow.rangeSelectObject && 350 TraceRow.rangeSelectObject.startNS && 351 TraceRow.rangeSelectObject.endNS && 352 currSpacingStruct.currentTs >= TraceRow.rangeSelectObject.startNS && 353 currSpacingStruct.currentTs <= TraceRow.rangeSelectObject.endNS 354 ); 355 } 356 357 static refreshHoverStruct( 358 preFrameSpacing: FrameSpacingStruct, 359 frameSpacing: FrameSpacingStruct, 360 row: TraceRow<FrameSpacingStruct>, 361 minValue: number, 362 maxValue: number 363 ): void { 364 if (frameSpacing.frame) { 365 frameSpacing.frame.y = 366 row.frame.height - 367 Math.floor( 368 ((frameSpacing.frameSpacingResult! - minValue) * (row.frame.height - padding * multiple)) / 369 (maxValue - minValue) 370 ) - 371 padding; 372 } 373 } 374 375 static draw( 376 ctx: CanvasRenderingContext2D, 377 preFrameSpacing: FrameSpacingStruct, 378 currentStruct: FrameSpacingStruct, 379 rowFrame: TraceRow<FrameSpacingStruct>, 380 minValue: number, 381 maxValue: number 382 ): void { 383 if (currentStruct.frame && preFrameSpacing.frame) { 384 this.drawPolyline(ctx, preFrameSpacing, currentStruct, rowFrame, minValue, maxValue); 385 } 386 } 387 388 static drawSelect( 389 currentStruct: FrameSpacingStruct, 390 ctx: CanvasRenderingContext2D, 391 rowFrame: TraceRow<FrameSpacingStruct> 392 ): void { 393 if ( 394 currentStruct.frame && 395 currentStruct.currentTs > TraceRow.range!.startNS && 396 currentStruct.currentTs < TraceRow.range!.endNS 397 ) { 398 if ( 399 (currentStruct === FrameSpacingStruct.hoverFrameSpacingStruct && rowFrame.isHover) || 400 currentStruct === FrameSpacingStruct.selectFrameSpacingStruct 401 ) { 402 ctx.lineWidth = 3; 403 ctx.beginPath(); 404 ctx.arc(currentStruct.frame.x, currentStruct.frame.y, selectRadius, 0, multiple * Math.PI); 405 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[7]; 406 ctx.lineWidth = 2; 407 ctx.globalAlpha = 1; 408 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[9]; 409 ctx.stroke(); 410 ctx.fill(); 411 ctx.closePath(); 412 } 413 } 414 if (rowFrame.getAttribute('check-type') === '2' && FrameSpacingStruct.isSelect(currentStruct)) { 415 ctx.beginPath(); 416 ctx.lineWidth = 3; 417 ctx.arc(currentStruct.frame!.x, currentStruct.frame!.y, selectRadius, 0, multiple * Math.PI); 418 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[7]; 419 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[9]; 420 ctx.lineWidth = 2; 421 ctx.globalAlpha = 1; 422 ctx.stroke(); 423 ctx.fill(); 424 ctx.closePath(); 425 } 426 } 427 428 static drawParallelLine( 429 ctx: CanvasRenderingContext2D, 430 rowFrame: Rect, 431 dashedLines: number[], 432 index: number, 433 minValue: number, 434 maxValue: number 435 ): void { 436 let pointY = 437 rowFrame.height - 438 Math.floor(((dashedLines[index] - minValue) * (rowFrame.height - padding * multiple)) / (maxValue - minValue)) - 439 padding; 440 let lineDash = 10; 441 let textPadding = 4; 442 ctx.beginPath(); 443 ctx.lineWidth = 2; 444 ctx.setLineDash([lineDash]); 445 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[6]; 446 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[6]; 447 ctx.moveTo(0, pointY); 448 ctx.lineTo(rowFrame.width, pointY); 449 ctx.stroke(); 450 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[3]; 451 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[3]; 452 if (index === 0) { 453 ctx.fillText(dashedLines[index].toString(), 0, pointY + multiple * textPadding); 454 } else if (index === unitIndex) { 455 ctx.fillText(dashedLines[index].toString(), 0, pointY + textPadding); 456 } else { 457 ctx.fillText(dashedLines[index].toString(), 0, pointY - textPadding); 458 } 459 ctx.closePath(); 460 } 461 462 static drawPolyline( 463 ctx: CanvasRenderingContext2D, 464 preFrameSpacing: FrameSpacingStruct, 465 currentStruct: FrameSpacingStruct, 466 rowFrame: TraceRow<FrameSpacingStruct>, 467 minValue: number, 468 maxValue: number 469 ): void { 470 ctx.beginPath(); 471 let prePointY = 472 rowFrame.frame.height - 473 Math.floor( 474 ((preFrameSpacing.frameSpacingResult! - minValue) * (rowFrame.frame.height - padding * multiple)) / 475 (maxValue - minValue) 476 ) - 477 padding; 478 let currentPointY = 479 rowFrame.frame.height - 480 Math.floor( 481 ((currentStruct.frameSpacingResult! - minValue) * (rowFrame.frame.height - padding * multiple)) / 482 (maxValue - minValue) 483 ) - 484 padding; 485 if (preFrameSpacing.frame && currentStruct.frame) { 486 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2]; 487 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[2]; 488 ctx.lineWidth = 2; 489 ctx.setLineDash([0]); 490 ctx.moveTo(preFrameSpacing.frame.x, prePointY); 491 ctx.lineTo(currentStruct.frame.x, currentPointY); 492 ctx.stroke(); 493 ctx.closePath(); 494 FrameSpacingStruct.drawSelect(preFrameSpacing, ctx, rowFrame); 495 } 496 } 497} 498 499const padding = 3; 500const invalidGroupId: number = -1; 501const multiple: number = 2; 502const unitIndex: number = 1; 503const selectRadius: number = 3; 504 505const smallTick = { 506 60: { 507 firstLine: 11.4, 508 secondLine: 13, 509 thirdLine: 14.6, 510 }, 511 90: { 512 firstLine: 13.7, 513 secondLine: 19.4, 514 thirdLine: 25, 515 }, 516 120: { 517 firstLine: 13.7, 518 secondLine: 19.4, 519 thirdLine: 25, 520 }, 521}; 522