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