• 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 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, // @ts-ignore
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 = // @ts-ignore
171      row.frame.height -
172      Math.floor(
173        // @ts-ignore
174        ((currentStruct.frameSpacingResult! - minValue) * (row.frame.height - padding * multiple)) /
175          (maxValue - minValue)
176      ) -
177      padding;
178    ctx.beginPath();
179    ctx.lineWidth = 1;
180    ctx.globalAlpha = 1;
181    ctx.arc(currentStruct.frame!.x, currentPointY, multiple, 0, multiple * Math.PI);
182    ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2];
183    ctx.fillStyle = ColorUtils.ANIMATION_COLOR[2];
184    ctx.stroke();
185    ctx.fill();
186    ctx.closePath();
187  }
188
189  private drawDashedLines(
190    dashedLines: number[],
191    req: { useCache: boolean; context: CanvasRenderingContext2D; type: string; frameRate: number },
192    row: TraceRow<FrameSpacingStruct>,
193    minVale: number,
194    maxValue: number
195  ): void {
196    for (let i = 0; i < dashedLines.length; i++) {
197      // @ts-ignore
198      FrameSpacingStruct.drawParallelLine(req.context, row.frame, dashedLines, i, minVale, maxValue);
199    }
200  }
201
202  private frameSpacing(
203    frameSpacingList: Array<FrameSpacingStruct>,
204    frameSpacingFilter: Array<FrameSpacingStruct>,
205    startNS: number,
206    endNS: number,
207    totalNS: number,
208    row: TraceRow<FrameSpacingStruct>,
209    animationRanges: AnimationRanges[],
210    use: boolean
211  ): void {
212    // @ts-ignore
213    let frame: Rect = row.frame;
214    let modelName: string | undefined | null = row.getAttribute('model-name');
215    if ((use || !TraceRow.range!.refresh) && frameSpacingFilter.length > 0) {
216      frameSpacingList.length = 0;
217      let groupIdList: number[] = [];
218      for (let index = 0; index < frameSpacingFilter.length; index++) {
219        let item = frameSpacingFilter[index];
220        if (modelName === item.nameId) {
221          item.groupId = invalidGroupId;
222          for (let rangeIndex = 0; rangeIndex < animationRanges.length; rangeIndex++) {
223            let currentRange = animationRanges[rangeIndex];
224            if (item.currentTs >= currentRange.start && item.currentTs <= currentRange.end) {
225              item.groupId = currentRange.start;
226              break;
227            }
228          }
229          if (
230            item.currentTs < startNS &&
231            index + unitIndex < frameSpacingFilter.length &&
232            frameSpacingFilter[index + unitIndex].currentTs >= startNS &&
233            item.groupId !== invalidGroupId
234          ) {
235            this.refreshFrame(frameSpacingList, item, startNS, endNS, totalNS, frame, groupIdList);
236          }
237          if (item.currentTs >= startNS && item.currentTs <= endNS && item.groupId !== invalidGroupId) {
238            this.refreshFrame(frameSpacingList, item, startNS, endNS, totalNS, frame, groupIdList);
239          }
240          if (item.currentTs > endNS && item.groupId !== invalidGroupId) {
241            this.refreshFrame(frameSpacingList, item, startNS, endNS, totalNS, frame, groupIdList);
242            break;
243          }
244        }
245      }
246      this.grouping(groupIdList, frameSpacingList);
247      return;
248    }
249  }
250
251  private grouping(groupIdList: number[], frameSpacingFilter: Array<FrameSpacingStruct>): void {
252    let simpleGroup = groupIdList.filter((groupId) => {
253      return groupId !== invalidGroupId && groupIdList.indexOf(groupId) === groupIdList.lastIndexOf(groupId);
254    });
255    frameSpacingFilter.forEach((frameSpacing) => {
256      if (simpleGroup.indexOf(frameSpacing.groupId!) > invalidGroupId) {
257        frameSpacing.groupId = 0;
258        frameSpacing.frameSpacingResult = 0;
259        frameSpacing.preFrameWidth = 0;
260        frameSpacing.preFrameHeight = 0;
261        frameSpacing.preTs = 0;
262        frameSpacing.preX = 0;
263        frameSpacing.preY = 0;
264      }
265    });
266  }
267
268  private refreshFrame(
269    frameSpacingFilter: Array<FrameSpacingStruct>,
270    item: FrameSpacingStruct,
271    startNS: number,
272    endNS: number,
273    totalNS: number,
274    frame: Rect,
275    groupIdList: number[]
276  ): void {
277    frameSpacingFilter.push(item);
278    FrameSpacingStruct.setFrameSpacingFrame(item, startNS, endNS, totalNS, frame);
279    groupIdList.push(item.groupId!);
280  }
281
282  private maxMinData(tickStandardMin: number, tickStandardMax: number, filter: FrameSpacingStruct[]): [number, number] {
283    let min = Math.min.apply(
284      Math,
285      filter.map((filterData) => {
286        return filterData.frameSpacingResult!;
287      })
288    );
289    let max = Math.max.apply(
290      Math,
291      filter.map((filterData) => {
292        return filterData.frameSpacingResult!;
293      })
294    );
295    if (max < tickStandardMax) {
296      max = tickStandardMax + padding;
297    }
298    if (min > tickStandardMin) {
299      min = tickStandardMin;
300    }
301    return [min, max];
302  }
303}
304export function FrameSpacingStructOnClick(clickRowType: string, sp: SpSystemTrace, row: TraceRow<any>) {
305  return new Promise((resolve, reject) => {
306    if (clickRowType === TraceRow.ROW_TYPE_FRAME_SPACING) {
307      FrameSpacingStruct.selectFrameSpacingStruct =
308        FrameSpacingStruct.hoverFrameSpacingStruct || row.getHoverStruct(false, true);
309      if (FrameSpacingStruct.selectFrameSpacingStruct) {
310        sp.traceSheetEL?.displayFrameSpacingData(FrameSpacingStruct.selectFrameSpacingStruct);
311        sp.timerShaftEL?.modifyFlagList(undefined);
312      }
313      reject(new Error());
314    } else {
315      resolve(null);
316    }
317  });
318}
319export class FrameSpacingStruct extends BaseStruct {
320  static hoverFrameSpacingStruct: FrameSpacingStruct | undefined;
321  static selectFrameSpacingStruct: FrameSpacingStruct | undefined;
322  physicalWidth: number | undefined;
323  physicalHeight: number | undefined;
324  preTs: number | undefined;
325  currentTs: number = 0;
326  frameSpacingResult: number | undefined;
327  id: number = 0;
328  groupId: number | undefined;
329  currentFrameWidth: number | undefined;
330  preFrameWidth: number | undefined;
331  currentFrameHeight: number | undefined;
332  preFrameHeight: number | undefined;
333  x: number | undefined;
334  y: number | undefined;
335  preX: number | undefined;
336  preY: number | undefined;
337  nameId: string | undefined;
338
339  static setFrameSpacingFrame(
340    frameSpacingNode: FrameSpacingStruct,
341    startNS: number,
342    endNS: number,
343    totalNS: number,
344    row: Rect
345  ): void {
346    let pointX = ns2x(frameSpacingNode.currentTs || 0, startNS, endNS, totalNS, row);
347    if (!frameSpacingNode.frame) {
348      frameSpacingNode.frame = new Rect(0, 0, 0, 0);
349    }
350    frameSpacingNode.frame.x = Math.floor(pointX);
351  }
352
353  static isSelect(currSpacingStruct: FrameSpacingStruct): boolean | 0 | undefined {
354    return (
355      TraceRow.rangeSelectObject &&
356      TraceRow.rangeSelectObject.startNS &&
357      TraceRow.rangeSelectObject.endNS &&
358      currSpacingStruct.currentTs >= TraceRow.rangeSelectObject.startNS &&
359      currSpacingStruct.currentTs <= TraceRow.rangeSelectObject.endNS
360    );
361  }
362
363  static refreshHoverStruct(
364    preFrameSpacing: FrameSpacingStruct,
365    frameSpacing: FrameSpacingStruct,
366    row: TraceRow<FrameSpacingStruct>,
367    minValue: number,
368    maxValue: number
369  ): void {
370    if (frameSpacing.frame) {
371      frameSpacing.frame.y = // @ts-ignore
372        row.frame.height -
373        Math.floor(
374          // @ts-ignore
375          ((frameSpacing.frameSpacingResult! - minValue) * (row.frame.height - padding * multiple)) /
376            (maxValue - minValue)
377        ) -
378        padding;
379    }
380  }
381
382  static draw(
383    ctx: CanvasRenderingContext2D,
384    preFrameSpacing: FrameSpacingStruct,
385    currentStruct: FrameSpacingStruct,
386    rowFrame: TraceRow<FrameSpacingStruct>,
387    minValue: number,
388    maxValue: number
389  ): void {
390    if (currentStruct.frame && preFrameSpacing.frame) {
391      this.drawPolyline(ctx, preFrameSpacing, currentStruct, rowFrame, minValue, maxValue);
392    }
393  }
394
395  static drawSelect(
396    currentStruct: FrameSpacingStruct,
397    ctx: CanvasRenderingContext2D,
398    rowFrame: TraceRow<FrameSpacingStruct>
399  ): void {
400    if (
401      currentStruct.frame &&
402      currentStruct.currentTs > TraceRow.range!.startNS &&
403      currentStruct.currentTs < TraceRow.range!.endNS
404    ) {
405      if (
406        (currentStruct === FrameSpacingStruct.hoverFrameSpacingStruct && rowFrame.isHover) ||
407        currentStruct === FrameSpacingStruct.selectFrameSpacingStruct
408      ) {
409        ctx.lineWidth = 3;
410        ctx.beginPath();
411        ctx.arc(currentStruct.frame.x, currentStruct.frame.y, selectRadius, 0, multiple * Math.PI);
412        ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[7];
413        ctx.lineWidth = 2;
414        ctx.globalAlpha = 1;
415        ctx.fillStyle = ColorUtils.ANIMATION_COLOR[9];
416        ctx.stroke();
417        ctx.fill();
418        ctx.closePath();
419      }
420    }
421    if (rowFrame.getAttribute('check-type') === '2' && FrameSpacingStruct.isSelect(currentStruct)) {
422      ctx.beginPath();
423      ctx.lineWidth = 3;
424      ctx.arc(currentStruct.frame!.x, currentStruct.frame!.y, selectRadius, 0, multiple * Math.PI);
425      ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[7];
426      ctx.fillStyle = ColorUtils.ANIMATION_COLOR[9];
427      ctx.lineWidth = 2;
428      ctx.globalAlpha = 1;
429      ctx.stroke();
430      ctx.fill();
431      ctx.closePath();
432    }
433  }
434
435  static drawParallelLine(
436    ctx: CanvasRenderingContext2D,
437    rowFrame: Rect,
438    dashedLines: number[],
439    index: number,
440    minValue: number,
441    maxValue: number
442  ): void {
443    let pointY =
444      rowFrame.height -
445      Math.floor(((dashedLines[index] - minValue) * (rowFrame.height - padding * multiple)) / (maxValue - minValue)) -
446      padding;
447    let lineDash = 10;
448    let textPadding = 4;
449    ctx.beginPath();
450    ctx.lineWidth = 2;
451    ctx.setLineDash([lineDash]);
452    ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[6];
453    ctx.fillStyle = ColorUtils.ANIMATION_COLOR[6];
454    ctx.moveTo(0, pointY);
455    ctx.lineTo(rowFrame.width, pointY);
456    ctx.stroke();
457    ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[3];
458    ctx.fillStyle = ColorUtils.ANIMATION_COLOR[3];
459    if (index === 0) {
460      ctx.fillText(dashedLines[index].toString(), 0, pointY + multiple * textPadding);
461    } else if (index === unitIndex) {
462      ctx.fillText(dashedLines[index].toString(), 0, pointY + textPadding);
463    } else {
464      ctx.fillText(dashedLines[index].toString(), 0, pointY - textPadding);
465    }
466    ctx.closePath();
467  }
468
469  static drawPolyline(
470    ctx: CanvasRenderingContext2D,
471    preFrameSpacing: FrameSpacingStruct,
472    currentStruct: FrameSpacingStruct,
473    rowFrame: TraceRow<FrameSpacingStruct>,
474    minValue: number,
475    maxValue: number
476  ): void {
477    ctx.beginPath();
478    let prePointY = // @ts-ignore
479      rowFrame.frame.height -
480      Math.floor(
481        // @ts-ignore
482        ((preFrameSpacing.frameSpacingResult! - minValue) * (rowFrame.frame.height - padding * multiple)) /
483          (maxValue - minValue)
484      ) -
485      padding;
486    let currentPointY = // @ts-ignore
487      rowFrame.frame.height -
488      Math.floor(
489        // @ts-ignore
490        ((currentStruct.frameSpacingResult! - minValue) * (rowFrame.frame.height - padding * multiple)) /
491          (maxValue - minValue)
492      ) -
493      padding;
494    if (preFrameSpacing.frame && currentStruct.frame) {
495      ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2];
496      ctx.fillStyle = ColorUtils.ANIMATION_COLOR[2];
497      ctx.lineWidth = 2;
498      ctx.setLineDash([0]);
499      ctx.moveTo(preFrameSpacing.frame.x, prePointY);
500      ctx.lineTo(currentStruct.frame.x, currentPointY);
501      ctx.stroke();
502      ctx.closePath();
503      FrameSpacingStruct.drawSelect(preFrameSpacing, ctx, rowFrame);
504    }
505  }
506}
507
508const padding = 3;
509const invalidGroupId: number = -1;
510const multiple: number = 2;
511const unitIndex: number = 1;
512const selectRadius: number = 3;
513
514const smallTick = {
515  60: {
516    firstLine: 11.4,
517    secondLine: 13,
518    thirdLine: 14.6,
519  },
520  90: {
521    firstLine: 13.7,
522    secondLine: 19.4,
523    thirdLine: 25,
524  },
525  120: {
526    firstLine: 13.7,
527    secondLine: 19.4,
528    thirdLine: 25,
529  },
530};
531