• 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js';
17import { TraceRow } from '../../component/trace/base/TraceRow.js';
18import { BaseStruct, drawString, isFrameContainPoint, ns2x, Rect, Render } from './ProcedureWorkerCommon.js';
19
20export class FrameAnimationRender extends Render {
21  renderMainThread(
22    req: {
23      useCache: boolean;
24      context: CanvasRenderingContext2D;
25      type: string;
26    },
27    row: TraceRow<FrameAnimationStruct>
28  ): void {
29    let frameAnimationList: FrameAnimationStruct[] = row.dataList;
30    let frameAnimationFilter: FrameAnimationStruct[] = row.dataListCache;
31    this.frameAnimation(
32      frameAnimationList,
33      frameAnimationFilter,
34      TraceRow.range!.startNS,
35      TraceRow.range!.endNS,
36      TraceRow.range!.totalNS,
37      row.frame,
38      req.useCache || !TraceRow.range!.refresh
39    );
40    req.context.beginPath();
41    let find: boolean = false;
42    for (let index: number = 0; index < frameAnimationFilter.length; index++) {
43      let currentAnimationStruct: FrameAnimationStruct = frameAnimationFilter[index];
44      FrameAnimationStruct.draw(req.context, index, currentAnimationStruct, row);
45      if (row.isHover && currentAnimationStruct.frame &&
46        isFrameContainPoint(currentAnimationStruct.frame, row.hoverX, row.hoverY)) {
47        FrameAnimationStruct.hoverFrameAnimationStruct = currentAnimationStruct;
48        find = true;
49      }
50    }
51    if (!find && row.isHover) {
52      FrameAnimationStruct.hoverFrameAnimationStruct = undefined;
53    }
54    req.context.closePath();
55  }
56
57  private frameAnimation(
58    frameAnimationList: FrameAnimationStruct[],
59    frameAnimationFilter: FrameAnimationStruct[],
60    startNS: number = 0,
61    endNS: number = 0,
62    totalNS: number,
63    frame: Rect,
64    use: boolean
65  ): void {
66    if (use && frameAnimationFilter.length > 0) {
67      for (let index: number = 0; index < frameAnimationFilter.length; index++) {
68        let frameAnimationNode: FrameAnimationStruct = frameAnimationFilter[index];
69        frameAnimationNode.frame = undefined;
70        FrameAnimationStruct.setFrameAnimation(frameAnimationNode, padding, startNS, endNS, totalNS, frame);
71      }
72      return;
73    }
74    frameAnimationFilter.length = 0;
75    if (frameAnimationList) {
76      for (let index: number = 0; index < frameAnimationList.length; index++) {
77        let currentFrameAnimation: FrameAnimationStruct = frameAnimationList[index];
78        let currentResponseFrame: FrameAnimationStruct = JSON.parse(JSON.stringify(currentFrameAnimation));
79        currentResponseFrame.status = 'Response delay';
80        currentResponseFrame.dur = currentFrameAnimation.dynamicStartTs - currentFrameAnimation.ts;
81        if ((currentResponseFrame.ts || 0) + (currentResponseFrame.dur || 0) > startNS &&
82          (currentResponseFrame.ts || 0) < endNS) {
83          FrameAnimationStruct.setFrameAnimation(currentResponseFrame, padding, startNS,
84            endNS || 0, totalNS || 0, frame);
85          frameAnimationFilter.push(currentResponseFrame);
86        }
87        let currentCompletionFrame: FrameAnimationStruct = JSON.parse(JSON.stringify(currentFrameAnimation));
88        currentCompletionFrame.status = 'Completion delay';
89        currentCompletionFrame.ts = currentFrameAnimation.dynamicStartTs;
90        currentCompletionFrame.dur = currentFrameAnimation.dynamicEndTs - currentFrameAnimation.dynamicStartTs;
91        if ((currentCompletionFrame.ts || 0) + (currentCompletionFrame.dur || 0) > startNS &&
92          (currentCompletionFrame.ts || 0) < endNS) {
93          FrameAnimationStruct.setFrameAnimation(currentCompletionFrame, padding, startNS,
94            endNS || 0, totalNS || 0, frame);
95          frameAnimationFilter.push(currentCompletionFrame);
96        }
97      }
98    }
99  };
100}
101
102export class FrameAnimationStruct extends BaseStruct {
103  static hoverFrameAnimationStruct: FrameAnimationStruct | undefined;
104  static selectFrameAnimationStruct: FrameAnimationStruct | undefined;
105  ts: number = 0;
106  dur: number = 0;
107  status: string = '';
108  animationId: number | undefined;
109  dynamicStartTs: number = 0;
110  dynamicEndTs: number = 0;
111  fps: number | undefined;
112
113  static setFrameAnimation(
114    animationNode: FrameAnimationStruct,
115    padding: number,
116    startNS: number,
117    endNS: number,
118    totalNS: number,
119    frame: Rect
120  ): void {
121    let stateStartPointX: number;
122    let stateEndPointX: number;
123    if ((animationNode.ts || 0) < startNS) {
124      stateStartPointX = 0;
125    } else {
126      stateStartPointX = ns2x(animationNode.ts || 0, startNS, endNS, totalNS, frame);
127    }
128    if ((animationNode.ts || 0) + (animationNode.dur || 0) > endNS) {
129      stateEndPointX = frame.width;
130    } else {
131      stateEndPointX = ns2x((animationNode.ts || 0) + (animationNode.dur || 0), startNS, endNS, totalNS, frame);
132    }
133    let frameWidth: number = stateEndPointX - stateStartPointX <= unitIndex ? unitIndex :
134      stateEndPointX - stateStartPointX;
135    if (!animationNode.frame) {
136      animationNode.frame = new Rect(0, 0, 0, 0);
137    }
138    animationNode.frame.x = Math.floor(stateStartPointX);
139    animationNode.frame.y = frame.y + padding;
140    animationNode.frame.width = Math.ceil(frameWidth);
141    animationNode.frame.height = Math.floor(frame.height - padding * multiple);
142  }
143
144  static draw(
145    ctx: CanvasRenderingContext2D,
146    index: number,
147    frameAnimationNode: FrameAnimationStruct,
148    row: TraceRow<FrameAnimationStruct>
149  ): void {
150    let tsFixed: number = 6;
151    let isHover: boolean = row.isHover;
152    if (frameAnimationNode.frame) {
153      let nsToMillisecond = 1000_000;
154      ctx.globalAlpha = 1.0;
155      ctx.lineWidth = 1;
156      ctx.lineJoin = 'round';
157      ctx.fillStyle = ColorUtils.ANIMATION_COLOR[6];
158      ctx.fillRect(frameAnimationNode.frame.x, frameAnimationNode.frame.y + (multiple * padding),
159        frameAnimationNode.frame.width, frameAnimationNode.frame.height);
160      ctx.fillStyle = ColorUtils.ANIMATION_COLOR[3];
161      ctx.textBaseline = 'middle';
162      ctx.font = '8px sans-serif';
163      drawString(ctx, `${frameAnimationNode.status} (${(frameAnimationNode.dur / nsToMillisecond).
164        toFixed(tsFixed)} ms)`, textPadding, frameAnimationNode.frame, frameAnimationNode);
165      ctx.lineWidth = 2;
166      if ((frameAnimationNode === FrameAnimationStruct.hoverFrameAnimationStruct && isHover) ||
167        frameAnimationNode === FrameAnimationStruct.selectFrameAnimationStruct) {
168        ctx.globalAlpha = 0.8;
169        ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[3];
170        ctx.strokeRect(frameAnimationNode.frame.x + padding, frameAnimationNode.frame.y + (multiple * padding),
171          frameAnimationNode.frame.width - padding, frameAnimationNode.frame.height - (multiple * padding));
172      } else {
173        ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2];
174        ctx.strokeRect(frameAnimationNode.frame.x + padding, frameAnimationNode.frame.y + (multiple * padding),
175          frameAnimationNode.frame.width - padding, frameAnimationNode.frame.height - (multiple * padding));
176      }
177    }
178  }
179}
180
181const padding: number = 2;
182const multiple: number = 2;
183const unitIndex: number = 1;
184const textPadding: number = 5;
185