@easyv/charts 1.8.22 → 1.8.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * 图例
3
3
  */
4
- import React, { memo, useCallback, useState, useEffect, useRef } from 'react';
5
- import { getIcon, sortPie } from '../utils';
6
- import TextOverflow from './TextOverflow';
4
+ import React, { memo, useCallback, useState, useEffect, useRef } from "react";
5
+ import { getIcon, sortPie } from "../utils";
6
+ import TextOverflow from "./TextOverflow";
7
7
 
8
8
  const defaultFont = {
9
- fontStyle: 'normal',
10
- fontWeight: 'normal',
9
+ fontStyle: "normal",
10
+ fontWeight: "normal",
11
11
  };
12
12
 
13
13
  export default memo(
@@ -17,14 +17,14 @@ export default memo(
17
17
  config,
18
18
  config: {
19
19
  show,
20
- order = '',
20
+ order = "",
21
21
  interactive,
22
- LegendType,//类型
22
+ LegendType, //类型
23
23
  maxWidth,
24
24
  textOverflow,
25
25
  speed,
26
26
  layout: {
27
- alignment = 'right center',
27
+ alignment = "right center",
28
28
  gridTemplateColumns,
29
29
  gridGap: { gridColumnGap, gridRowGap },
30
30
  translate: { x, y },
@@ -35,7 +35,8 @@ export default memo(
35
35
  },
36
36
  filterData,
37
37
  formatter,
38
- judge
38
+ judge,
39
+ pieClick,
39
40
  }) => {
40
41
  if (!show) return null;
41
42
 
@@ -47,7 +48,8 @@ export default memo(
47
48
  // 初始化行高
48
49
  useEffect(() => {
49
50
  if (ref_container.current) {
50
- const rowHeight = ref_container.current.querySelector('li').clientHeight + gridRowGap;
51
+ const rowHeight =
52
+ ref_container.current.querySelector("li").clientHeight + gridRowGap;
51
53
  setScrollStep(rowHeight);
52
54
  }
53
55
  }, [gridRowGap]);
@@ -64,12 +66,12 @@ export default memo(
64
66
 
65
67
  // 清除定时器
66
68
  return () => clearInterval(timer);
67
- }, [scrollStep, loop.show, loop.interval])
68
-
69
+ }, [scrollStep, loop.show, loop.interval]);
70
+
69
71
  const handleAutoScroll = () => {
70
72
  const table = ref_container.current;
71
73
  if (!table) return;
72
-
74
+
73
75
  // 如果已经滚动到了底部,则返回顶部
74
76
  if (ref_scrollTop.current + table.clientHeight >= table.scrollHeight) {
75
77
  ref_scrollTop.current = 0;
@@ -78,11 +80,11 @@ export default memo(
78
80
  ref_scrollTop.current += scrollStep;
79
81
  }
80
82
 
81
- table.scrollTo({ top: ref_scrollTop.current, behavior: 'smooth' });
83
+ table.scrollTo({ top: ref_scrollTop.current, behavior: "smooth" });
82
84
  };
83
85
 
84
86
  const _series = sortPie(series, order);
85
- const [_alignment, position] = alignment.split(' ');
87
+ const [_alignment, position] = alignment.split(" ");
86
88
  const length = _series.length;
87
89
 
88
90
  const onClick = useCallback(
@@ -90,168 +92,249 @@ export default memo(
90
92
  const { dataset } = e.currentTarget;
91
93
  const { name } = dataset;
92
94
  filterData && interactive && filterData(name);
95
+ pieClick && pieClick(e);
93
96
  },
94
- [interactive, filterData]
97
+ [interactive, filterData, pieClick]
95
98
  );
96
99
 
97
100
  if (judge == 0) {
98
101
  _series.forEach((d) => {
99
- d.percent=0
100
- })
102
+ d.percent = 0;
103
+ });
101
104
  }
102
105
 
103
106
  // 计算最大宽度
104
107
  const valueFont = config.value?.font || {};
105
108
  const percentFont = config.percent?.font || {};
106
- const valueSuffix = config.value?.suffix?.text || '';
109
+ const valueSuffix = config.value?.suffix?.text || "";
107
110
  const valueSplitConfig = config.value?.splitConfig || {};
108
111
  const getValueStr = (item) => {
109
- let valueStr = (item.data?.y ?? item.value ?? '') + (valueSuffix || '');
112
+ let valueStr = (item.data?.y ?? item.value ?? "") + (valueSuffix || "");
110
113
  if (valueSplitConfig.show && valueSplitConfig.separator) {
111
- valueStr = valueStr.toString().replace(/\B(?=(\d{3})+(?!\d))/g, valueSplitConfig.separator);
114
+ valueStr = valueStr
115
+ .toString()
116
+ .replace(/\B(?=(\d{3})+(?!\d))/g, valueSplitConfig.separator);
112
117
  }
113
118
  return valueStr;
114
119
  };
115
120
  const valueMaxWidth = Math.max(
116
- ..._series.map(item => parseFloat(getCanvasTextWidth(getValueStr(item), valueFont.letterSpacing || 0, `${valueFont.fontSize || 12}px ${valueFont.fontFamily || 'Arial'}`)))
121
+ ..._series.map((item) =>
122
+ parseFloat(
123
+ getCanvasTextWidth(
124
+ getValueStr(item),
125
+ valueFont.letterSpacing || 0,
126
+ `${valueFont.fontSize || 12}px ${valueFont.fontFamily || "Arial"}`
127
+ )
128
+ )
129
+ )
117
130
  );
118
131
  const percentMaxWidth = Math.max(
119
- ..._series.map(item => {
120
- const percentStr = (item.percent !== undefined ? item.percent : item.data?.percent) + '%';
121
- return parseFloat(getCanvasTextWidth(percentStr, percentFont.letterSpacing || 0, `${percentFont.fontSize || 12}px ${percentFont.fontFamily || 'Arial'}`));
132
+ ..._series.map((item) => {
133
+ const percentStr =
134
+ (item.percent !== undefined ? item.percent : item.data?.percent) +
135
+ "%";
136
+ return parseFloat(
137
+ getCanvasTextWidth(
138
+ percentStr,
139
+ percentFont.letterSpacing || 0,
140
+ `${percentFont.fontSize || 12}px ${
141
+ percentFont.fontFamily || "Arial"
142
+ }`
143
+ )
144
+ );
122
145
  })
123
146
  );
124
147
  const nameMaxWidth = config.name?.maxWidth || 80;
125
148
 
126
- const stylePieOrAxis=formatter?{
127
- display:'flex',
128
- alignContent:alignment.split(" ")[0]=="center"&&(alignment.split(" ")[1]=="left"||alignment.split(" ")[1]=="right")?alignment.split(" ")[1]=="left"?"flex-start":"flex-end":alignment.split(" ")[0]=="left"?"flex-start":alignment.split(" ")[0]=="center"?"center":"flex-end",
129
- flexDirection:"column",
130
- position: 'absolute',
131
- ...getPosition(position, _alignment, x, y),
132
- height: loop.show ? height : 'auto',
133
- overflowY: loop.show ? 'scroll' : 'auto'
134
- }:{
135
- display:'flex',
136
- flexWrap:"wrap",
137
- alignContent:alignment.split(" ")[0]=="center"&&(alignment.split(" ")[1]=="left"||alignment.split(" ")[1]=="right")?alignment.split(" ")[1]=="left"?"flex-start":"flex-end":alignment.split(" ")[0]=="left"?"flex-start":alignment.split(" ")[0]=="center"?"center":"flex-end",
138
- flexDirection: "column",
139
- position: 'absolute',
140
- ...getPosition(position, _alignment, x, y),
141
- height: loop.show ? height : 'auto',
142
- overflowY: loop.show ? 'scroll' : 'auto'
143
- }
144
- return (
145
- LegendType=="FixedWidth"?
149
+ const stylePieOrAxis = formatter
150
+ ? {
151
+ display: "flex",
152
+ alignContent:
153
+ alignment.split(" ")[0] == "center" &&
154
+ (alignment.split(" ")[1] == "left" ||
155
+ alignment.split(" ")[1] == "right")
156
+ ? alignment.split(" ")[1] == "left"
157
+ ? "flex-start"
158
+ : "flex-end"
159
+ : alignment.split(" ")[0] == "left"
160
+ ? "flex-start"
161
+ : alignment.split(" ")[0] == "center"
162
+ ? "center"
163
+ : "flex-end",
164
+ flexDirection: "column",
165
+ position: "absolute",
166
+ ...getPosition(position, _alignment, x, y),
167
+ height: loop.show ? height : "auto",
168
+ overflowY: loop.show ? "scroll" : "auto",
169
+ }
170
+ : {
171
+ display: "flex",
172
+ flexWrap: "wrap",
173
+ alignContent:
174
+ alignment.split(" ")[0] == "center" &&
175
+ (alignment.split(" ")[1] == "left" ||
176
+ alignment.split(" ")[1] == "right")
177
+ ? alignment.split(" ")[1] == "left"
178
+ ? "flex-start"
179
+ : "flex-end"
180
+ : alignment.split(" ")[0] == "left"
181
+ ? "flex-start"
182
+ : alignment.split(" ")[0] == "center"
183
+ ? "center"
184
+ : "flex-end",
185
+ flexDirection: "column",
186
+ position: "absolute",
187
+ ...getPosition(position, _alignment, x, y),
188
+ height: loop.show ? height : "auto",
189
+ overflowY: loop.show ? "scroll" : "auto",
190
+ };
191
+ return LegendType == "FixedWidth" ? (
146
192
  <div
147
- className='__easyv-legend-wrapper'
193
+ className="__easyv-legend-wrapper"
148
194
  style={{
149
- position: 'absolute',
150
- display: 'flex',
195
+ position: "absolute",
196
+ display: "flex",
151
197
  ...getPosition(position, _alignment, x, y),
152
- height: loop.show ? height : 'auto',
153
- overflowY: loop.show ? 'scroll' : 'auto'
198
+ height: loop.show ? height : "auto",
199
+ overflowY: loop.show ? "scroll" : "auto",
154
200
  }}
155
201
  ref={ref_container}
156
202
  >
157
203
  <ul
158
204
  style={{
159
- display: 'grid',
160
- gridGap: gridRowGap + 'px ' + gridColumnGap + 'px',
161
- gridTemplateColumns:formatter?`${nameMaxWidth}px ${valueMaxWidth}px ${percentMaxWidth}px`:
162
- 'repeat(' + Math.min(gridTemplateColumns, length) + ', 1fr)',//饼图或者柱状图配合不同的图例显示格式
205
+ display: "grid",
206
+ gridGap: gridRowGap + "px " + gridColumnGap + "px",
207
+ gridTemplateColumns: formatter
208
+ ? `${nameMaxWidth}px ${valueMaxWidth}px ${percentMaxWidth}px`
209
+ : "repeat(" + Math.min(gridTemplateColumns, length) + ", 1fr)", //饼图或者柱状图配合不同的图例显示格式
163
210
  }}
164
211
  >
165
- {_series.map((series, index) => {
166
- const { type, name, displayName, icon, selected } = series;
212
+ {_series.map((series, i) => {
213
+ const { type, name, displayName, icon, selected, index } = series;
167
214
  const _icon = getIcon(type, icon, series?.config?.line?.type);
168
215
  return (
169
216
  <li
170
- key={index}
217
+ key={i}
171
218
  onClick={onClick}
172
- data-name={name}
219
+ data-name={displayName || name}
220
+ data-index={index}
173
221
  style={{
174
- display: 'flex',
222
+ display: "flex",
175
223
  opacity: selected === false ? opacity / 100 : 1,
176
- alignItems: 'center',
224
+ alignItems: "center",
177
225
  cursor: "pointer",
178
226
  gap: _icon.gap,
179
227
  }}
180
228
  >
181
229
  {formatter ? (
182
- formatter(series, { ...config, valueMaxWidth, percentMaxWidth, nameMaxWidth })
230
+ formatter(series, {
231
+ ...config,
232
+ valueMaxWidth,
233
+ percentMaxWidth,
234
+ nameMaxWidth,
235
+ })
183
236
  ) : (
184
237
  <>
185
238
  <span style={_icon} />
186
- <TextOverflow type={textOverflow} value={displayName || name} style={{
239
+ <TextOverflow
240
+ type={textOverflow}
241
+ value={displayName || name}
242
+ style={{
187
243
  ...font,
188
- width:maxWidth,
189
- fontStyle: italic ? 'italic' : 'normal',
190
- fontWeight: bold ? 'bold' : 'normal',
191
- }} speed={speed}></TextOverflow>
192
-
244
+ width: maxWidth,
245
+ fontStyle: italic ? "italic" : "normal",
246
+ fontWeight: bold ? "bold" : "normal",
247
+ }}
248
+ speed={speed}
249
+ ></TextOverflow>
193
250
  </>
194
251
  )}
195
252
  </li>
196
253
  );
197
254
  })}
198
255
  </ul>
199
- </div>:<div
200
- className='__easyv-legend-wrapper'
256
+ </div>
257
+ ) : (
258
+ <div
259
+ className="__easyv-legend-wrapper"
201
260
  style={stylePieOrAxis}
202
261
  ref={ref_container}
203
262
  >
204
-
205
- {[...Array(Math.ceil(series.length/gridTemplateColumns))].map((_,indexs)=>(
206
- <ul
207
- key={indexs}
208
- style={{
209
- display: 'flex',
210
- width: 'fit-content',
211
- justifyContent:alignment.split(" ")[0]=="left"?"flex-start":alignment.split(" ")[0]=="center"?"center":"flex-end",
212
- marginBottom:"0px",
213
- gap:`${gridRowGap}px ${gridColumnGap}px`,
214
- marginBottom:gridRowGap+"px"
215
- }}
216
- >
217
- {_series.map((series, index) => {
218
- if(Math.floor(index/gridTemplateColumns)==indexs){
219
- const { type, name, displayName, icon, selected } = series;
220
- const _icon = getIcon(type, icon, series?.config?.line?.type);
221
- return (
222
- <li
223
- key={index}
224
- onClick={onClick}
225
- data-name={name}
263
+ {[...Array(Math.ceil(series.length / gridTemplateColumns))].map(
264
+ (_, indexs) => (
265
+ <ul
266
+ key={indexs}
226
267
  style={{
227
- display: 'flex',
228
- opacity: selected === false ? opacity / 100 : 1,
229
- alignItems: 'center',
230
- cursor: "pointer",
231
- gap: _icon.gap,
268
+ display: "flex",
269
+ width: "fit-content",
270
+ justifyContent:
271
+ alignment.split(" ")[0] == "left"
272
+ ? "flex-start"
273
+ : alignment.split(" ")[0] == "center"
274
+ ? "center"
275
+ : "flex-end",
276
+ marginBottom: "0px",
277
+ gap: `${gridRowGap}px ${gridColumnGap}px`,
278
+ marginBottom: gridRowGap + "px",
232
279
  }}
233
280
  >
234
- {formatter ? (
235
- formatter(series, { ...config, valueMaxWidth, percentMaxWidth, nameMaxWidth })
236
- ) : (
237
- <>
238
- <span style={_icon} />
239
- <TextOverflow ShowType={LegendType} type="ellipsis" value={displayName || name} style={{
240
- ...font,
241
- fontStyle: italic ? 'italic' : 'normal',
242
- fontWeight: bold ? 'bold' : 'normal',
243
- minWidth:getCanvasTextWidth(displayName?(displayName.substring(0,5) || name.substring(0,5)):"",font.letterSpacing,`${font.fontSize}px ${font.fontFamily}` )
244
- }} speed={speed}></TextOverflow>
245
-
246
- </>
247
- )}
248
- </li>
249
- );
250
- }
251
- })}
252
- </ul>
253
- ))
254
- }
281
+ {_series.map((series, i) => {
282
+ if (Math.floor(i / gridTemplateColumns) == indexs) {
283
+ const { type, name, displayName, icon, selected, index } =
284
+ series;
285
+ const _icon = getIcon(type, icon, series?.config?.line?.type);
286
+ return (
287
+ <li
288
+ key={i}
289
+ onClick={onClick}
290
+ data-name={displayName || name}
291
+ data-index={index}
292
+ style={{
293
+ display: "flex",
294
+ opacity: selected === false ? opacity / 100 : 1,
295
+ alignItems: "center",
296
+ cursor: "pointer",
297
+ gap: _icon.gap,
298
+ }}
299
+ >
300
+ {formatter ? (
301
+ formatter(series, {
302
+ ...config,
303
+ valueMaxWidth,
304
+ percentMaxWidth,
305
+ nameMaxWidth,
306
+ })
307
+ ) : (
308
+ <>
309
+ <span style={_icon} />
310
+ <TextOverflow
311
+ ShowType={LegendType}
312
+ type="ellipsis"
313
+ value={displayName || name}
314
+ style={{
315
+ ...font,
316
+ fontStyle: italic ? "italic" : "normal",
317
+ fontWeight: bold ? "bold" : "normal",
318
+ minWidth: getCanvasTextWidth(
319
+ displayName
320
+ ? displayName.substring(0, 5) ||
321
+ name.substring(0, 5)
322
+ : "",
323
+ font.letterSpacing,
324
+ `${font.fontSize}px ${font.fontFamily}`
325
+ ),
326
+ }}
327
+ speed={speed}
328
+ ></TextOverflow>
329
+ </>
330
+ )}
331
+ </li>
332
+ );
333
+ }
334
+ })}
335
+ </ul>
336
+ )
337
+ )}
255
338
  </div>
256
339
  );
257
340
  }
@@ -259,38 +342,42 @@ const stylePieOrAxis=formatter?{
259
342
 
260
343
  const getPosition = (position, alignment, x = 0, y = 0) => {
261
344
  switch (position) {
262
- case 'top':
345
+ case "top":
263
346
  return {
264
- left: alignment == 'left' ? 5 : alignment == 'center' ? '50%' : '',
265
- right: alignment == 'right' ? 10 : '',
347
+ left: alignment == "left" ? 5 : alignment == "center" ? "50%" : "",
348
+ right: alignment == "right" ? 10 : "",
266
349
  top: 5,
267
- transform: `translate3d(calc(${alignment == 'center' ? '-50%' : '0px'} + ${x}px), ${y}px, 0px)`
350
+ transform: `translate3d(calc(${
351
+ alignment == "center" ? "-50%" : "0px"
352
+ } + ${x}px), ${y}px, 0px)`,
268
353
  };
269
- case 'right':
354
+ case "right":
270
355
  return {
271
- top: '50%',
356
+ top: "50%",
272
357
  right: 10,
273
- transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`
358
+ transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`,
274
359
  };
275
- case 'left':
360
+ case "left":
276
361
  return {
277
- top: '50%',
362
+ top: "50%",
278
363
  left: 5,
279
- transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`
364
+ transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`,
280
365
  };
281
366
  default: // bottom
282
367
  return {
283
- left: alignment == 'left' ? 5 : alignment == 'center' ? '50%' : '',
284
- right: alignment == 'right' ? 10 : '',
368
+ left: alignment == "left" ? 5 : alignment == "center" ? "50%" : "",
369
+ right: alignment == "right" ? 10 : "",
285
370
  bottom: 5,
286
- transform: `translate3d(calc(${alignment == 'center' ? '-50%' : '0px'} + ${x}px), ${y}px, 0px)`
371
+ transform: `translate3d(calc(${
372
+ alignment == "center" ? "-50%" : "0px"
373
+ } + ${x}px), ${y}px, 0px)`,
287
374
  };
288
375
  }
289
376
  };
290
- const getCanvasTextWidth=(text,letterSpacing, font = '16px Arial')=>{
291
- const canvas = document.createElement('canvas');
292
- const ctx = canvas.getContext('2d');
377
+ const getCanvasTextWidth = (text, letterSpacing, font = "16px Arial") => {
378
+ const canvas = document.createElement("canvas");
379
+ const ctx = canvas.getContext("2d");
293
380
  ctx.font = font;
294
- return ctx.measureText(text).width+(text.length)*letterSpacing+"px";
381
+ return ctx.measureText(text).width + text.length * letterSpacing + "px";
295
382
  // return ctx.measureText(text).width+(text.length-1)*letterSpacing+"px";//-1有bug
296
- }
383
+ };
@@ -653,6 +653,7 @@ const Component = memo(
653
653
  ...arc,
654
654
  percent: arc.percent.toFixed(legendPrecision),
655
655
  }))}
656
+ pieClick={onClick}
656
657
  formatter={formatter}
657
658
  judge={judgeData}
658
659
  />
@@ -921,6 +922,7 @@ const Component = memo(
921
922
  ...arc,
922
923
  percent: arc.percent.toFixed(legendPrecision),
923
924
  }))}
925
+ pieClick={onClick}
924
926
  formatter={formatter}
925
927
  judge={judgeData}
926
928
  />
@@ -1106,7 +1108,14 @@ const Label = ({
1106
1108
  align,
1107
1109
  show,
1108
1110
  translate: { x: translateX, y: translateY },
1109
- name: { show: showName, font: nameFont, maxWidth, textOverflow, speed,translate:NameTranslate },
1111
+ name: {
1112
+ show: showName,
1113
+ font: nameFont,
1114
+ maxWidth,
1115
+ textOverflow,
1116
+ speed,
1117
+ translate: NameTranslate,
1118
+ },
1110
1119
  value: {
1111
1120
  show: showValue,
1112
1121
  font: valueFont,
@@ -1117,14 +1126,14 @@ const Label = ({
1117
1126
  fontSize: suffixFontSize,
1118
1127
  translate: { x: suffixTranslateX, y: suffixTranslateY },
1119
1128
  },
1120
- translate:ValueTranslate
1129
+ translate: ValueTranslate,
1121
1130
  },
1122
1131
  percent: {
1123
1132
  show: showPercent,
1124
1133
  sameColor: percentSameColor,
1125
1134
  font: percentFont,
1126
1135
  precision,
1127
- translate:PercentTranslate
1136
+ translate: PercentTranslate,
1128
1137
  },
1129
1138
  },
1130
1139
  iosStyle: { isIOS, left, top },
@@ -1240,7 +1249,12 @@ const Label = ({
1240
1249
  width: "max-content",
1241
1250
  display: "flex",
1242
1251
  flexDirection: mode == "horizontal" ? "row" : "column",
1243
- alignItems: align=="left"?"flex-start":align=="center"?"center":"flex-end",
1252
+ alignItems:
1253
+ align == "left"
1254
+ ? "flex-start"
1255
+ : align == "center"
1256
+ ? "center"
1257
+ : "flex-end",
1244
1258
  justifyContent: "center",
1245
1259
  }}
1246
1260
  >
@@ -1255,7 +1269,7 @@ const Label = ({
1255
1269
  maxWidth,
1256
1270
  ...nameStyle,
1257
1271
  float: mode == "horizontal" ? "left" : "none",
1258
- transform: `translate(${NameTranslate.x}px, ${NameTranslate.y}px)`
1272
+ transform: `translate(${NameTranslate.x}px, ${NameTranslate.y}px)`,
1259
1273
  }}
1260
1274
  ></TextOverflow>
1261
1275
  )}
@@ -1264,7 +1278,7 @@ const Label = ({
1264
1278
  style={{
1265
1279
  ...getFontStyle(valueFont),
1266
1280
  color: valueSameColor ? pure : valueFont.color,
1267
- transform: `translate(${ValueTranslate.x}px, ${ValueTranslate.y}px)`
1281
+ transform: `translate(${ValueTranslate.x}px, ${ValueTranslate.y}px)`,
1268
1282
  }}
1269
1283
  >
1270
1284
  {data.y}
@@ -1339,6 +1353,7 @@ const RingLabel = ({
1339
1353
  value: {
1340
1354
  show: showValue,
1341
1355
  font: valueFont,
1356
+ sameColor: valueSameColor,
1342
1357
  suffix: {
1343
1358
  show: showSuffix,
1344
1359
  text,
@@ -1349,6 +1364,7 @@ const RingLabel = ({
1349
1364
  },
1350
1365
  percent: {
1351
1366
  show: showPercent,
1367
+ sameColor: percentSameColor,
1352
1368
  font: percentFont,
1353
1369
  precision,
1354
1370
  translate: percentTranslate,
@@ -1393,7 +1409,6 @@ const RingLabel = ({
1393
1409
  index
1394
1410
  ) => {
1395
1411
  const [x, y] = arc.centroid();
1396
-
1397
1412
  const midAngle = Math.atan2(y, x);
1398
1413
 
1399
1414
  const [x1, y1] = getCoord(