1/*
2 * Copyright (C) 2024 Shenzhen Kaihong Digital Industry Development 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, dataFilterHandler, drawLoadingFrame, drawString, isFrameContainPoint, Render } from './ProcedureWorkerCommon';
17import { TraceRow } from '../../component/trace/base/TraceRow';
18import { SpSystemTrace } from '../../component/SpSystemTrace';
19import { HangType } from '../../component/chart/SpHangChart';
20
21/// Render类 用于处理Hang子泳道的绘制逻辑
22export class HangRender extends Render {
23  renderMainThread(
24    hangReq: {
25      context: CanvasRenderingContext2D;
26      useCache: boolean;
27      type: string;
28      index: number;
29    },
30    row: TraceRow<HangStruct>,
31  ): void {
32    HangStruct.index = hangReq.index;
33    let hangList = row.dataList;
34    let hangFilter = row.dataListCache;
35    let filterConfig = {
36      startKey: 'startNS',
37      durKey: 'dur',
38      startNS: TraceRow.range?.startNS ?? 0,
39      endNS: TraceRow.range?.endNS ?? 0,
40      totalNS: TraceRow.range?.totalNS ?? 0,
41      frame: row.frame,
42      paddingTop: 2,
43      useCache: hangReq.useCache || !(TraceRow.range?.refresh ?? false),
44    };
45    dataFilterHandler(hangList, hangFilter, filterConfig);
46    drawLoadingFrame(hangReq.context, hangFilter, row);
47    hangReq.context.beginPath();
48    let find = false;
49    for (let re of hangFilter) {
50      HangStruct.draw(hangReq.context, re);
51      if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
52        HangStruct.hoverHangStruct = re;
53        find = true;
54      }
55    }
56    if (!find && row.isHover) {
57      HangStruct.hoverHangStruct = undefined;
58    }
59    hangReq.context.closePath();
60  }
61}
62
63export function HangStructOnClick(clickRowType: string, sp: SpSystemTrace, scrollCallback: Function): Promise<unknown> {
64  return new Promise((resolve, reject) => {
65    if ((clickRowType === TraceRow.ROW_TYPE_HANG || clickRowType === TraceRow.ROW_TYPE_HANG_INNER) && HangStruct.hoverHangStruct) {
66      HangStruct.selectHangStruct = HangStruct.hoverHangStruct;
67      sp.traceSheetEL?.displayHangData(HangStruct.selectHangStruct, sp, scrollCallback);
68      sp.timerShaftEL?.modifyFlagList(undefined);
69      reject(new Error());
70    } else {
71      resolve(null);
72    }
73  });
74}
75
76/// BaseStruct类 存储每个Hang事件详细信息 管理Hang色块绘制细节
77export class HangStruct extends BaseStruct {
78  static hoverHangStruct: HangStruct | undefined;
79  static selectHangStruct: HangStruct | undefined;
80  static index = 0;
81  id: number | undefined;
82  startNS: number | undefined;
83  dur: number | undefined;
84  tid: number | undefined;
85  pid: number | undefined;
86  // 手动补充 按时间分类
87  type: HangType | undefined;
88  // 手动补充
89  pname: string | undefined;
90  // 手动补充 在tab页中需要手动解析内容
91  content: string | undefined;
92  name: string | undefined;
93
94  static getFrameColor(data: HangStruct): string {
95    return ({
96      'Instant': '#559CFF',
97      'Circumstantial': '#E8BE44',
98      'Micro': '#FEB354',
99      'Severe': '#FC7470',
100      '': '',
101    })[data.type!];
102  }
103
104  static draw(ctx: CanvasRenderingContext2D, data: HangStruct): void {
105    if (data.frame) {
106      ctx.fillStyle = HangStruct.getFrameColor(data);
107      ctx.strokeStyle = HangStruct.getFrameColor(data);
108
109      ctx.globalAlpha = 1;
110      ctx.lineWidth = 1;
111
112      if (data === HangStruct.hoverHangStruct) {
113        ctx.globalAlpha = 0.7;
114      }
115
116      ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, data.frame.height);
117      if (data.frame.width > 10) {
118        ctx.fillStyle = '#000';
119        drawString(ctx, `${data.type || ''}`, 1, data.frame, data);
120      }
121
122      if (data === HangStruct.selectHangStruct && HangStruct.equals(HangStruct.selectHangStruct, data)) {
123        ctx.strokeStyle = '#000';
124        ctx.lineWidth = 2;
125        ctx.strokeRect(
126          data.frame.x + 1,
127          data.frame.y + 1,
128          data.frame.width - 2,
129          data.frame.height - 2,
130        );
131      }
132
133      ctx.globalAlpha = 1;
134    }
135  }
136
137  static isHover(data: HangStruct): boolean {
138    return data === HangStruct.hoverHangStruct || data === HangStruct.selectHangStruct;
139  }
140  static equals(d1: HangStruct, d2: HangStruct): boolean {
141    return (
142      d1 &&
143      d2 &&
144      d1.pid === d2.pid &&
145      d1.tid === d2.tid &&
146      d1.pname === d2.pname &&
147      d1.startNS === d2.startNS &&
148      d1.dur === d2.dur &&
149      d1.type === d2.type &&
150      d1.id === d2.id &&
151      d1.name === d2.name
152    );
153  }
154}
155