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 FrameDynamicRender extends Render { 31 renderMainThread( 32 req: { 33 useCache: boolean; 34 context: CanvasRenderingContext2D; 35 type: string; 36 animationRanges: AnimationRanges[]; 37 }, 38 row: TraceRow<FrameDynamicStruct> 39 ): void { 40 let frameDynamicList: FrameDynamicStruct[] = row.dataList; 41 let frameDynamicFilter: FrameDynamicStruct[] = row.dataListCache; 42 this.frameDynamic(frameDynamicList, frameDynamicFilter, row, req.animationRanges, req.useCache); 43 drawLoadingFrame(req.context, row.dataListCache, row); 44 if (req.animationRanges.length > 0 && req.animationRanges[0] && frameDynamicList.length > 0) { 45 let modelType: string = row.getAttribute('model-type') || 'x'; 46 let [minValue, maxValue] = this.getMinAndMaxData(frameDynamicList, modelType); 47 let preDynamic: FrameDynamicStruct = frameDynamicList[0]; 48 let isDraw = false; 49 let selectUnitWidth: number = 0; 50 for (let index: number = 0; index < frameDynamicList.length; index++) { 51 let currDynamic: FrameDynamicStruct = frameDynamicList[index]; // @ts-ignore 52 selectUnitWidth = computeUnitWidth(preDynamic.ts, currDynamic.ts, row.frame.width, selectUnitWidth); 53 this.refreshPointY(currDynamic, row, modelType, minValue, maxValue); 54 if (currDynamic.groupId === 0) { 55 if (currDynamic.ts > TraceRow.range!.startNS && currDynamic.ts < TraceRow.range!.endNS) { 56 isDraw = true; 57 this.drawSinglePoint(req.context, currDynamic, row, modelType, minValue, maxValue); 58 } 59 } else if (currDynamic.groupId !== invalidGroupId && index > 0 && currDynamic.groupId === preDynamic!.groupId) { 60 isDraw = true; 61 FrameDynamicStruct.draw(req.context, preDynamic, currDynamic, row, modelType); 62 } 63 FrameDynamicStruct.drawSelect(req.context, currDynamic, row); 64 preDynamic = currDynamic; 65 } 66 if (isDraw) { 67 // @ts-ignore 68 this.drawDynamicPointYStr(req.context, frameDynamicList, row.frame, minValue, maxValue); 69 } 70 if (!this.setHoverFrameDynamic(row, frameDynamicList, selectUnitWidth) && row.isHover) { 71 FrameDynamicStruct.hoverFrameDynamicStruct = undefined; 72 } 73 } 74 } 75 76 private setHoverFrameDynamic( 77 row: TraceRow<FrameDynamicStruct>, 78 frameDynamicFilter: FrameDynamicStruct[], 79 selectUnitWidth: number 80 ): boolean { 81 let find: boolean = false; 82 let findStructList = frameDynamicFilter.filter( 83 (filter) => row.isHover && isSurroundingPoint(row.hoverX, filter.frame!, selectUnitWidth / multiple) 84 ); 85 if (findStructList.length > 0) { 86 find = true; 87 let hoverIndex: number = 0; 88 if (findStructList.length > unitIndex) { 89 hoverIndex = Math.ceil(findStructList.length / multiple); 90 } 91 FrameDynamicStruct.hoverFrameDynamicStruct = findStructList[hoverIndex]; 92 } 93 return find; 94 } 95 96 private frameDynamic( 97 dynamicList: FrameDynamicStruct[], 98 dynamicFilter: FrameDynamicStruct[], 99 row: TraceRow<FrameDynamicStruct>, 100 animationRanges: AnimationRanges[], 101 use: boolean 102 ): void { 103 let startNS: number = TraceRow.range!.startNS; 104 let endNS: number = TraceRow.range!.endNS; 105 let totalNS: number = TraceRow.range!.totalNS; // @ts-ignore 106 let frame: Rect = row.frame; 107 let modelName: string | undefined | null = row.getAttribute('model-name'); 108 if ((use || !TraceRow.range!.refresh) && dynamicFilter.length > 0) { 109 dynamicList.length = 0; 110 let groupIdList: number[] = []; 111 for (let dataIndex: number = 0; dataIndex < dynamicFilter.length; dataIndex++) { 112 let currentDynamic: FrameDynamicStruct = dynamicFilter[dataIndex]; 113 if (currentDynamic.appName === modelName) { 114 currentDynamic.groupId = invalidGroupId; 115 for (let rangeIndex = 0; rangeIndex < animationRanges.length; rangeIndex++) { 116 let currentRange = animationRanges[rangeIndex]; 117 if (currentDynamic.ts >= currentRange.start && currentDynamic.ts <= currentRange.end) { 118 currentDynamic.groupId = currentRange.start; 119 break; 120 } 121 } 122 if ( 123 currentDynamic.ts < startNS && 124 dataIndex + unitIndex < dynamicFilter.length && 125 dynamicFilter[dataIndex + unitIndex].ts >= startNS && 126 currentDynamic.groupId !== invalidGroupId 127 ) { 128 this.refreshFilterDynamicFrame(dynamicList, currentDynamic, frame, startNS, endNS, totalNS, groupIdList); 129 } 130 if (currentDynamic.ts >= startNS && currentDynamic.ts <= endNS && currentDynamic.groupId !== invalidGroupId) { 131 this.refreshFilterDynamicFrame(dynamicList, currentDynamic, frame, startNS, endNS, totalNS, groupIdList); 132 } 133 if (currentDynamic.ts >= endNS && currentDynamic.groupId !== invalidGroupId) { 134 this.refreshFilterDynamicFrame(dynamicList, currentDynamic, frame, startNS, endNS, totalNS, groupIdList); 135 break; 136 } 137 } 138 } 139 this.setSimpleGroupId(groupIdList, dynamicList); 140 } 141 } 142 143 private setSimpleGroupId(groupIdList: number[], frameDynamicFilter: FrameDynamicStruct[]): void { 144 let simpleGroup = groupIdList.filter((groupId) => { 145 return groupId !== invalidGroupId && groupIdList.indexOf(groupId) === groupIdList.lastIndexOf(groupId); 146 }); 147 frameDynamicFilter.forEach((dynamic) => { 148 if (simpleGroup.indexOf(dynamic.groupId!) > invalidGroupId) { 149 dynamic.groupId = 0; 150 } 151 }); 152 } 153 154 private refreshDynamicFrame( 155 frameDynamicFilter: FrameDynamicStruct[], 156 frame: Rect, 157 startNS: number, 158 endNS: number, 159 totalNS: number, 160 modelName: string 161 ): void { 162 for (let index: number = 0; index < frameDynamicFilter.length; index++) { 163 let frameDynamicNode: FrameDynamicStruct = frameDynamicFilter[index]; 164 frameDynamicNode.frame = undefined; 165 if (frameDynamicNode.appName === modelName) { 166 FrameDynamicStruct.setFrameDynamic(frameDynamicNode, startNS, endNS, totalNS, frame); 167 } 168 } 169 } 170 171 private drawSinglePoint( 172 ctx: CanvasRenderingContext2D, 173 currDynamic: FrameDynamicStruct, 174 row: TraceRow<FrameDynamicStruct>, 175 modelType: string, 176 minValue: number, 177 maxValue: number 178 ): void { 179 let smallArcRadius: number = 2; 180 // @ts-ignore 181 currDynamic.typeValue = currDynamic[modelType]; 182 currDynamic.frame!.y = // @ts-ignore 183 row.frame.height - 184 padding - // @ts-ignore 185 ((row.frame.height - padding * multiple) * ((currDynamic.typeValue || 0) - minValue)) / (maxValue - minValue); 186 ctx.beginPath(); 187 ctx.lineWidth = 1; 188 ctx.globalAlpha = 1; 189 ctx.arc(currDynamic.frame!.x, currDynamic.frame!.y, smallArcRadius, 0, multiple * Math.PI); 190 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2]; 191 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[2]; 192 ctx.stroke(); 193 ctx.fill(); 194 ctx.closePath(); 195 } 196 197 private refreshPointY( 198 curDynamic: FrameDynamicStruct, 199 row: TraceRow<FrameDynamicStruct>, 200 modelType: string, 201 minValue: number, 202 maxValue: number 203 ): void { 204 // @ts-ignore 205 let currDynamicValue = curDynamic[modelType]; 206 if (curDynamic.frame) { 207 // @ts-ignore 208 let pointY = (row.frame.height - padding * multiple) * ((currDynamicValue - minValue) / (maxValue - minValue)); // @ts-ignore 209 curDynamic.frame.y = row.frame.height - padding - pointY; 210 } 211 } 212 213 private drawDynamicPointYStr( 214 ctx: CanvasRenderingContext2D, 215 frameDynamicFilter: FrameDynamicStruct[], 216 frame: Rect, 217 minValue: number, 218 maxValue: number 219 ): void { 220 if (frameDynamicFilter.length > 0) { 221 ctx.globalAlpha = 1; 222 ctx.lineWidth = 1; 223 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[3]; 224 let minUnitValue: number = 10; 225 let fixedNumber = 2; 226 let totalValue = maxValue - minValue; 227 let pointYInterval = totalValue / (yScaleNumber - unitIndex); 228 for (let index = 0; index < yScaleNumber; index++) { 229 let pointYValue = minValue + pointYInterval * index; 230 let pointYHeight = ((frame.height - padding * multiple) * (pointYValue - minValue)) / totalValue; 231 let pointY = frame.height - multiple * padding - pointYHeight; 232 if (pointYValue !== 0) { 233 if (maxValue - minValue <= minUnitValue) { 234 ctx.fillText(`- ${pointYValue.toFixed(fixedNumber)}`, 0, pointY); 235 } else { 236 ctx.fillText(`- ${Math.ceil(pointYValue)}`, 0, pointY); 237 } 238 } 239 } 240 } 241 } 242 243 private getMinAndMaxData(frameDynamicFilter: FrameDynamicStruct[], modelType: string): [number, number] { 244 let min: number = Math.min.apply( 245 Math, 246 frameDynamicFilter.map((filterData) => { 247 // @ts-ignore 248 return filterData[modelType]; 249 }) 250 ); 251 let max: number = Math.max.apply( 252 Math, 253 frameDynamicFilter.map((filterData) => { 254 // @ts-ignore 255 return filterData[modelType]; 256 }) 257 ); 258 259 let yScaleMinValue: number = 1; 260 let yScaleMinSpacing: number = 10; 261 if (min === max) { 262 if (max <= yScaleMinValue) { 263 max = yScaleMinValue; 264 min = 0; 265 } else if (max <= yScaleMinSpacing) { 266 max = yScaleMinSpacing; 267 min = 0; 268 } else { 269 max += yScaleMinSpacing; 270 min -= yScaleMinSpacing; 271 } 272 } 273 return [min, max]; 274 } 275 276 private refreshFilterDynamicFrame( 277 frameDynamicFilter: FrameDynamicStruct[], 278 currentFrameDynamic: FrameDynamicStruct, 279 frame: Rect, 280 startNS: number, 281 endNS: number, 282 totalNS: number, 283 groupIdList: number[] 284 ): void { 285 groupIdList.push(currentFrameDynamic.groupId!); 286 frameDynamicFilter.push(currentFrameDynamic); 287 FrameDynamicStruct.setFrameDynamic(currentFrameDynamic, startNS, endNS, totalNS, frame); 288 } 289} 290export function FrameDynamicStructOnClick(clickRowType: string, sp: SpSystemTrace, row: undefined | TraceRow<any>) { 291 return new Promise((resolve, reject) => { 292 if (clickRowType === TraceRow.ROW_TYPE_FRAME_DYNAMIC) { 293 FrameDynamicStruct.selectFrameDynamicStruct = 294 FrameDynamicStruct.hoverFrameDynamicStruct || row?.getHoverStruct(false, true); 295 if (FrameDynamicStruct.selectFrameDynamicStruct) { 296 sp.traceSheetEL?.displayFrameDynamicData(row!, FrameDynamicStruct.selectFrameDynamicStruct); 297 sp.timerShaftEL?.modifyFlagList(undefined); 298 } 299 reject(new Error()); 300 } else { 301 resolve(null); 302 } 303 }); 304} 305export class FrameDynamicStruct extends BaseStruct { 306 static hoverFrameDynamicStruct: FrameDynamicStruct | undefined; 307 static selectFrameDynamicStruct: FrameDynamicStruct | undefined; 308 ts: number = 0; 309 id: number | undefined; 310 x: number | undefined; 311 y: number | undefined; 312 width: number | undefined; 313 height: number | undefined; 314 alpha: number = 0; 315 appName: string | undefined; 316 groupId: number | undefined; 317 typeValue: number | undefined; 318 319 static setFrameDynamic( 320 dynamicNode: FrameDynamicStruct, 321 startNS: number, 322 endNS: number, 323 totalNS: number, 324 frame: Rect 325 ): void { 326 let pointX: number = ns2x(dynamicNode.ts || 0, startNS, endNS, totalNS, frame); 327 if (!dynamicNode.frame) { 328 dynamicNode.frame = new Rect(0, 0, 0, 0); 329 } 330 dynamicNode.frame.x = Math.floor(pointX); 331 dynamicNode.frame.height = frame.height; 332 } 333 334 static draw( 335 ctx: CanvasRenderingContext2D, 336 preDynamicStruct: FrameDynamicStruct, 337 currDynamicStruct: FrameDynamicStruct, 338 row: TraceRow<FrameDynamicStruct>, 339 modelType: string 340 ): void { 341 if (preDynamicStruct.frame && currDynamicStruct.frame) { 342 // @ts-ignore 343 preDynamicStruct.typeValue = preDynamicStruct[modelType]; 344 // @ts-ignore 345 currDynamicStruct.typeValue = currDynamicStruct[modelType]; 346 if (preDynamicStruct.typeValue === currDynamicStruct.typeValue) { 347 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[1]; 348 } else { 349 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2]; 350 } 351 ctx.beginPath(); 352 ctx.globalAlpha = 1; 353 ctx.lineWidth = 3; 354 ctx.lineJoin = 'round'; 355 ctx.moveTo(preDynamicStruct.frame.x, preDynamicStruct.frame.y); 356 ctx.lineTo(currDynamicStruct.frame.x, currDynamicStruct.frame.y); 357 ctx.stroke(); 358 ctx.closePath(); 359 FrameDynamicStruct.drawSelect(ctx, preDynamicStruct, row); 360 } 361 } 362 363 static drawSelect( 364 ctx: CanvasRenderingContext2D, 365 currDynamicStruct: FrameDynamicStruct, 366 row: TraceRow<FrameDynamicStruct> 367 ): void { 368 if ( 369 (currDynamicStruct === FrameDynamicStruct.hoverFrameDynamicStruct && row.isHover) || 370 currDynamicStruct === FrameDynamicStruct.selectFrameDynamicStruct 371 ) { 372 FrameDynamicStruct.drawSelectOrHoverArc(ctx, currDynamicStruct); 373 } 374 if (row.getAttribute('check-type') === '2' && FrameDynamicStruct.isSelect(currDynamicStruct)) { 375 FrameDynamicStruct.drawSelectOrHoverArc(ctx, currDynamicStruct); 376 } 377 } 378 379 static drawSelectOrHoverArc(ctx: CanvasRenderingContext2D, currDynamicStruct: FrameDynamicStruct): void { 380 if ( 381 currDynamicStruct.frame && 382 currDynamicStruct.ts > TraceRow.range!.startNS && 383 currDynamicStruct.ts < TraceRow.range!.endNS 384 ) { 385 let bigArcRadius: number = 3; 386 ctx.beginPath(); 387 ctx.lineWidth = 3; 388 ctx.globalAlpha = 1; 389 ctx.arc(currDynamicStruct.frame.x, currDynamicStruct.frame.y, bigArcRadius, 0, multiple * Math.PI); 390 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[7]; 391 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[9]; 392 ctx.stroke(); 393 ctx.fill(); 394 } 395 } 396 397 static isSelect(currDynamicStruct: FrameDynamicStruct): boolean | 0 | undefined { 398 return ( 399 TraceRow.rangeSelectObject && 400 TraceRow.rangeSelectObject.startNS && 401 TraceRow.rangeSelectObject.endNS && 402 currDynamicStruct.ts >= TraceRow.rangeSelectObject.startNS && 403 currDynamicStruct.ts <= TraceRow.rangeSelectObject.endNS 404 ); 405 } 406} 407 408const padding: number = 3; 409const invalidGroupId: number = -1; 410const multiple: number = 2; 411const unitIndex: number = 1; 412const yScaleNumber: number = 5; 413