• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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