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