1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ci
16fb726d48Sopenharmony_ciimport { resizeCanvas } from '../helper';
17fb726d48Sopenharmony_ciimport { BaseElement, element } from '../../BaseElement';
18fb726d48Sopenharmony_ciimport { LitChartPieConfig } from './LitChartPieConfig';
19fb726d48Sopenharmony_ciimport { isPointIsCircle, pieChartColors, randomRgbColor } from './LitChartPieData';
20fb726d48Sopenharmony_ciimport { Utils } from '../../../trace/component/trace/base/Utils';
21fb726d48Sopenharmony_ci
22fb726d48Sopenharmony_ciinterface Rectangle {
23fb726d48Sopenharmony_ci  x: number;
24fb726d48Sopenharmony_ci  y: number;
25fb726d48Sopenharmony_ci  w: number;
26fb726d48Sopenharmony_ci  h: number;
27fb726d48Sopenharmony_ci}
28fb726d48Sopenharmony_ci
29fb726d48Sopenharmony_ciclass Sector {
30fb726d48Sopenharmony_ci  id?: unknown;
31fb726d48Sopenharmony_ci  obj?: unknown;
32fb726d48Sopenharmony_ci  key: unknown;
33fb726d48Sopenharmony_ci  value: unknown;
34fb726d48Sopenharmony_ci  startAngle?: number;
35fb726d48Sopenharmony_ci  endAngle?: number;
36fb726d48Sopenharmony_ci  startDegree?: number;
37fb726d48Sopenharmony_ci  endDegree?: number;
38fb726d48Sopenharmony_ci  color?: string;
39fb726d48Sopenharmony_ci  percent?: number;
40fb726d48Sopenharmony_ci  hover?: boolean;
41fb726d48Sopenharmony_ci  ease?: {
42fb726d48Sopenharmony_ci    initVal?: number;
43fb726d48Sopenharmony_ci    step?: number;
44fb726d48Sopenharmony_ci    process?: boolean;
45fb726d48Sopenharmony_ci  };
46fb726d48Sopenharmony_ci}
47fb726d48Sopenharmony_ci
48fb726d48Sopenharmony_ciconst initHtmlStyle = `
49fb726d48Sopenharmony_ci    <style>   
50fb726d48Sopenharmony_ci        :host {
51fb726d48Sopenharmony_ci            display: flex;
52fb726d48Sopenharmony_ci            flex-direction: column;
53fb726d48Sopenharmony_ci            overflow: hidden;
54fb726d48Sopenharmony_ci            width: 100%;
55fb726d48Sopenharmony_ci            height: 100%;
56fb726d48Sopenharmony_ci        }
57fb726d48Sopenharmony_ci        .shape.active {
58fb726d48Sopenharmony_ci            animation: color 3.75 both;    
59fb726d48Sopenharmony_ci        }
60fb726d48Sopenharmony_ci        @keyframes color {
61fb726d48Sopenharmony_ci            0% { background-color: white; }
62fb726d48Sopenharmony_ci           100% { background-color: black; }    
63fb726d48Sopenharmony_ci        }
64fb726d48Sopenharmony_ci        #tip{
65fb726d48Sopenharmony_ci            background-color: #f5f5f4;
66fb726d48Sopenharmony_ci            border: 1px solid #fff;
67fb726d48Sopenharmony_ci            border-radius: 5px;
68fb726d48Sopenharmony_ci            color: #333322;
69fb726d48Sopenharmony_ci            font-size: 8pt;
70fb726d48Sopenharmony_ci            position: absolute;
71fb726d48Sopenharmony_ci            display: none;
72fb726d48Sopenharmony_ci            top: 0;
73fb726d48Sopenharmony_ci            left: 0;
74fb726d48Sopenharmony_ci            z-index: 99;
75fb726d48Sopenharmony_ci            pointer-events: none;
76fb726d48Sopenharmony_ci            user-select: none;
77fb726d48Sopenharmony_ci            padding: 5px 10px;
78fb726d48Sopenharmony_ci            box-shadow: 0 0 10px #22ffffff;
79fb726d48Sopenharmony_ci        }
80fb726d48Sopenharmony_ci        #root{
81fb726d48Sopenharmony_ci            position:relative;
82fb726d48Sopenharmony_ci        }
83fb726d48Sopenharmony_ci        .bg_nodata{
84fb726d48Sopenharmony_ci            background-repeat:no-repeat;
85fb726d48Sopenharmony_ci            background-position:center;
86fb726d48Sopenharmony_ci            background-image: url("img/pie_chart_no_data.png");
87fb726d48Sopenharmony_ci        }
88fb726d48Sopenharmony_ci        .bg_hasdata{
89fb726d48Sopenharmony_ci            background-repeat:no-repeat;
90fb726d48Sopenharmony_ci            background-position:center;
91fb726d48Sopenharmony_ci        }
92fb726d48Sopenharmony_ci        
93fb726d48Sopenharmony_ci        #labels{
94fb726d48Sopenharmony_ci            display: grid;
95fb726d48Sopenharmony_ci            grid-template-columns: auto auto auto auto auto;
96fb726d48Sopenharmony_ci            /*justify-content: center;*/
97fb726d48Sopenharmony_ci            /*align-items: center;*/
98fb726d48Sopenharmony_ci            width: 100%;
99fb726d48Sopenharmony_ci            height: 25%;
100fb726d48Sopenharmony_ci            box-sizing: border-box;
101fb726d48Sopenharmony_ci            position: absolute;
102fb726d48Sopenharmony_ci            bottom: 0px;
103fb726d48Sopenharmony_ci            left: 0;
104fb726d48Sopenharmony_ci            /*margin: 0px 10px;*/
105fb726d48Sopenharmony_ci            padding-left: 10px;
106fb726d48Sopenharmony_ci            padding-right: 10px;
107fb726d48Sopenharmony_ci            pointer-events: none    ;
108fb726d48Sopenharmony_ci        }
109fb726d48Sopenharmony_ci        .name{
110fb726d48Sopenharmony_ci            flex: 1;
111fb726d48Sopenharmony_ci            font-size: 9pt;
112fb726d48Sopenharmony_ci            overflow: hidden;
113fb726d48Sopenharmony_ci            white-space: nowrap;
114fb726d48Sopenharmony_ci            text-overflow: ellipsis;
115fb726d48Sopenharmony_ci            /*color: #666;*/
116fb726d48Sopenharmony_ci            color: var(--dark-color1,#252525);
117fb726d48Sopenharmony_ci            pointer-events: painted;
118fb726d48Sopenharmony_ci        }
119fb726d48Sopenharmony_ci        .label{
120fb726d48Sopenharmony_ci            display: flex;
121fb726d48Sopenharmony_ci            align-items: center;
122fb726d48Sopenharmony_ci            max-lines: 1;
123fb726d48Sopenharmony_ci            white-space: nowrap;
124fb726d48Sopenharmony_ci            overflow: hidden;
125fb726d48Sopenharmony_ci            padding-right: 5px;
126fb726d48Sopenharmony_ci        }
127fb726d48Sopenharmony_ci        .tag{
128fb726d48Sopenharmony_ci            display: flex;
129fb726d48Sopenharmony_ci            align-items: center;
130fb726d48Sopenharmony_ci            justify-content: center;
131fb726d48Sopenharmony_ci            width: 10px;
132fb726d48Sopenharmony_ci            height: 10px;
133fb726d48Sopenharmony_ci            border-radius: 5px;
134fb726d48Sopenharmony_ci            margin-right: 5px;
135fb726d48Sopenharmony_ci        }
136fb726d48Sopenharmony_ci        </style>
137fb726d48Sopenharmony_ci    `;
138fb726d48Sopenharmony_ci
139fb726d48Sopenharmony_ci@element('lit-chart-pie')
140fb726d48Sopenharmony_ciexport class LitChartPie extends BaseElement {
141fb726d48Sopenharmony_ci  private eleShape: Element | null | undefined;
142fb726d48Sopenharmony_ci  private pieTipEL: HTMLDivElement | null | undefined;
143fb726d48Sopenharmony_ci  private labelsEL: HTMLDivElement | null | undefined;
144fb726d48Sopenharmony_ci  canvas: HTMLCanvasElement | undefined | null;
145fb726d48Sopenharmony_ci  ctx: CanvasRenderingContext2D | undefined | null;
146fb726d48Sopenharmony_ci  litChartPieConfig: LitChartPieConfig | null | undefined;
147fb726d48Sopenharmony_ci  centerX: number | null | undefined;
148fb726d48Sopenharmony_ci  centerY: number | null | undefined;
149fb726d48Sopenharmony_ci  data: Sector[] = [];
150fb726d48Sopenharmony_ci  radius: number | undefined;
151fb726d48Sopenharmony_ci  private textRects: Rectangle[] = [];
152fb726d48Sopenharmony_ci
153fb726d48Sopenharmony_ci  set config(litChartPieCfg: LitChartPieConfig | null | undefined) {
154fb726d48Sopenharmony_ci    if (!litChartPieCfg) {
155fb726d48Sopenharmony_ci      return;
156fb726d48Sopenharmony_ci    }
157fb726d48Sopenharmony_ci    this.litChartPieConfig = litChartPieCfg;
158fb726d48Sopenharmony_ci    this.measure();
159fb726d48Sopenharmony_ci    this.render();
160fb726d48Sopenharmony_ci    (this.shadowRoot!.querySelector('#root') as HTMLDivElement).className =
161fb726d48Sopenharmony_ci    this.data.length > 0 ? 'bg_hasdata' : 'bg_nodata';
162fb726d48Sopenharmony_ci  }
163fb726d48Sopenharmony_ci
164fb726d48Sopenharmony_ci  set dataSource(litChartPieArr: unknown[]) {
165fb726d48Sopenharmony_ci    if (this.litChartPieConfig) {
166fb726d48Sopenharmony_ci      this.litChartPieConfig.data = litChartPieArr;
167fb726d48Sopenharmony_ci      this.measure();
168fb726d48Sopenharmony_ci      this.render();
169fb726d48Sopenharmony_ci    }
170fb726d48Sopenharmony_ci  }
171fb726d48Sopenharmony_ci
172fb726d48Sopenharmony_ci  showHover(): void {
173fb726d48Sopenharmony_ci    let hasHover = false;
174fb726d48Sopenharmony_ci    this.data.forEach((it) => {
175fb726d48Sopenharmony_ci      // @ts-ignore
176fb726d48Sopenharmony_ci      it.hover = it.obj.isHover;
177fb726d48Sopenharmony_ci      if (it.hover) {
178fb726d48Sopenharmony_ci        hasHover = true;
179fb726d48Sopenharmony_ci      }
180fb726d48Sopenharmony_ci      this.updateHoverItemStatus(it);
181fb726d48Sopenharmony_ci      if (it.hover) {
182fb726d48Sopenharmony_ci        if (this.centerX && this.centerX > 0 && this.centerY && this.centerY > 0) { 
183fb726d48Sopenharmony_ci          this.showTip(
184fb726d48Sopenharmony_ci            this.centerX - 40 || 0,
185fb726d48Sopenharmony_ci            this.centerY || 0,
186fb726d48Sopenharmony_ci            this.litChartPieConfig!.tip ? this.litChartPieConfig!.tip(it) : `${it.key}: ${it.value}`
187fb726d48Sopenharmony_ci          );
188fb726d48Sopenharmony_ci        }
189fb726d48Sopenharmony_ci      }
190fb726d48Sopenharmony_ci    });
191fb726d48Sopenharmony_ci    if (!hasHover) {
192fb726d48Sopenharmony_ci      this.hideTip();
193fb726d48Sopenharmony_ci    }
194fb726d48Sopenharmony_ci    this.render();
195fb726d48Sopenharmony_ci  }
196fb726d48Sopenharmony_ci
197fb726d48Sopenharmony_ci  measureInitialize(): void {
198fb726d48Sopenharmony_ci    this.data = [];
199fb726d48Sopenharmony_ci    this.radius = (Math.min(this.clientHeight, this.clientWidth) * 0.65) / 2 - 10;
200fb726d48Sopenharmony_ci    this.labelsEL!.textContent = '';
201fb726d48Sopenharmony_ci  }
202fb726d48Sopenharmony_ci
203fb726d48Sopenharmony_ci  measure(): void {
204fb726d48Sopenharmony_ci    if (!this.litChartPieConfig) {
205fb726d48Sopenharmony_ci      return;
206fb726d48Sopenharmony_ci    }
207fb726d48Sopenharmony_ci    this.measureInitialize();
208fb726d48Sopenharmony_ci    let pieCfg = this.litChartPieConfig!;
209fb726d48Sopenharmony_ci    let startAngle = 0;
210fb726d48Sopenharmony_ci    let startDegree = 0;
211fb726d48Sopenharmony_ci    let full = Math.PI / 180; //每度
212fb726d48Sopenharmony_ci    let fullDegree = 0; //每度
213fb726d48Sopenharmony_ci    let sum = this.litChartPieConfig.data.reduce(
214fb726d48Sopenharmony_ci      // @ts-ignore
215fb726d48Sopenharmony_ci      (previousValue, currentValue) => currentValue[pieCfg.angleField] + previousValue,
216fb726d48Sopenharmony_ci      0
217fb726d48Sopenharmony_ci    );
218fb726d48Sopenharmony_ci    let labelArray: string[] = [];
219fb726d48Sopenharmony_ci    sum && this.litChartPieConfig.data.forEach((pieItem, index) => {
220fb726d48Sopenharmony_ci      let item: Sector = {
221fb726d48Sopenharmony_ci        id: `id-${Utils.uuid()}`,
222fb726d48Sopenharmony_ci        color: this.litChartPieConfig!.label.color
223fb726d48Sopenharmony_ci          ? // @ts-ignore
224fb726d48Sopenharmony_ci            this.litChartPieConfig!.label.color(pieItem)
225fb726d48Sopenharmony_ci          : pieChartColors[index % pieChartColors.length],
226fb726d48Sopenharmony_ci        obj: pieItem, // @ts-ignore
227fb726d48Sopenharmony_ci        key: pieItem[pieCfg.colorField], // @ts-ignore
228fb726d48Sopenharmony_ci        value: pieItem[pieCfg.angleField],
229fb726d48Sopenharmony_ci        startAngle: startAngle, // @ts-ignore
230fb726d48Sopenharmony_ci        endAngle: startAngle + full * ((pieItem[pieCfg.angleField] / sum) * 360),
231fb726d48Sopenharmony_ci        startDegree: startDegree, // @ts-ignore
232fb726d48Sopenharmony_ci        endDegree: startDegree + fullDegree + (pieItem[pieCfg.angleField] / sum) * 360,
233fb726d48Sopenharmony_ci        ease: {
234fb726d48Sopenharmony_ci          initVal: 0, // @ts-ignore
235fb726d48Sopenharmony_ci          step: (startAngle + full * ((pieItem[pieCfg.angleField] / sum) * 360)) / startDegree,
236fb726d48Sopenharmony_ci          process: true,
237fb726d48Sopenharmony_ci        },
238fb726d48Sopenharmony_ci      };
239fb726d48Sopenharmony_ci      this.data.push(item); // @ts-ignore
240fb726d48Sopenharmony_ci      startAngle += full * ((pieItem[pieCfg.angleField] / sum) * 360); // @ts-ignore
241fb726d48Sopenharmony_ci      startDegree += fullDegree + (pieItem[pieCfg.angleField] / sum) * 360; // @ts-ignore
242fb726d48Sopenharmony_ci      let colorFieldValue = item.obj[pieCfg.colorField];
243fb726d48Sopenharmony_ci      if (this.config?.colorFieldTransferHandler) {
244fb726d48Sopenharmony_ci        colorFieldValue = this.config.colorFieldTransferHandler(colorFieldValue);
245fb726d48Sopenharmony_ci      }
246fb726d48Sopenharmony_ci      labelArray.push(`<label class="label">
247fb726d48Sopenharmony_ci                    <div style="display: flex;flex-direction: row;margin-left: 5px;align-items: center;overflow: hidden;text-overflow: ellipsis" 
248fb726d48Sopenharmony_ci                        id="${item.id}">
249fb726d48Sopenharmony_ci                        <div class="tag" style="background-color: ${item.color}"></div>
250fb726d48Sopenharmony_ci                        <span class="name">${colorFieldValue}</span>
251fb726d48Sopenharmony_ci                    </div>
252fb726d48Sopenharmony_ci                </label>`);
253fb726d48Sopenharmony_ci    });
254fb726d48Sopenharmony_ci    this.labelsEL!.innerHTML = labelArray.join('');
255fb726d48Sopenharmony_ci  }
256fb726d48Sopenharmony_ci
257fb726d48Sopenharmony_ci  get config(): LitChartPieConfig | null | undefined {
258fb726d48Sopenharmony_ci    return this.litChartPieConfig;
259fb726d48Sopenharmony_ci  }
260fb726d48Sopenharmony_ci
261fb726d48Sopenharmony_ci  addCanvasOnmousemoveEvent(): void {
262fb726d48Sopenharmony_ci    this.canvas!.onmousemove = (ev): void => {
263fb726d48Sopenharmony_ci      let rect = this.getBoundingClientRect();
264fb726d48Sopenharmony_ci      let x = ev.pageX - rect.left - this.centerX!;
265fb726d48Sopenharmony_ci      let y = ev.pageY - rect.top - this.centerY!;
266fb726d48Sopenharmony_ci      if (isPointIsCircle(0, 0, x, y, this.radius!)) {
267fb726d48Sopenharmony_ci        let degree = this.computeDegree(x, y);
268fb726d48Sopenharmony_ci        this.data.forEach((it) => {
269fb726d48Sopenharmony_ci          it.hover = degree >= it.startDegree! && degree <= it.endDegree!;
270fb726d48Sopenharmony_ci          this.updateHoverItemStatus(it); // @ts-ignore
271fb726d48Sopenharmony_ci          it.obj.isHover = it.hover;
272fb726d48Sopenharmony_ci          if (it.hover && this.litChartPieConfig) {
273fb726d48Sopenharmony_ci            this.litChartPieConfig.hoverHandler?.(it.obj);
274fb726d48Sopenharmony_ci            this.showTip(
275fb726d48Sopenharmony_ci              ev.pageX - rect.left > this.centerX! ? ev.pageX - rect.left - 165 : ev.pageX - rect.left + 10,
276fb726d48Sopenharmony_ci              ev.pageY - this.offsetTop > this.centerY! ? ev.pageY - this.offsetTop - 50 : ev.pageY + (this.offsetTop - rect.top) - this.offsetTop + 20,
277fb726d48Sopenharmony_ci              this.litChartPieConfig.tip ? this.litChartPieConfig!.tip(it) : `${it.key}: ${it.value}`
278fb726d48Sopenharmony_ci            );
279fb726d48Sopenharmony_ci          }
280fb726d48Sopenharmony_ci        });
281fb726d48Sopenharmony_ci      } else {
282fb726d48Sopenharmony_ci        this.hideTip();
283fb726d48Sopenharmony_ci        this.data.forEach((it) => {
284fb726d48Sopenharmony_ci          it.hover = false; // @ts-ignore
285fb726d48Sopenharmony_ci          it.obj.isHover = false;
286fb726d48Sopenharmony_ci          this.updateHoverItemStatus(it);
287fb726d48Sopenharmony_ci        });
288fb726d48Sopenharmony_ci        this.litChartPieConfig?.hoverHandler?.(undefined);
289fb726d48Sopenharmony_ci      }
290fb726d48Sopenharmony_ci      this.render();
291fb726d48Sopenharmony_ci    };
292fb726d48Sopenharmony_ci  }
293fb726d48Sopenharmony_ci  connectedCallback(): void {
294fb726d48Sopenharmony_ci    super.connectedCallback();
295fb726d48Sopenharmony_ci    this.eleShape = this.shadowRoot!.querySelector<Element>('#shape');
296fb726d48Sopenharmony_ci    this.pieTipEL = this.shadowRoot!.querySelector<HTMLDivElement>('#tip');
297fb726d48Sopenharmony_ci    this.labelsEL = this.shadowRoot!.querySelector<HTMLDivElement>('#labels');
298fb726d48Sopenharmony_ci    this.canvas = this.shadowRoot!.querySelector<HTMLCanvasElement>('#canvas');
299fb726d48Sopenharmony_ci    this.ctx = this.canvas!.getContext('2d', { alpha: true });
300fb726d48Sopenharmony_ci    resizeCanvas(this.canvas!);
301fb726d48Sopenharmony_ci    this.radius = (Math.min(this.clientHeight, this.clientWidth) * 0.65) / 2 - 10;
302fb726d48Sopenharmony_ci    this.centerX = this.clientWidth / 2;
303fb726d48Sopenharmony_ci    this.centerY = this.clientHeight / 2 - 40;
304fb726d48Sopenharmony_ci    this.ctx?.translate(this.centerX, this.centerY);
305fb726d48Sopenharmony_ci    this.canvas!.onmouseout = (e): void => {
306fb726d48Sopenharmony_ci      this.hideTip();
307fb726d48Sopenharmony_ci      this.data.forEach((it) => {
308fb726d48Sopenharmony_ci        it.hover = false;
309fb726d48Sopenharmony_ci        this.updateHoverItemStatus(it);
310fb726d48Sopenharmony_ci      });
311fb726d48Sopenharmony_ci      this.render();
312fb726d48Sopenharmony_ci    };
313fb726d48Sopenharmony_ci    //增加点击事件
314fb726d48Sopenharmony_ci    this.canvas!.onclick = (ev): void => {
315fb726d48Sopenharmony_ci      let rect = this.getBoundingClientRect();
316fb726d48Sopenharmony_ci      let x = ev.pageX - rect.left - this.centerX!;
317fb726d48Sopenharmony_ci      let y = ev.pageY - rect.top - this.centerY!;
318fb726d48Sopenharmony_ci      if (isPointIsCircle(0, 0, x, y, this.radius!)) {
319fb726d48Sopenharmony_ci        let degree = this.computeDegree(x, y);
320fb726d48Sopenharmony_ci        this.data.forEach((it) => {
321fb726d48Sopenharmony_ci          if (degree >= it.startDegree! && degree <= it.endDegree!) {
322fb726d48Sopenharmony_ci            // @ts-ignore
323fb726d48Sopenharmony_ci            this.config?.angleClick?.(it.obj);
324fb726d48Sopenharmony_ci          }
325fb726d48Sopenharmony_ci        });
326fb726d48Sopenharmony_ci      }
327fb726d48Sopenharmony_ci    };
328fb726d48Sopenharmony_ci    this.addCanvasOnmousemoveEvent();
329fb726d48Sopenharmony_ci    this.render();
330fb726d48Sopenharmony_ci  }
331fb726d48Sopenharmony_ci
332fb726d48Sopenharmony_ci  updateHoverItemStatus(item: unknown): void {
333fb726d48Sopenharmony_ci    // @ts-ignore
334fb726d48Sopenharmony_ci    let label = this.shadowRoot!.querySelector(`#${item.id}`);
335fb726d48Sopenharmony_ci    if (label) {
336fb726d48Sopenharmony_ci      // @ts-ignore
337fb726d48Sopenharmony_ci      (label as HTMLLabelElement).style.boxShadow = item.hover ? '0 0 5px #22ffffff' : '';
338fb726d48Sopenharmony_ci    }
339fb726d48Sopenharmony_ci  }
340fb726d48Sopenharmony_ci
341fb726d48Sopenharmony_ci  computeDegree(x: number, y: number): number {
342fb726d48Sopenharmony_ci    let degree = (360 * Math.atan(y / x)) / (2 * Math.PI);
343fb726d48Sopenharmony_ci    if (x >= 0 && y >= 0) {
344fb726d48Sopenharmony_ci      degree = degree;
345fb726d48Sopenharmony_ci    } else if (x < 0 && y >= 0) {
346fb726d48Sopenharmony_ci      degree = 180 + degree;
347fb726d48Sopenharmony_ci    } else if (x < 0 && y < 0) {
348fb726d48Sopenharmony_ci      degree = 180 + degree;
349fb726d48Sopenharmony_ci    } else {
350fb726d48Sopenharmony_ci      degree = 270 + (90 + degree);
351fb726d48Sopenharmony_ci    }
352fb726d48Sopenharmony_ci    return degree;
353fb726d48Sopenharmony_ci  }
354fb726d48Sopenharmony_ci
355fb726d48Sopenharmony_ci  initElements(): void {
356fb726d48Sopenharmony_ci    new ResizeObserver((entries, observer) => {
357fb726d48Sopenharmony_ci      entries.forEach((it) => {
358fb726d48Sopenharmony_ci        resizeCanvas(this.canvas!);
359fb726d48Sopenharmony_ci        this.centerX = this.clientWidth / 2;
360fb726d48Sopenharmony_ci        this.centerY = this.clientHeight / 2 - 40;
361fb726d48Sopenharmony_ci        this.ctx?.translate(this.centerX, this.centerY);
362fb726d48Sopenharmony_ci        this.measure();
363fb726d48Sopenharmony_ci        this.render();
364fb726d48Sopenharmony_ci      });
365fb726d48Sopenharmony_ci    }).observe(this);
366fb726d48Sopenharmony_ci  }
367fb726d48Sopenharmony_ci
368fb726d48Sopenharmony_ci  handleData(): void {
369fb726d48Sopenharmony_ci    this.textRects = [];
370fb726d48Sopenharmony_ci    if (this.litChartPieConfig!.showChartLine) {
371fb726d48Sopenharmony_ci      this.data.forEach((dataItem) => {
372fb726d48Sopenharmony_ci        let text = `${dataItem.value}`;
373fb726d48Sopenharmony_ci        let metrics = this.ctx!.measureText(text);
374fb726d48Sopenharmony_ci        let textWidth = metrics.width;
375fb726d48Sopenharmony_ci        let textHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
376fb726d48Sopenharmony_ci        this.ctx!.beginPath();
377fb726d48Sopenharmony_ci        this.ctx!.strokeStyle = dataItem.color!;
378fb726d48Sopenharmony_ci        this.ctx!.fillStyle = '#595959';
379fb726d48Sopenharmony_ci        let deg = dataItem.startDegree! + (dataItem.endDegree! - dataItem.startDegree!) / 2;
380fb726d48Sopenharmony_ci        let dep = 25;
381fb726d48Sopenharmony_ci        let x1 = 0 + this.radius! * Math.cos((deg * Math.PI) / 180);
382fb726d48Sopenharmony_ci        let y1 = 0 + this.radius! * Math.sin((deg * Math.PI) / 180);
383fb726d48Sopenharmony_ci        let x2 = 0 + (this.radius! + 13) * Math.cos((deg * Math.PI) / 180);
384fb726d48Sopenharmony_ci        let y2 = 0 + (this.radius! + 13) * Math.sin((deg * Math.PI) / 180);
385fb726d48Sopenharmony_ci        let x3 = 0 + (this.radius! + dep) * Math.cos((deg * Math.PI) / 180);
386fb726d48Sopenharmony_ci        let y3 = 0 + (this.radius! + dep) * Math.sin((deg * Math.PI) / 180);
387fb726d48Sopenharmony_ci        this.ctx!.moveTo(x1, y1);
388fb726d48Sopenharmony_ci        this.ctx!.lineTo(x2, y2);
389fb726d48Sopenharmony_ci        this.ctx!.stroke();
390fb726d48Sopenharmony_ci        let rect = this.correctRect({
391fb726d48Sopenharmony_ci          x: x3 - textWidth / 2,
392fb726d48Sopenharmony_ci          y: y3 + textHeight / 2,
393fb726d48Sopenharmony_ci          w: textWidth,
394fb726d48Sopenharmony_ci          h: textHeight,
395fb726d48Sopenharmony_ci        });
396fb726d48Sopenharmony_ci        this.ctx?.fillText(text, rect.x, rect.y);
397fb726d48Sopenharmony_ci        this.ctx?.closePath();
398fb726d48Sopenharmony_ci      });
399fb726d48Sopenharmony_ci    }
400fb726d48Sopenharmony_ci  }
401fb726d48Sopenharmony_ci
402fb726d48Sopenharmony_ci  render(ease: boolean = true): void {
403fb726d48Sopenharmony_ci    if (!this.canvas || !this.litChartPieConfig) {
404fb726d48Sopenharmony_ci      return;
405fb726d48Sopenharmony_ci    }
406fb726d48Sopenharmony_ci    if (this.radius! <= 0) {
407fb726d48Sopenharmony_ci      return;
408fb726d48Sopenharmony_ci    }
409fb726d48Sopenharmony_ci    this.ctx?.clearRect(0 - this.centerX!, 0 - this.centerY!, this.clientWidth, this.clientHeight);
410fb726d48Sopenharmony_ci    this.data.forEach((it) => {
411fb726d48Sopenharmony_ci      this.ctx!.beginPath();
412fb726d48Sopenharmony_ci      this.ctx!.fillStyle = it.color as string;
413fb726d48Sopenharmony_ci      this.ctx!.strokeStyle = this.data.length > 1 ? '#fff' : (it.color as string);
414fb726d48Sopenharmony_ci      this.ctx?.moveTo(0, 0);
415fb726d48Sopenharmony_ci      if (it.hover) {
416fb726d48Sopenharmony_ci        this.ctx!.lineWidth = 1;
417fb726d48Sopenharmony_ci        this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false);
418fb726d48Sopenharmony_ci      } else {
419fb726d48Sopenharmony_ci        this.ctx!.lineWidth = 1;
420fb726d48Sopenharmony_ci        if (ease) {
421fb726d48Sopenharmony_ci          if (it.ease!.initVal! < it.endAngle! - it.startAngle!) {
422fb726d48Sopenharmony_ci            it.ease!.process = true;
423fb726d48Sopenharmony_ci            this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.startAngle! + it.ease!.initVal!, false);
424fb726d48Sopenharmony_ci            it.ease!.initVal! += it.ease!.step!;
425fb726d48Sopenharmony_ci          } else {
426fb726d48Sopenharmony_ci            it.ease!.process = false;
427fb726d48Sopenharmony_ci            this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false);
428fb726d48Sopenharmony_ci          }
429fb726d48Sopenharmony_ci        } else {
430fb726d48Sopenharmony_ci          this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false);
431fb726d48Sopenharmony_ci        }
432fb726d48Sopenharmony_ci      }
433fb726d48Sopenharmony_ci      this.ctx?.lineTo(0, 0);
434fb726d48Sopenharmony_ci      this.ctx?.fill();
435fb726d48Sopenharmony_ci      this.ctx!.stroke();
436fb726d48Sopenharmony_ci      this.ctx?.closePath();
437fb726d48Sopenharmony_ci    });
438fb726d48Sopenharmony_ci    this.setData(ease);
439fb726d48Sopenharmony_ci  }
440fb726d48Sopenharmony_ci
441fb726d48Sopenharmony_ci  setData(ease: boolean): void {
442fb726d48Sopenharmony_ci    this.data
443fb726d48Sopenharmony_ci      .filter((it) => it.hover)
444fb726d48Sopenharmony_ci      .forEach((it) => {
445fb726d48Sopenharmony_ci        this.ctx!.beginPath();
446fb726d48Sopenharmony_ci        this.ctx!.fillStyle = it.color as string;
447fb726d48Sopenharmony_ci        this.ctx!.lineWidth = 1;
448fb726d48Sopenharmony_ci        this.ctx?.moveTo(0, 0);
449fb726d48Sopenharmony_ci        this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false);
450fb726d48Sopenharmony_ci        this.ctx?.lineTo(0, 0);
451fb726d48Sopenharmony_ci        this.ctx!.strokeStyle = this.data.length > 1 ? '#000' : (it.color as string);
452fb726d48Sopenharmony_ci        this.ctx!.stroke();
453fb726d48Sopenharmony_ci        this.ctx?.closePath();
454fb726d48Sopenharmony_ci      });
455fb726d48Sopenharmony_ci    this.handleData();
456fb726d48Sopenharmony_ci    if (this.data.filter((it) => it.ease!.process).length > 0) {
457fb726d48Sopenharmony_ci      requestAnimationFrame(() => this.render(ease));
458fb726d48Sopenharmony_ci    }
459fb726d48Sopenharmony_ci  }
460fb726d48Sopenharmony_ci
461fb726d48Sopenharmony_ci  correctRect(pieRect: Rectangle): Rectangle {
462fb726d48Sopenharmony_ci    if (this.textRects.length === 0) {
463fb726d48Sopenharmony_ci      this.textRects.push(pieRect);
464fb726d48Sopenharmony_ci      return pieRect;
465fb726d48Sopenharmony_ci    } else {
466fb726d48Sopenharmony_ci      let rectangles = this.textRects.filter((it) => this.intersect(it, pieRect).cross);
467fb726d48Sopenharmony_ci      if (rectangles.length === 0) {
468fb726d48Sopenharmony_ci        this.textRects.push(pieRect);
469fb726d48Sopenharmony_ci        return pieRect;
470fb726d48Sopenharmony_ci      } else {
471fb726d48Sopenharmony_ci        let it = rectangles[0];
472fb726d48Sopenharmony_ci        let inter = this.intersect(it, pieRect);
473fb726d48Sopenharmony_ci        if (inter.direction === 'Right') {
474fb726d48Sopenharmony_ci          pieRect.x += inter.crossW;
475fb726d48Sopenharmony_ci        } else if (inter.direction === 'Bottom') {
476fb726d48Sopenharmony_ci          pieRect.y += inter.crossH;
477fb726d48Sopenharmony_ci        } else if (inter.direction === 'Left') {
478fb726d48Sopenharmony_ci          pieRect.x -= inter.crossW;
479fb726d48Sopenharmony_ci        } else if (inter.direction === 'Top') {
480fb726d48Sopenharmony_ci          pieRect.y -= inter.crossH;
481fb726d48Sopenharmony_ci        } else if (inter.direction === 'Right-Top') {
482fb726d48Sopenharmony_ci          pieRect.y -= inter.crossH;
483fb726d48Sopenharmony_ci        } else if (inter.direction === 'Right-Bottom') {
484fb726d48Sopenharmony_ci          pieRect.y += inter.crossH;
485fb726d48Sopenharmony_ci        } else if (inter.direction === 'Left-Top') {
486fb726d48Sopenharmony_ci          pieRect.y -= inter.crossH;
487fb726d48Sopenharmony_ci        } else if (inter.direction === 'Left-Bottom') {
488fb726d48Sopenharmony_ci          pieRect.y += inter.crossH;
489fb726d48Sopenharmony_ci        }
490fb726d48Sopenharmony_ci        this.textRects.push(pieRect);
491fb726d48Sopenharmony_ci        return pieRect;
492fb726d48Sopenharmony_ci      }
493fb726d48Sopenharmony_ci    }
494fb726d48Sopenharmony_ci  }
495fb726d48Sopenharmony_ci
496fb726d48Sopenharmony_ci  intersect(
497fb726d48Sopenharmony_ci    r1: Rectangle,
498fb726d48Sopenharmony_ci    rect: Rectangle
499fb726d48Sopenharmony_ci  ): {
500fb726d48Sopenharmony_ci    cross: boolean;
501fb726d48Sopenharmony_ci    direction: string;
502fb726d48Sopenharmony_ci    crossW: number;
503fb726d48Sopenharmony_ci    crossH: number;
504fb726d48Sopenharmony_ci  } {
505fb726d48Sopenharmony_ci    let cross: boolean;
506fb726d48Sopenharmony_ci    let direction: string = '';
507fb726d48Sopenharmony_ci    let crossW: number;
508fb726d48Sopenharmony_ci    let crossH: number;
509fb726d48Sopenharmony_ci    let maxX = r1.x + r1.w > rect.x + rect.w ? r1.x + r1.w : rect.x + rect.w;
510fb726d48Sopenharmony_ci    let maxY = r1.y + r1.h > rect.y + rect.h ? r1.y + r1.h : rect.y + rect.h;
511fb726d48Sopenharmony_ci    let minX = r1.x < rect.x ? r1.x : rect.x;
512fb726d48Sopenharmony_ci    let minY = r1.y < rect.y ? r1.y : rect.y;
513fb726d48Sopenharmony_ci    cross = maxX - minX < rect.w + r1.w && maxY - minY < r1.h + rect.h;
514fb726d48Sopenharmony_ci    crossW = Math.abs(maxX - minX - (rect.w + r1.w));
515fb726d48Sopenharmony_ci    crossH = Math.abs(maxY - minY - (rect.y + r1.y));
516fb726d48Sopenharmony_ci    if (rect.x > r1.x) {
517fb726d48Sopenharmony_ci      if (rect.y > r1.y) {
518fb726d48Sopenharmony_ci        direction = 'Right-Bottom';
519fb726d48Sopenharmony_ci      } else if (rect.y === r1.y) {
520fb726d48Sopenharmony_ci        direction = 'Right';
521fb726d48Sopenharmony_ci      } else {
522fb726d48Sopenharmony_ci        direction = 'Right-Top';
523fb726d48Sopenharmony_ci      }
524fb726d48Sopenharmony_ci    } else if (rect.x < r1.x) {
525fb726d48Sopenharmony_ci      if (rect.y > r1.y) {
526fb726d48Sopenharmony_ci        direction = 'Left-Bottom';
527fb726d48Sopenharmony_ci      } else if (rect.y === r1.y) {
528fb726d48Sopenharmony_ci        direction = 'Left';
529fb726d48Sopenharmony_ci      } else {
530fb726d48Sopenharmony_ci        direction = 'Left-Top';
531fb726d48Sopenharmony_ci      }
532fb726d48Sopenharmony_ci    } else {
533fb726d48Sopenharmony_ci      direction = this.rectSuperposition(rect, r1);
534fb726d48Sopenharmony_ci    }
535fb726d48Sopenharmony_ci    return {
536fb726d48Sopenharmony_ci      cross,
537fb726d48Sopenharmony_ci      direction,
538fb726d48Sopenharmony_ci      crossW,
539fb726d48Sopenharmony_ci      crossH,
540fb726d48Sopenharmony_ci    };
541fb726d48Sopenharmony_ci  }
542fb726d48Sopenharmony_ci
543fb726d48Sopenharmony_ci  rectSuperposition(rect: Rectangle, r1: Rectangle): string {
544fb726d48Sopenharmony_ci    if (rect.y > r1.y) {
545fb726d48Sopenharmony_ci      return 'Bottom';
546fb726d48Sopenharmony_ci    } else if (rect.y === r1.y) {
547fb726d48Sopenharmony_ci      return 'Right'; //superposition default right
548fb726d48Sopenharmony_ci    } else {
549fb726d48Sopenharmony_ci      return 'Top';
550fb726d48Sopenharmony_ci    }
551fb726d48Sopenharmony_ci  }
552fb726d48Sopenharmony_ci
553fb726d48Sopenharmony_ci  showTip(x: number, y: number, msg: string): void {
554fb726d48Sopenharmony_ci    this.pieTipEL!.style.display = 'flex';
555fb726d48Sopenharmony_ci    this.pieTipEL!.style.top = `${y}px`;
556fb726d48Sopenharmony_ci    this.pieTipEL!.style.left = `${x}px`;
557fb726d48Sopenharmony_ci    this.pieTipEL!.innerHTML = msg;
558fb726d48Sopenharmony_ci  }
559fb726d48Sopenharmony_ci
560fb726d48Sopenharmony_ci  hideTip(): void {
561fb726d48Sopenharmony_ci    this.pieTipEL!.style.display = 'none';
562fb726d48Sopenharmony_ci  }
563fb726d48Sopenharmony_ci
564fb726d48Sopenharmony_ci  initHtml(): string {
565fb726d48Sopenharmony_ci    return `
566fb726d48Sopenharmony_ci        ${initHtmlStyle}
567fb726d48Sopenharmony_ci        <div id="root">
568fb726d48Sopenharmony_ci            <div id="shape" class="shape active"></div>
569fb726d48Sopenharmony_ci            <canvas id="canvas" style="top: 0;left: 0;z-index: 21"></canvas>
570fb726d48Sopenharmony_ci            <div id="tip"></div>
571fb726d48Sopenharmony_ci            <div id="labels"></div>
572fb726d48Sopenharmony_ci        </div>`;
573fb726d48Sopenharmony_ci  }
574fb726d48Sopenharmony_ci}
575