• 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]; // @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