• 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 { BaseStruct, drawLoadingFrame, isFrameContainPoint, Rect, Render, ns2x } from './ProcedureWorkerCommon';
17import { TraceRow } from '../../component/trace/base/TraceRow';
18import { ColorUtils } from '../../component/trace/base/ColorUtils';
19import { SpSystemTrace } from '../../component/SpSystemTrace';
20
21export class XpowerWifiRender extends Render {
22  renderMainThread(
23    xpowerWifiReq: {
24      context: CanvasRenderingContext2D;
25      useCache: boolean;
26      name: string;
27    },
28    row: TraceRow<XpowerWifiStruct>
29  ): void {
30    // offsetW控制图例的横向偏移量 确保图例不超过画布边界 因收藏和非收藏时泳道的宽度不一致 offsetW根据情况调整
31    let offsetW: number = row.collect ? 40 : 260;
32    let checkedType = row.rowSettingCheckedBoxList;
33    let xpowerWifiList = row.dataListCache.map((item) => ({ ...item }));
34    xpowerWifiList.forEach((item) => {
35      if (!checkedType![0]) {
36        item.tx = 0;
37      }
38      if (!checkedType![1]) {
39        item.rx = 0;
40      }
41    });
42    setDataFrameAndHoverHtml(xpowerWifiList, row, xpowerWifiReq.name);
43    drawLoadingFrame(xpowerWifiReq.context, xpowerWifiList, row);
44    setMaxInfo(xpowerWifiReq.context, xpowerWifiList, xpowerWifiReq.name);
45    xpowerWifiReq.context.beginPath();
46    let find = false;
47    for (let re of xpowerWifiList) {
48      XpowerWifiStruct.draw(xpowerWifiReq, re, row, isFrameContainPoint(re.frame!, row.hoverX, row.hoverY));
49      if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
50        xpowerWifiReq.name === 'WIFIPackets'
51          ? (XpowerWifiStruct.hoverPacketsStruct = re)
52          : (XpowerWifiStruct.hoverBytesStruct = re);
53        find = true;
54      }
55    }
56    if (!find) {
57      xpowerWifiReq.name === 'WIFIPackets'
58        ? (XpowerWifiStruct.hoverPacketsStruct = undefined)
59        : (XpowerWifiStruct.hoverBytesStruct = undefined);
60    }
61    xpowerWifiReq.context.closePath();
62    let spApplication = document.getElementsByTagName('sp-application')[0];
63    let isDark = spApplication.hasAttribute('dark');
64    drawLegend(xpowerWifiReq, checkedType!, offsetW, isDark);
65  }
66}
67
68function setDataFrameAndHoverHtml(filter: XpowerWifiStruct[], row: TraceRow<XpowerWifiStruct>, name: string): void {
69  filter.forEach((item) => {
70    XpowerWifiStruct.setXPowerStatisticFrame(
71      item,
72      5,
73      TraceRow.range?.startNS ?? 0,
74      TraceRow.range?.endNS ?? 0,
75      TraceRow.range?.totalNS ?? 0,
76      row.frame
77    );
78    if ((name === 'WIFIPackets' && !item.hoverHtmlPackets) || (name === 'WIFIBytes' && !item.hoverHtmlBytes)) {
79      XpowerWifiStruct.setHoverHtml(item, name);
80    }
81  });
82}
83
84export function drawLegend(
85  req: { context: CanvasRenderingContext2D; useCache: boolean; name: string },
86  checkedType: boolean[],
87  offsetW: number,
88  isDark?: boolean
89): void {
90  let textList: string[] = [];
91  checkedType[0] && textList.push('tx');
92  checkedType[1] && textList.push('rx');
93  for (let index = 0; index < textList.length; index++) {
94    let text = req.context.measureText(textList[index]);
95    req.context.fillStyle = textList[index] === 'tx' ? ColorUtils.colorForTid(index) : ColorUtils.colorForTid(10);
96    req.context.globalAlpha = 1;
97    let canvasEndX = req.context.canvas.clientWidth - offsetW;
98    let textColor = isDark ? '#FFFFFF' : '#333';
99    if (index === 0) {
100      req!.context.fillRect(canvasEndX - textList.length * 60, 12, 8, 8);
101      req.context.globalAlpha = 0.8;
102      req.context.fillStyle = textColor;
103      req.context.textBaseline = 'middle';
104      req.context.fillText(textList[index], canvasEndX - textList.length * 60 + 10, 18);
105      XpowerWifiStruct.currentTextWidth = canvasEndX - textList.length * 60 + 40 + text.width;
106    } else {
107      req!.context.fillRect(XpowerWifiStruct.currentTextWidth, 12, 8, 8);
108      req.context.globalAlpha = 0.8;
109      req.context.fillStyle = textColor;
110      req.context.textBaseline = 'middle';
111      req!.context.fillText(textList[index], XpowerWifiStruct.currentTextWidth + 12, 18);
112      XpowerWifiStruct.currentTextWidth = XpowerWifiStruct.currentTextWidth + 40 + text.width;
113    }
114  }
115  req.context.fillStyle = '#333';
116}
117
118function setMaxInfo(context: CanvasRenderingContext2D, dataList: XpowerWifiStruct[], name: string): void {
119  let maxNumber = 0;
120  dataList.forEach((item) => {
121    item.total = item.rx + item.tx;
122    if (maxNumber < item.total) {
123      maxNumber = item.total;
124    }
125  });
126  XpowerWifiStruct.max = maxNumber;
127  let s = name === 'WIFIBytes' ? XpowerWifiStruct.max + ' B' : XpowerWifiStruct.max.toString();
128  let textMetrics = context.measureText(s);
129  context.globalAlpha = 0.8;
130  context.fillStyle = '#f0f0f0';
131  context.fillRect(0, 5, textMetrics.width + 8, 18);
132  context.globalAlpha = 1;
133  context.fillStyle = '#333';
134  context.textBaseline = 'middle';
135  context.fillText(s, 4, 5 + 9);
136}
137
138export function XpowerWifiBytesStructOnClick(
139  clickRowType: string,
140  sp: SpSystemTrace,
141  entry?: XpowerWifiStruct
142): Promise<unknown> {
143  return new Promise((resolve, reject) => {
144    if (clickRowType === TraceRow.ROW_TYPE_XPOWER_WIFI_BYTES && (XpowerWifiStruct.hoverBytesStruct || entry)) {
145      XpowerWifiStruct.selectBytesXpowerStruct = entry || XpowerWifiStruct.hoverBytesStruct;
146      sp.traceSheetEL?.displayXpowerBytesWifiData(XpowerWifiStruct.selectBytesXpowerStruct!);
147      sp.timerShaftEL?.modifyFlagList(undefined);
148      reject(new Error());
149    } else {
150      resolve(null);
151    }
152  });
153}
154
155export function XpowerWifiPacketsStructOnClick(
156  clickRowType: string,
157  sp: SpSystemTrace,
158  entry?: XpowerWifiStruct
159): Promise<unknown> {
160  return new Promise((resolve, reject) => {
161    if (clickRowType === TraceRow.ROW_TYPE_XPOWER_WIFI_PACKETS && (XpowerWifiStruct.hoverPacketsStruct || entry)) {
162      XpowerWifiStruct.selectPacketsXpowerStruct = entry || XpowerWifiStruct.hoverPacketsStruct;
163      sp.traceSheetEL?.displayXpowerWifiPacketsData(XpowerWifiStruct.selectPacketsXpowerStruct!);
164      sp.timerShaftEL?.modifyFlagList(undefined);
165      reject(new Error());
166    } else {
167      resolve(null);
168    }
169  });
170}
171
172export class XpowerWifiStruct extends BaseStruct {
173  static rowHeight: number = 100;
174  static currentTextWidth: number = 0;
175  startTime: number = 0;
176  rx: number = 0;
177  tx: number = 0;
178  static hoverPacketsStruct: XpowerWifiStruct | undefined;
179  static hoverBytesStruct: XpowerWifiStruct | undefined;
180  static selectPacketsXpowerStruct: XpowerWifiStruct | undefined;
181  static selectBytesXpowerStruct: XpowerWifiStruct | undefined;
182
183  hoverHtmlPackets: string = '';
184  hoverHtmlBytes: string = '';
185  total: number = 0;
186  static max: number = 0;
187
188  static draw(
189    req: { context: CanvasRenderingContext2D; useCache: boolean; name: string },
190    data: XpowerWifiStruct,
191    row: TraceRow<XpowerWifiStruct>,
192    ishover: boolean
193  ): void {
194    if (data.frame) {
195      req!.context.globalAlpha = 0.8;
196      req!.context.lineWidth = 1;
197      this.currentTextWidth = 0;
198      let txHeight = this.drawHistogram(req, data, -1, data.tx!, 'tx', row.frame);
199      let rxHeight = this.drawHistogram(req, data, txHeight, data.rx!, 'rx', row.frame);
200      let startNS = TraceRow.range!.startNS;
201      let endNS = TraceRow.range!.endNS;
202      let totalNS = TraceRow.range!.totalNS;
203      let hoverTime =
204        req.name === 'WIFIPackets'
205          ? XpowerWifiStruct.hoverPacketsStruct?.startTime
206          : XpowerWifiStruct.hoverBytesStruct?.startTime;
207      let selectTime =
208        req.name === 'WIFIPackets'
209          ? XpowerWifiStruct.selectPacketsXpowerStruct?.startTime
210          : XpowerWifiStruct.selectBytesXpowerStruct?.startTime;
211      if ((data.startTime === hoverTime && ishover) || data.startTime === selectTime) {
212        let endPointX = ns2x((data.startTime || 0) + 3000000000, startNS, endNS, totalNS, row.frame);
213        let startPointX = ns2x(data.startTime || 0, startNS, endNS, totalNS, row.frame);
214        let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX;
215        req.context.globalAlpha = 0.8;
216        req!.context.lineWidth = 2;
217        req.context.strokeStyle = '#9899a0';
218        req!.context.strokeRect(startPointX, rxHeight, frameWidth, data.frame.height);
219      }
220    }
221    req!.context.globalAlpha = 0.8;
222    req!.context.lineWidth = 1;
223  }
224
225  static drawHistogram(
226    req: { context: CanvasRenderingContext2D; useCache: boolean },
227    data: XpowerWifiStruct,
228    height: number,
229    itemValue: number,
230    type: string,
231    rowFrame: Rect
232  ): number {
233    let endPointX = ns2x(
234      data.startTime + 3000000000 || 0,
235      TraceRow.range!.startNS,
236      TraceRow.range!.endNS,
237      TraceRow.range!.totalNS,
238      rowFrame
239    );
240    let startPointX = ns2x(
241      data.startTime || 0,
242      TraceRow.range!.startNS,
243      TraceRow.range!.endNS,
244      TraceRow.range!.totalNS,
245      rowFrame
246    );
247    let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX;
248    let histogramColor = type === 'tx' ? ColorUtils.colorForTid(0) : ColorUtils.colorForTid(10);
249    req!.context.fillStyle = histogramColor;
250    let dataHeight: number = Math.floor(((itemValue || 0) * (this.rowHeight - 40)) / XpowerWifiStruct.max);
251    if (itemValue !== 0 && dataHeight < 10) {
252      dataHeight = 10;
253    }
254    let drawStartY = 0;
255    if (height === -1) {
256      drawStartY = data.frame!.y + this.rowHeight - dataHeight;
257      req!.context.fillRect(startPointX, drawStartY, frameWidth, dataHeight);
258      data.frame!.y = drawStartY;
259      data.frame!.height += dataHeight;
260      return drawStartY;
261    } else {
262      drawStartY = height - dataHeight;
263      req!.context.fillRect(startPointX, drawStartY, frameWidth, dataHeight);
264      if (type === 'rx') {
265        data.frame!.y = drawStartY;
266        data.frame!.height += dataHeight;
267        return drawStartY;
268      }
269      data.frame!.y = drawStartY;
270      data.frame!.height += dataHeight;
271      return dataHeight;
272    }
273  }
274
275  static setHoverHtml(node: XpowerWifiStruct, name: string): void {
276    let hoverHtml = '';
277    if (name === 'WIFIPackets') {
278      let hoverTx =
279        node.tx !== 0
280          ? `<div style="text-align: left">tx_packets:&nbsp;&nbsp;</div>
281      <div style="text-align: left">${node.tx}</div>`
282          : '';
283      let hoverRx =
284        node.rx !== 0
285          ? `<div style="text-align: left">rx_packets:&nbsp;&nbsp;</div>
286      <div style="text-align: left">${node.rx}</div>`
287          : '';
288      hoverHtml = `<div style="display: grid; width:auto; grid-template-columns: 1fr 1fr;">
289        ${hoverTx}
290        ${hoverRx}
291      </div>`;
292      node.hoverHtmlPackets = hoverHtml;
293    } else {
294      let hoverTx =
295        node.tx !== 0
296          ? `<div style="text-align: left">tx_bytes:&nbsp;&nbsp;</div>
297      <div style="text-align: left">${node.tx + ' B'}</div>`
298          : '';
299      let hoverRx =
300        node.rx !== 0
301          ? `<div style="text-align: left">rx_bytes:&nbsp;&nbsp;</div>
302      <div style="text-align: left">${node.rx + ' B'}</div>`
303          : '';
304      hoverHtml = `<div style="display: grid; width: auto; grid-template-columns: 1fr 1fr;">
305        ${hoverTx}
306        ${hoverRx}
307        </div>`;
308      node.hoverHtmlBytes = hoverHtml;
309    }
310  }
311
312  static setXPowerStatisticFrame(
313    node: XpowerWifiStruct,
314    padding: number,
315    startNS: number,
316    endNS: number,
317    totalNS: number,
318    frame: Rect
319  ): void {
320    let startPointX: number;
321    let endPointX: number;
322    if ((node.startTime || 0) < startNS) {
323      startPointX = 0;
324    } else {
325      startPointX = ns2x(node.startTime, startNS, endNS, totalNS, frame);
326    }
327    if (node.startTime + 3000000000 > endNS) {
328      endPointX = frame.width;
329    } else {
330      endPointX = ns2x(node.startTime + 3000000000, startNS, endNS, totalNS, frame);
331    }
332    let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX;
333    if (!node.frame) {
334      node.frame = new Rect(0, 0, 0, 0);
335    }
336    node.frame.x = Math.floor(startPointX);
337    node.frame.y = frame.y + padding;
338    node.frame.width = Math.ceil(frameWidth);
339    node.frame.height = Math.floor(frame.height - padding * 2);
340  }
341}
342