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 { 17 BaseStruct, 18 drawLines, 19 drawLoading, 20 drawFlagLine, 21 drawSelection, 22 isFrameContainPoint, 23 ns2x, 24 Render, 25 RequestMessage, 26} from './ProcedureWorkerCommon.js'; 27import { TraceRow } from '../../component/trace/base/TraceRow.js'; 28 29export class EnergyStateRender extends Render { 30 renderMainThread( 31 req: { 32 useCache: boolean; 33 context: CanvasRenderingContext2D; 34 type: string; 35 maxState: number; 36 maxStateName: string; 37 }, 38 row: TraceRow<EnergyStateStruct> 39 ) { 40 let stateList = row.dataList; 41 let stateFilter = row.dataListCache; 42 state( 43 stateList, 44 stateFilter, 45 TraceRow.range!.startNS, 46 TraceRow.range!.endNS, 47 TraceRow.range!.totalNS, 48 row.frame, 49 req.useCache || !TraceRow.range!.refresh 50 ); 51 req.context.beginPath(); 52 let find = false; 53 for (let i = 0; i < stateFilter.length; i++) { 54 let re = stateFilter[i]; 55 EnergyStateStruct.draw(req.context, re, req.maxState, req.maxStateName); 56 if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { 57 EnergyStateStruct.hoverEnergyStateStruct = re; 58 find = true; 59 } 60 } 61 if (!find && row.isHover) EnergyStateStruct.hoverEnergyStateStruct = undefined; 62 if (req.maxStateName != 'enable' && req.maxStateName != 'disable' && req.maxStateName != '-1') { 63 let s = req.maxStateName; 64 let textMetrics = req.context.measureText(s); 65 req.context.globalAlpha = 1.0; 66 req.context.fillStyle = '#f0f0f0'; 67 req.context.fillRect(0, 5, textMetrics.width + 8, 18); 68 req.context.fillStyle = '#333'; 69 req.context.textBaseline = 'middle'; 70 req.context.fillText(s, 4, 5 + 9); 71 } 72 req.context.closePath(); 73 } 74 75 render(energyStateRequest: RequestMessage, stateList: Array<any>, filter: Array<any>) { 76 if (energyStateRequest.lazyRefresh) { 77 state( 78 stateList, 79 filter, 80 energyStateRequest.startNS, 81 energyStateRequest.endNS, 82 energyStateRequest.totalNS, 83 energyStateRequest.frame, 84 energyStateRequest.useCache || !energyStateRequest.range.refresh 85 ); 86 } else { 87 if (!energyStateRequest.useCache) { 88 state( 89 stateList, 90 filter, 91 energyStateRequest.startNS, 92 energyStateRequest.endNS, 93 energyStateRequest.totalNS, 94 energyStateRequest.frame, 95 false 96 ); 97 } 98 } 99 if (energyStateRequest.canvas) { 100 energyStateRequest.context.clearRect(0, 0, energyStateRequest.canvas.width, energyStateRequest.canvas.height); 101 let energyStateArr = filter; 102 if ( 103 energyStateArr.length > 0 && 104 !energyStateRequest.range.refresh && 105 !energyStateRequest.useCache && 106 energyStateRequest.lazyRefresh 107 ) { 108 drawLoading( 109 energyStateRequest.context, 110 energyStateRequest.startNS, 111 energyStateRequest.endNS, 112 energyStateRequest.totalNS, 113 energyStateRequest.frame, 114 energyStateArr[0].startNS, 115 energyStateArr[energyStateArr.length - 1].startNS + energyStateArr[energyStateArr.length - 1].dur 116 ); 117 } 118 drawLines( 119 energyStateRequest.context, 120 energyStateRequest.xs, 121 energyStateRequest.frame.height, 122 energyStateRequest.lineColor 123 ); 124 energyStateRequest.context.beginPath(); 125 EnergyStateStruct.maxState = energyStateRequest.params.maxState; 126 EnergyStateStruct.maxStateName = energyStateRequest.params.maxStateName; 127 drawLines( 128 energyStateRequest.context, 129 energyStateRequest.xs, 130 energyStateRequest.frame.height, 131 energyStateRequest.lineColor 132 ); 133 EnergyStateStruct.hoverEnergyStateStruct = undefined; 134 if (energyStateRequest.isHover) { 135 for (let re of filter) { 136 if ( 137 re.frame && 138 energyStateRequest.hoverX >= re.frame.x && 139 energyStateRequest.hoverX <= re.frame.x + re.frame.width && 140 energyStateRequest.hoverY >= re.frame.y && 141 energyStateRequest.hoverY <= re.frame.y + re.frame.height 142 ) { 143 EnergyStateStruct.hoverEnergyStateStruct = re; 144 break; 145 } 146 } 147 } 148 EnergyStateStruct.selectEnergyStateStruct = energyStateRequest.params.selectEnergyStateStruct; 149 for (let re of filter) { 150 EnergyStateStruct.draw(energyStateRequest.context, re, 0, ''); 151 } 152 drawSelection(energyStateRequest.context, energyStateRequest.params); 153 energyStateRequest.context.closePath(); 154 if ( 155 EnergyStateStruct.maxStateName != 'enable' && 156 EnergyStateStruct.maxStateName != 'disable' && 157 EnergyStateStruct.maxStateName != '-1' 158 ) { 159 let s = EnergyStateStruct.maxStateName; 160 let textMetrics = energyStateRequest.context.measureText(s); 161 energyStateRequest.context.globalAlpha = 1.0; 162 energyStateRequest.context.fillStyle = '#f0f0f0'; 163 energyStateRequest.context.fillRect(0, 5, textMetrics.width + 8, 18); 164 energyStateRequest.context.fillStyle = '#333'; 165 energyStateRequest.context.textBaseline = 'middle'; 166 energyStateRequest.context.fillText(s, 4, 5 + 9); 167 } 168 drawFlagLine( 169 energyStateRequest.context, 170 energyStateRequest.flagMoveInfo, 171 energyStateRequest.flagSelectedInfo, 172 energyStateRequest.startNS, 173 energyStateRequest.endNS, 174 energyStateRequest.totalNS, 175 energyStateRequest.frame, 176 energyStateRequest.slicesTime 177 ); 178 } 179 // @ts-ignore 180 self.postMessage({ 181 id: energyStateRequest.id, 182 type: energyStateRequest.type, 183 results: energyStateRequest.canvas ? undefined : filter, 184 hover: EnergyStateStruct.hoverEnergyStateStruct, 185 }); 186 } 187} 188 189export function state( 190 stateList: Array<any>, 191 res: Array<any>, 192 startNS: number, 193 endNS: number, 194 totalNS: number, 195 frame: any, 196 use: boolean 197) { 198 if (use && res.length > 0) { 199 for (let i = 0; i < res.length; i++) { 200 let stateItem = res[i]; 201 if ((stateItem.startNs || 0) + (stateItem.dur || 0) > (startNS || 0) && (stateItem.startNs || 0) < (endNS || 0)) { 202 EnergyStateStruct.setStateFrame(stateItem, 5, startNS || 0, endNS || 0, totalNS || 0, frame); 203 } else { 204 stateItem.frame = null; 205 } 206 } 207 return; 208 } 209 res.length = 0; 210 if (stateList) { 211 for (let index = 0; index < stateList.length; index++) { 212 let item = stateList[index]; 213 if (index === stateList.length - 1) { 214 item.dur = (endNS || 0) - (item.startNs || 0); 215 } else { 216 item.dur = (stateList[index + 1].startNs || 0) - (item.startNs || 0); 217 } 218 if ((item.startNs || 0) + (item.dur || 0) > (startNS || 0) && (item.startNs || 0) < (endNS || 0)) { 219 EnergyStateStruct.setStateFrame(stateList[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); 220 if ( 221 index > 0 && 222 (stateList[index - 1].frame?.x || 0) == (stateList[index].frame?.x || 0) && 223 (stateList[index - 1].frame?.width || 0) == (stateList[index].frame?.width || 0) 224 ) { 225 } else { 226 res.push(item); 227 } 228 } 229 } 230 } 231} 232 233export class EnergyStateStruct extends BaseStruct { 234 static maxState: number = 0; 235 static maxStateName: string = '0'; 236 static hoverEnergyStateStruct: EnergyStateStruct | undefined; 237 static selectEnergyStateStruct: EnergyStateStruct | undefined; 238 type: string | undefined; 239 value: number | undefined; 240 startNs: number | undefined; 241 dur: number | undefined; 242 243 sensorType: number | undefined; 244 pkg_name: string | undefined; 245 deviceState: number | undefined; 246 deviceType: number | undefined; 247 248 static draw( 249 energyStateContext: CanvasRenderingContext2D, 250 data: EnergyStateStruct, 251 maxState: number, 252 maxStateName: string 253 ) { 254 if (data.frame) { 255 let width = data.frame.width || 0; 256 let drawColor = this.setDrawColor(data.type!); 257 energyStateContext.fillStyle = drawColor; 258 energyStateContext.strokeStyle = drawColor; 259 energyStateContext.globalAlpha = 1.0; 260 energyStateContext.lineWidth = 1; 261 let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxState); 262 if (maxStateName === 'enable' || maxStateName === 'disable') { 263 if (data.value == 0) { 264 drawHeight = data.frame.height; 265 energyStateContext.fillRect(data.frame.x, data.frame.y + 4, width, data.frame.height); 266 } 267 } else { 268 energyStateContext.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); 269 } 270 if (data.startNs === EnergyStateStruct.hoverEnergyStateStruct?.startNs) { 271 let pointy = data.frame.y + data.frame.height + 4; 272 if (data.value == 0) { 273 pointy -= drawHeight; 274 } 275 energyStateContext.beginPath(); 276 energyStateContext.arc(data.frame.x, pointy, 3, 0, 2 * Math.PI, true); 277 energyStateContext.fill(); 278 energyStateContext.globalAlpha = 1.0; 279 energyStateContext.stroke(); 280 energyStateContext.beginPath(); 281 energyStateContext.moveTo(data.frame.x + 3, pointy); 282 energyStateContext.lineWidth = 3; 283 energyStateContext.lineTo(data.frame.x + width, pointy); 284 energyStateContext.stroke(); 285 } 286 } 287 energyStateContext.globalAlpha = 1.0; 288 energyStateContext.lineWidth = 1; 289 } 290 291 static setStateFrame(stateNode: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { 292 let stateStartPointX: number, stateEndPointX: number; 293 294 if ((stateNode.startNs || 0) < startNS) { 295 stateStartPointX = 0; 296 } else { 297 stateStartPointX = ns2x(stateNode.startNs || 0, startNS, endNS, totalNS, frame); 298 } 299 if ((stateNode.startNs || 0) + (stateNode.dur || 0) > endNS) { 300 stateEndPointX = frame.width; 301 } else { 302 stateEndPointX = ns2x((stateNode.startNs || 0) + (stateNode.dur || 0), startNS, endNS, totalNS, frame); 303 } 304 let frameWidth: number = stateEndPointX - stateStartPointX <= 1 ? 1 : stateEndPointX - stateStartPointX; 305 if (!stateNode.frame) { 306 stateNode.frame = {}; 307 } 308 stateNode.frame.x = Math.floor(stateStartPointX); 309 stateNode.frame.y = frame.y + padding; 310 stateNode.frame.width = Math.ceil(frameWidth); 311 stateNode.frame.height = Math.floor(frame.height - padding * 2); 312 } 313 314 static setDrawColor(eventType: string): string { 315 switch (eventType) { 316 case 'BRIGHTNESS_NIT': 317 return '#92D6CC'; 318 case 'SIGNAL_LEVEL': 319 return '#61CFBE'; 320 case 'WIFI_EVENT_RECEIVED': 321 return '#46B1E3'; 322 case 'AUDIO_STREAM_CHANGE': 323 return '#ED6F21'; 324 case 'WIFI_STATE': 325 return '#61CFBE'; 326 case 'LOCATION_SWITCH_STATE': 327 return '#61CFBE'; 328 case 'SENSOR_STATE': 329 return '#61CFBE'; 330 default: 331 return '#61CFBE'; 332 } 333 } 334} 335