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 { BaseStruct, isFrameContainPoint, drawLoadingFrame, ns2x, Render, Rect } from './ProcedureWorkerCommon'; 17import { TraceRow } from '../../component/trace/base/TraceRow'; 18 19export class EnergyStateRender extends Render { 20 renderMainThread( 21 req: { 22 useCache: boolean; 23 context: CanvasRenderingContext2D; 24 type: string; 25 maxState: number; 26 maxStateName: string; 27 }, 28 row: TraceRow<EnergyStateStruct> 29 ): void { 30 let stateList = row.dataList; 31 let stateFilter = row.dataListCache; 32 state( 33 stateList, 34 stateFilter, 35 TraceRow.range!.startNS || 0, 36 TraceRow.range!.endNS || 0, 37 TraceRow.range!.totalNS || 0, 38 row.frame, 39 req.useCache || !TraceRow.range!.refresh 40 ); 41 drawLoadingFrame(req.context, row.dataListCache, row); 42 req.context.beginPath(); 43 let find = false; 44 for (let i = 0; i < stateFilter.length; i++) { 45 let re = stateFilter[i]; 46 EnergyStateStruct.draw(req.context, re, req.maxState, req.maxStateName); 47 if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { 48 EnergyStateStruct.hoverEnergyStateStruct = re; 49 find = true; 50 } 51 } 52 if (!find && row.isHover) { 53 EnergyStateStruct.hoverEnergyStateStruct = undefined; 54 } 55 if (req.maxStateName !== 'enable' && req.maxStateName !== 'disable' && req.maxStateName !== '-1') { 56 let s = req.maxStateName; 57 let textMetrics = req.context.measureText(s); 58 req.context.globalAlpha = 1.0; 59 req.context.fillStyle = '#f0f0f0'; 60 req.context.fillRect(0, 5, textMetrics.width + 8, 18); 61 req.context.fillStyle = '#333'; 62 req.context.textBaseline = 'middle'; 63 req.context.fillText(s, 4, 5 + 9); 64 } 65 req.context.closePath(); 66 } 67} 68 69export function state( 70 stateList: Array<EnergyStateStruct>, 71 res: Array<EnergyStateStruct>, 72 startNS: number, 73 endNS: number, 74 totalNS: number, 75 frame: Rect, 76 use: boolean 77): void { 78 if (use && res.length > 0) { 79 for (let i = 0; i < res.length; i++) { 80 let stateItem = res[i]; 81 if (i === res.length - 1) { 82 stateItem.dur = endNS - (stateItem.startNs || 0); 83 } else { 84 stateItem.dur = (res[i + 1].startNs || 0) - (stateItem.startNs || 0); 85 } 86 if ((stateItem.startNs || 0) + (stateItem.dur || 0) > startNS && (stateItem.startNs || 0) < endNS) { 87 EnergyStateStruct.setStateFrame(res[i], 5, startNS, endNS, totalNS, frame); 88 } 89 } 90 return; 91 } 92 res.length = 0; 93 stateFilter(stateList, startNS, endNS, totalNS, frame, res); 94} 95function stateFilter( 96 stateList: Array<EnergyStateStruct>, 97 startNS: number, 98 endNS: number, 99 totalNS: number, 100 frame: Rect, 101 res: Array<EnergyStateStruct> 102): void { 103 if (stateList) { 104 for (let index = 0; index < stateList.length; index++) { 105 let item = stateList[index]; 106 item.dur = 107 index === stateList.length - 1 108 ? endNS - (item.startNs || 0) 109 : (stateList[index + 1].startNs || 0) - (item.startNs || 0); 110 if ((item.startNs || 0) + (item.dur || 0) > startNS && (item.startNs || 0) < endNS) { 111 EnergyStateStruct.setStateFrame(stateList[index], 5, startNS, endNS, totalNS, frame); 112 if ( 113 !( 114 index > 0 && 115 (stateList[index - 1].frame?.x || 0) === (stateList[index].frame?.x || 0) && 116 (stateList[index - 1].frame?.width || 0) === (stateList[index].frame?.width || 0) 117 ) 118 ) { 119 res.push(item); 120 } 121 } 122 } 123 } 124} 125 126export class EnergyStateStruct extends BaseStruct { 127 static maxState: number = 0; 128 static maxStateName: string = '0'; 129 static hoverEnergyStateStruct: EnergyStateStruct | undefined; 130 static selectEnergyStateStruct: EnergyStateStruct | undefined; 131 type: string | undefined; 132 value: number | undefined; 133 startNs: number | undefined; 134 dur: number | undefined; 135 136 sensorType: number | undefined; 137 pkg_name: string | undefined; 138 deviceState: number | undefined; 139 deviceType: number | undefined; 140 141 static draw( 142 energyStateContext: CanvasRenderingContext2D, 143 data: EnergyStateStruct, 144 maxState: number, 145 maxStateName: string 146 ): void { 147 if (data.frame) { 148 let width = data.frame.width || 0; 149 let drawColor = this.setDrawColor(data.type!); 150 energyStateContext.fillStyle = drawColor; 151 energyStateContext.strokeStyle = drawColor; 152 energyStateContext.globalAlpha = 1.0; 153 energyStateContext.lineWidth = 1; 154 let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxState); 155 if (maxStateName === 'enable' || maxStateName === 'disable') { 156 if (data.value === 0) { 157 drawHeight = data.frame.height; 158 energyStateContext.fillRect(data.frame.x, data.frame.y + 4, width, data.frame.height); 159 } 160 } else { 161 energyStateContext.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); 162 } 163 if (data.startNs === EnergyStateStruct.hoverEnergyStateStruct?.startNs) { 164 let pointy = data.frame.y + data.frame.height + 4; 165 if (data.value === 0) { 166 pointy -= drawHeight; 167 } 168 energyStateContext.beginPath(); 169 energyStateContext.arc(data.frame.x, pointy, 3, 0, 2 * Math.PI, true); 170 energyStateContext.fill(); 171 energyStateContext.globalAlpha = 1.0; 172 energyStateContext.stroke(); 173 energyStateContext.beginPath(); 174 energyStateContext.moveTo(data.frame.x + 3, pointy); 175 energyStateContext.lineWidth = 3; 176 energyStateContext.lineTo(data.frame.x + width, pointy); 177 energyStateContext.stroke(); 178 } 179 } 180 energyStateContext.globalAlpha = 1.0; 181 energyStateContext.lineWidth = 1; 182 } 183 184 static setStateFrame( 185 stateNode: EnergyStateStruct, 186 padding: number, 187 startNS: number, 188 endNS: number, 189 totalNS: number, 190 frame: Rect 191 ): void { 192 let stateStartPointX: number; 193 let stateEndPointX: number; 194 195 if ((stateNode.startNs || 0) < startNS) { 196 stateStartPointX = 0; 197 } else { 198 stateStartPointX = ns2x(stateNode.startNs || 0, startNS, endNS, totalNS, frame); 199 } 200 if ((stateNode.startNs || 0) + (stateNode.dur || 0) > endNS) { 201 stateEndPointX = frame.width; 202 } else { 203 stateEndPointX = ns2x((stateNode.startNs || 0) + (stateNode.dur || 0), startNS, endNS, totalNS, frame); 204 } 205 let frameWidth: number = stateEndPointX - stateStartPointX <= 1 ? 1 : stateEndPointX - stateStartPointX; 206 if (!stateNode.frame) { 207 stateNode.frame = new Rect(0, 0, 0, 0); 208 } 209 stateNode.frame.x = Math.floor(stateStartPointX); 210 stateNode.frame.y = frame.y + padding; 211 stateNode.frame.width = Math.ceil(frameWidth); 212 stateNode.frame.height = Math.floor(frame.height - padding * 2); 213 } 214 215 static setDrawColor(eventType: string): string { 216 switch (eventType) { 217 case 'BRIGHTNESS_NIT': 218 return '#92D6CC'; 219 case 'SIGNAL_LEVEL': 220 return '#61CFBE'; 221 case 'WIFI_EVENT_RECEIVED': 222 return '#46B1E3'; 223 case 'AUDIO_STREAM_CHANGE': 224 return '#ED6F21'; 225 case 'WIFI_STATE': 226 return '#61CFBE'; 227 case 'LOCATION_SWITCH_STATE': 228 return '#61CFBE'; 229 case 'SENSOR_STATE': 230 return '#61CFBE'; 231 default: 232 return '#61CFBE'; 233 } 234 } 235} 236