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