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