@easyv/charts 1.0.44 → 1.0.48

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.
Files changed (65) hide show
  1. package/.babelrc +8 -8
  2. package/lib/components/AnimateData.js +2 -2
  3. package/lib/components/Axis.js +12 -12
  4. package/lib/components/Background.js +2 -2
  5. package/lib/components/Carousel.js +4 -2
  6. package/lib/components/Chart.js +2 -2
  7. package/lib/components/ConicalGradient.js +21 -21
  8. package/lib/components/Indicator.js +2 -2
  9. package/lib/components/Label.js +1 -1
  10. package/lib/components/LinearGradient.js +2 -2
  11. package/lib/components/PieChart.js +326 -139
  12. package/lib/css/index.module.css +42 -42
  13. package/lib/css/piechart.module.css +27 -0
  14. package/lib/formatter/legend.js +3 -2
  15. package/lib/hooks/useAnimateData.js +5 -5
  16. package/lib/hooks/useAxes.js +5 -5
  17. package/lib/hooks/useCarouselAxisX.js +5 -5
  18. package/lib/hooks/useExtentData.js +6 -6
  19. package/lib/hooks/useFilterData.js +5 -5
  20. package/lib/hooks/useStackData.js +5 -5
  21. package/lib/hooks/useTooltip.js +10 -10
  22. package/lib/utils/index.js +1 -1
  23. package/package.json +34 -34
  24. package/src/components/AnimateData.tsx +24 -24
  25. package/src/components/Axis.tsx +333 -333
  26. package/src/components/Background.tsx +45 -45
  27. package/src/components/Band.tsx +160 -160
  28. package/src/components/Brush.js +159 -159
  29. package/src/components/Carousel.tsx +144 -142
  30. package/src/components/Chart.js +99 -101
  31. package/src/components/ChartContainer.tsx +63 -63
  32. package/src/components/ConicalGradient.js +258 -258
  33. package/src/components/ExtentData.js +17 -17
  34. package/src/components/FilterData.js +23 -23
  35. package/src/components/Indicator.js +13 -13
  36. package/src/components/Label.js +194 -194
  37. package/src/components/Legend.js +158 -158
  38. package/src/components/Lighter.jsx +162 -162
  39. package/src/components/Line.js +126 -126
  40. package/src/components/LinearGradient.js +29 -29
  41. package/src/components/Mapping.js +71 -72
  42. package/src/components/PieChart.js +876 -709
  43. package/src/components/StackData.js +20 -20
  44. package/src/components/StereoBar.tsx +298 -298
  45. package/src/components/Tooltip.js +116 -116
  46. package/src/components/index.js +49 -49
  47. package/src/context/index.js +2 -2
  48. package/src/css/index.module.css +42 -42
  49. package/src/css/piechart.module.css +27 -0
  50. package/src/element/Line.tsx +33 -33
  51. package/src/element/index.ts +3 -3
  52. package/src/formatter/index.js +1 -1
  53. package/src/formatter/legend.js +87 -87
  54. package/src/hooks/index.js +17 -17
  55. package/src/hooks/useAnimateData.ts +62 -62
  56. package/src/hooks/useAxes.js +143 -143
  57. package/src/hooks/useCarouselAxisX.js +163 -163
  58. package/src/hooks/useExtentData.js +88 -88
  59. package/src/hooks/useFilterData.js +65 -65
  60. package/src/hooks/useStackData.js +100 -100
  61. package/src/hooks/useTooltip.ts +96 -96
  62. package/src/index.js +6 -6
  63. package/src/types/index.d.ts +59 -59
  64. package/src/utils/index.js +640 -641
  65. package/tsconfig.json +22 -22
@@ -1,709 +1,876 @@
1
- /**
2
- * 饼环图
3
- */
4
- import React, {
5
- memo,
6
- useMemo,
7
- useCallback,
8
- useRef,
9
- useState,
10
- useContext,
11
- useLayoutEffect,
12
- Fragment,
13
- } from 'react';
14
- import { ChartContainer, Carousel, Legend, ConicalGradient, Mapping } from '.';
15
- import { chartContext } from '../context';
16
- import {
17
- getFontStyle,
18
- sortPie,
19
- getDataWithPercent,
20
- getColorList,
21
- } from '../utils';
22
- import { pie, arc, extent, scaleLinear } from 'd3v7';
23
- import { animate, linear } from 'popmotion';
24
- import LinearGradient from './LinearGradient';
25
- import { pieLegendFormatter as legendFormatter } from '../formatter';
26
-
27
- const PI = Math.PI;
28
-
29
- const defaultChart = {
30
- outerRadius: 1,
31
- innerRadius: 0,
32
- cornerRadius: 0,
33
- rose: false,
34
- roseType: 'radius',
35
- baseRadius: 0,
36
- padAngle: 0,
37
- };
38
- const defaultAngle = { startAngle: 0, endAngle: 360, antiClockwise: false };
39
-
40
- const percentX = (showName, showValue, mode, x) => {
41
- if (showValue) {
42
- return '';
43
- }
44
- if (showName) {
45
- if (mode == 'vertical') {
46
- return x;
47
- } else {
48
- return '';
49
- }
50
- } else {
51
- return x;
52
- }
53
- };
54
-
55
- const percentDx = (showName, showValue, mode) => {
56
- if (showValue) {
57
- return '0.5em';
58
- }
59
- if (showName) {
60
- if (mode == 'vertical') {
61
- return 0;
62
- } else {
63
- return '0.5em';
64
- }
65
- } else {
66
- return 0;
67
- }
68
- };
69
-
70
- const percentDy = (showName, showValue, mode) => {
71
- if (showValue) {
72
- return 0;
73
- }
74
- if (showName) {
75
- if (mode == 'vertical') {
76
- return '1.5em';
77
- } else {
78
- return 0;
79
- }
80
- } else {
81
- return 0;
82
- }
83
- };
84
-
85
- const valueDx = (showName, mode) => {
86
- if (!showName) {
87
- return '';
88
- }
89
- if (mode == 'vertical') {
90
- return '';
91
- } else {
92
- return '0.5em';
93
- }
94
- };
95
-
96
- const getCoord = (deg, radius) => {
97
- var x = Math.cos(deg) * radius,
98
- y = Math.sin(deg) * radius;
99
- return [x, y];
100
- };
101
-
102
- const getRoseRadius = ({ innerRadius, baseRadius }) =>
103
- innerRadius + (1 - innerRadius) * baseRadius;
104
-
105
- const getAngle = ({ startAngle, endAngle, antiClockwise, ...rest }) => {
106
- if (antiClockwise)
107
- return {
108
- ...rest,
109
- startAngle: endAngle - 180,
110
- endAngle: startAngle - 180,
111
- };
112
- return { ...rest, startAngle, endAngle };
113
- };
114
-
115
- const getArc = (
116
- radius,
117
- {
118
- padAngle = 0,
119
- innerRadius = 0,
120
- outerRadius = 1,
121
- cornerRadius = 0,
122
- startAngle = 0,
123
- endAngle = 360,
124
- ...rest
125
- },
126
- series
127
- ) => ({
128
- ...rest,
129
- type: 'pie',
130
- fieldName: series.fieldName,
131
- displayName: series.displayName || rest.data.s,
132
- series: series,
133
- innerRadius: innerRadius * radius,
134
- outerRadius: outerRadius * radius,
135
- arc: arc()
136
- .innerRadius(innerRadius * radius)
137
- .outerRadius(outerRadius * radius)
138
- .cornerRadius(cornerRadius)
139
- .startAngle(startAngle)
140
- .endAngle(endAngle)
141
- .padAngle(padAngle),
142
- });
143
-
144
- const Component = memo(
145
- ({
146
- config: {
147
- chart: {
148
- dimension: {
149
- chartDimension: { width, height },
150
- },
151
- label,
152
- legend: { formatter = legendFormatter, ...legend },
153
- margin: { marginLeft, marginTop },
154
- },
155
- fan: {
156
- chart = defaultChart,
157
- chart: { outerRadius = defaultChart.outerRadius },
158
- angle = defaultAngle,
159
- stroke: { show, strokeWidth, color } = { show: false },
160
- decorate,
161
- current,
162
- } = {},
163
- order,
164
- series,
165
- animation: {
166
- on,
167
- current: { heighten, opacity },
168
- },
169
- },
170
- state: { currentIndex, trigger },
171
- onEvent,
172
- data = [],
173
- }) => {
174
- const prevIndex = useRef(null);
175
- const { precision: legendPrecision } = legend.config.percent;
176
-
177
- const {
178
- id,
179
- width: chartWidth,
180
- height: chartHeight,
181
- triggerOnRelative,
182
- onEmit,
183
- } = useContext(chartContext);
184
-
185
- const [y, setY] = useState(1);
186
- const radius = (Math.min(chartWidth, chartHeight) / 2) * outerRadius;
187
-
188
- const arcsFunc = useMemo(() => {
189
- const { startAngle = 0, endAngle = 360 } = getAngle(angle);
190
- const arcsFunc = pie()
191
- .startAngle((startAngle * PI) / 180)
192
- .endAngle((endAngle * PI) / 180)
193
- .value((d) => d.y);
194
- return arcsFunc;
195
- }, [angle]);
196
-
197
- const arcs = useMemo(() => {
198
- const _chart = Object.assign(defaultChart, chart);
199
- const {
200
- innerRadius,
201
- outerRadius,
202
- rose,
203
- cornerRadius,
204
- padAngle,
205
- roseType,
206
- } = _chart;
207
- const _padAngle = (padAngle * Math.PI) / 180;
208
-
209
- switch (order) {
210
- case '':
211
- arcsFunc.sort(null);
212
- break;
213
- case 'desc':
214
- arcsFunc.sort((a, b) => b.y - a.y);
215
- break;
216
- case 'asc':
217
- arcsFunc.sort((a, b) => a.y - b.y);
218
- break;
219
- }
220
-
221
- const arcs = arcsFunc(data);
222
- const legendDataWithPercent = getDataWithPercent(arcs, legendPrecision);
223
- const _legendDataWithPercent = sortPie(legendDataWithPercent, order);
224
-
225
- if (rose) {
226
- const domain = extent(_legendDataWithPercent, (d) => d.value);
227
- const roseRadius = getRoseRadius(_chart);
228
- const scaler = scaleLinear().domain(domain).range([roseRadius, 1]);
229
-
230
- const angle = (PI * 2) / _legendDataWithPercent.length;
231
- return _legendDataWithPercent.map(
232
- ({ startAngle, endAngle, ...arc }, index) => ({
233
- ...arc,
234
- id: id + '_linear_' + index,
235
- startAngle: roseType == 'area' ? angle * index : startAngle,
236
- endAngle: roseType == 'area' ? angle * (index + 1) : endAngle,
237
- cornerRadius,
238
- padAngle: _padAngle,
239
- innerRadius,
240
- outerRadius: scaler(arc.value),
241
- })
242
- );
243
- }
244
- return _legendDataWithPercent.map((arc, index) => ({
245
- ...arc,
246
- id: id + '_linear_' + index,
247
- cornerRadius,
248
- padAngle: _padAngle,
249
- innerRadius,
250
- outerRadius,
251
- }));
252
- }, [data, arcsFunc, chart, legendPrecision]);
253
-
254
- const _arcs = useMemo(() => {
255
- const seriesLength = series.size;
256
- if (!seriesLength) return [];
257
- const _series = [...series.values()];
258
- return arcs.map((arc, index) => getArc(radius, arc, _series[index]));
259
- }, [series, arcs, radius]);
260
-
261
- const onClick = useCallback(
262
- (e) =>
263
- onEvent({
264
- currentIndex: +e.currentTarget.dataset.index,
265
- type: 'onClick',
266
- }),
267
- [onEvent]
268
- );
269
-
270
- const onMouseEnter = useCallback(
271
- (e) =>
272
- onEvent({
273
- currentIndex: +e.currentTarget.dataset.index,
274
- type: 'onMouseEnter',
275
- }),
276
- [onEvent]
277
- );
278
-
279
- const onMouseLeave = useCallback(
280
- (e) =>
281
- onEvent({
282
- currentIndex: +e.currentTarget.dataset.index,
283
- type: 'onMouseLeave',
284
- }),
285
- [onEvent]
286
- );
287
-
288
- useLayoutEffect(() => {
289
- let animation;
290
- if (!!on) {
291
- animation = animate({
292
- from: 0,
293
- to: 1,
294
- duration: 500,
295
- ease: linear,
296
- onPlay: () => {},
297
- onUpdate: (v) => {
298
- setY(v);
299
- },
300
- onComplete: () => {
301
- const _data = arcs[+currentIndex].data;
302
- triggerOnRelative(_data);
303
- onEmit('carousel', _data);
304
- },
305
- });
306
- } else {
307
- if (currentIndex !== null && trigger === 'onClick') {
308
- const _data = arcs[+currentIndex].data;
309
- triggerOnRelative(_data);
310
- onEmit(trigger, _data);
311
- }
312
- }
313
- return () => {
314
- prevIndex.current = currentIndex;
315
- animation && animation.stop();
316
- animation = null;
317
- };
318
- }, [
319
- JSON.stringify(arcs),
320
- on,
321
- currentIndex,
322
- trigger,
323
- onEmit,
324
- triggerOnRelative,
325
- ]);
326
-
327
- const halfChartWidth = chartWidth / 2;
328
- const halfChartHeight = chartHeight / 2;
329
-
330
- return (
331
- <>
332
- <ChartContainer
333
- width={width}
334
- height={height}
335
- marginLeft={marginLeft}
336
- marginTop={marginTop}
337
- >
338
- <g
339
- transform={
340
- 'translate(' + halfChartWidth + ', ' + halfChartHeight + ')'
341
- }
342
- >
343
- {_arcs.map(
344
- ({ id, value, series, arc, innerRadius, outerRadius, index: dataIndex }, index) => {
345
- const current = index == currentIndex;
346
-
347
- const prev = index == prevIndex.current;
348
- // const offset = current ? y : prev ? 1 - y : 0;
349
- const offset = current ? y : prev ? 1 - y : 0;
350
-
351
- const fillOpacity = current ? opacity / 100 : 1;
352
-
353
- const path = arc
354
- .innerRadius(innerRadius + offset * heighten)
355
- .outerRadius(outerRadius + offset * heighten)(value);
356
-
357
- const pie = getColorList(series.color);
358
- return (
359
- <Fragment key={index}>
360
- <path
361
- data-index={dataIndex}
362
- onClick={onClick}
363
- onMouseEnter={onMouseEnter}
364
- onMouseLeave={onMouseLeave}
365
- d={path}
366
- stroke={show ? color : 'none'}
367
- strokeWidth={show ? strokeWidth : '0'}
368
- fill={'url(#' + id + ')'}
369
- fillOpacity={fillOpacity}
370
- />
371
- <defs>
372
- <LinearGradient
373
- id={id}
374
- colors={pie}
375
- rotate={series.color.linear.angle + 180}
376
- // gradientUnits='objectBoundingBox'
377
- />
378
- </defs>
379
- </Fragment>
380
- );
381
- }
382
- )}
383
- {label && <Label config={label} arcs={_arcs} />}
384
- {current && (
385
- <g fillOpacity={y}>
386
- <Current
387
- config={current}
388
- data={_arcs}
389
- currentIndex={+currentIndex}
390
- />
391
- </g>
392
- )}
393
- </g>
394
- </ChartContainer>
395
- {decorate && (
396
- <ConicalGradient
397
- width={width}
398
- height={height}
399
- centerX={halfChartWidth + marginLeft}
400
- centerY={halfChartHeight + marginTop}
401
- config={decorate}
402
- arcs={_arcs}
403
- radius={radius}
404
- />
405
- )}
406
- <Legend {...legend} series={_arcs} formatter={formatter} />
407
- </>
408
- );
409
- }
410
- );
411
- const Current = ({
412
- config: {
413
- show,
414
- gap,
415
- name: { show: showName, font: nameFont },
416
- percent: {
417
- show: showPercent,
418
- font: percentFont,
419
- precision,
420
- translate: { x: translatePercentX, y: translatePercentY },
421
- },
422
- value: {
423
- show: showValue,
424
- font: valueFont,
425
- translate: { x: translateValueX, y: translateValueY },
426
- suffix: {
427
- show: showSuffix,
428
- fontSize,
429
- text,
430
- translate: { x: translateSuffixX, y: translateSuffixY },
431
- },
432
- },
433
- },
434
- data,
435
- currentIndex,
436
- }) => {
437
- const _data = useMemo(() => {
438
- const legendDataWithPercent = getDataWithPercent(data, precision);
439
- return sortPie(legendDataWithPercent, '');
440
- }, [data, precision]);
441
- const currentData = _data[currentIndex];
442
-
443
- if (!currentData) return null;
444
-
445
- const { displayName, fieldName, value, percent } = currentData;
446
-
447
- return (
448
- show && (
449
- <>
450
- {showName && (
451
- <text
452
- textAnchor='middle'
453
- dy={
454
- (showValue && showPercent
455
- ? -1
456
- : showValue || showPercent
457
- ? -0.5
458
- : 0) * gap
459
- }
460
- {...getFontStyle(nameFont, 'svg')}
461
- >
462
- {displayName || fieldName}
463
- </text>
464
- )}
465
- {showValue && (
466
- <text
467
- textAnchor='middle'
468
- dy={
469
- (showName && showPercent
470
- ? 0
471
- : showName && !showPercent
472
- ? 0.5
473
- : showPercent
474
- ? -0.5
475
- : 0) *
476
- gap +
477
- translateValueY
478
- }
479
- dx={translateValueX}
480
- {...getFontStyle(valueFont, 'svg')}
481
- >
482
- {value}
483
- {showSuffix && text && (
484
- <tspan
485
- dx={translateSuffixX}
486
- dy={translateSuffixY}
487
- fontSize={fontSize}
488
- >
489
- {text}
490
- </tspan>
491
- )}
492
- </text>
493
- )}
494
- {showPercent && (
495
- <text
496
- textAnchor='middle'
497
- dy={
498
- (showName && showValue ? 1 : showName || showValue ? 0.5 : 0) *
499
- gap +
500
- translatePercentY
501
- }
502
- dx={translatePercentX}
503
- {...getFontStyle(percentFont, 'svg')}
504
- >
505
- {percent + '%'}
506
- </text>
507
- )}
508
- </>
509
- )
510
- );
511
- };
512
-
513
- const Label = ({
514
- config: {
515
- lineLength,
516
- distance,
517
- mode,
518
- show,
519
- translate: { x: translateX, y: translateY },
520
- name: { show: showName, font: nameFont },
521
- value: {
522
- show: showValue,
523
- font: valueFont,
524
- suffix: {
525
- show: showSuffix,
526
- text,
527
- fontSize: suffixFontSize,
528
- translate: { x: suffixTranslateX, y: suffixTranslateY },
529
- },
530
- sameColor: valueSameColor = false,
531
- },
532
- percent: {
533
- show: showPercent,
534
- font: percentFont,
535
- precision,
536
- sameColor: percentSameColor = false,
537
- },
538
- },
539
- arcs,
540
- }) => {
541
- // const [labels, setLabels] = useState(null);
542
- // const [opacity, setOpacity] = useState(0);
543
-
544
- const _arcs = useMemo(
545
- () => getDataWithPercent(arcs, precision),
546
- [arcs, precision]
547
- );
548
-
549
- // useEffect(() => {
550
- // if (labels) {
551
- // const children = [...labels.children];
552
- // const bbox = children.reduce(
553
- // (prev, current) => {
554
- // const { topRight, bottomRight, bottomLeft, topLeft } = prev;
555
- // const { x, y, height } = current.getBBox();
556
-
557
- // current._y1 = y;
558
- // current._y2 = y + height;
559
- // current._delta = 0;
560
-
561
- // if (x > 0) {
562
- // if (y > 0) {
563
- // bottomRight.push(current);
564
- // } else {
565
- // topRight.push(current);
566
- // }
567
- // } else {
568
- // if (y > 0) {
569
- // bottomLeft.push(current);
570
- // } else {
571
- // topLeft.push(current);
572
- // }
573
- // }
574
- // return prev;
575
- // },
576
- // {
577
- // topRight: [],
578
- // bottomRight: [],
579
- // bottomLeft: [],
580
- // topLeft: [],
581
- // }
582
- // );
583
- // console.log('bbox: ', bbox);
584
- // }
585
- // }, [labels]);
586
-
587
- return (
588
- <g
589
- // style={{ opacity }} ref={setLabels}
590
- >
591
- {_arcs.map(
592
- (
593
- {
594
- series: {
595
- color: {
596
- type,
597
- pure,
598
- linear: { stops },
599
- },
600
- },
601
- displayName,
602
- value,
603
- percent,
604
- arc,
605
- outerRadius,
606
- },
607
- index
608
- ) => {
609
- const [x, y] = arc.centroid();
610
-
611
- const midAngle = Math.atan2(y, x);
612
-
613
- const [x1, y1] = getCoord(midAngle, outerRadius);
614
-
615
- const radius = outerRadius + distance;
616
- const [x2, y2] = getCoord(midAngle, radius);
617
-
618
- const direction = x2 < 0 ? -1 : 1;
619
- const x3 = x2 + lineLength * direction;
620
-
621
- const _x = x3 + (translateX + 6) * direction;
622
-
623
- const _showName = showName && displayName;
624
- const _showValue = showValue && (value || showSuffix);
625
-
626
- return (
627
- show &&
628
- (_showName || showPercent || _showValue) && (
629
- <g key={index}>
630
- <path
631
- d={
632
- 'M' +
633
- x1 +
634
- ', ' +
635
- y1 +
636
- 'L' +
637
- x2 +
638
- ', ' +
639
- y2 +
640
- 'L' +
641
- x3 +
642
- ', ' +
643
- y2
644
- }
645
- stroke={type == 'pure' ? pure : stops[0].color}
646
- fill='none'
647
- />
648
- <text
649
- x={_x}
650
- y={y2 + translateY}
651
- dominantBaseline='middle'
652
- textAnchor={x3 >= 0 ? 'start' : 'end'}
653
- >
654
- {_showName && (
655
- <tspan style={getFontStyle(nameFont, 'svg')}>
656
- {displayName + (showValue || showPercent ? ':' : '')}
657
- </tspan>
658
- )}
659
- {_showValue && (
660
- <>
661
- <tspan
662
- x={!!(_showName && mode == 'vertical') ? _x : ''}
663
- dx={valueDx(_showName, mode)}
664
- dy={!!(_showName && mode == 'vertical') ? '1.5em' : ''}
665
- style={getFontStyle(valueFont, 'svg')}
666
- >
667
- {value}
668
- </tspan>
669
- {showSuffix && (
670
- <tspan
671
- style={{
672
- ...getFontStyle(valueFont, 'svg'),
673
- fontSize: suffixFontSize,
674
- }}
675
- dx={suffixTranslateX}
676
- dy={suffixTranslateY}
677
- >
678
- {text}
679
- </tspan>
680
- )}
681
- </>
682
- )}
683
- {showPercent && (
684
- <tspan
685
- x={percentX(_showName, _showValue, mode, _x)}
686
- dx={percentDx(_showName, _showValue, mode)}
687
- dy={
688
- percentDy(_showName, _showValue, mode) +
689
- (_showValue && showSuffix ? suffixTranslateY * -1 : 0)
690
- }
691
- style={getFontStyle(percentFont, 'svg')}
692
- >
693
- {(_showValue ? '(' : '') +
694
- percent +
695
- '%' +
696
- (_showValue ? ')' : '')}
697
- </tspan>
698
- )}
699
- </text>
700
- </g>
701
- )
702
- );
703
- }
704
- )}
705
- </g>
706
- );
707
- };
708
-
709
- export default Mapping(Carousel(Component));
1
+ /**
2
+ * 饼环图
3
+ */
4
+ import React, {
5
+ memo,
6
+ useMemo,
7
+ useCallback,
8
+ useRef,
9
+ useState,
10
+ useContext,
11
+ useLayoutEffect,
12
+ Fragment,
13
+ } from 'react';
14
+ import { ChartContainer, Carousel, Legend, ConicalGradient, Mapping } from '.';
15
+ import { chartContext } from '../context';
16
+ import {
17
+ getFontStyle,
18
+ sortPie,
19
+ getDataWithPercent,
20
+ getColorList,
21
+ } from '../utils';
22
+ import { pie, arc, extent, scaleLinear } from 'd3v7';
23
+ import { animate, linear } from 'popmotion';
24
+ import LinearGradient from './LinearGradient';
25
+ import { pieLegendFormatter as legendFormatter } from '../formatter';
26
+ import ringCss from '../css/piechart.module.css';
27
+
28
+ const PI = Math.PI;
29
+
30
+ const defaultChart = {
31
+ outerRadius: 1,
32
+ innerRadius: 0,
33
+ cornerRadius: 0,
34
+ rose: false,
35
+ roseType: 'radius',
36
+ baseRadius: 0,
37
+ padAngle: 0,
38
+ };
39
+ const defaultAngle = { startAngle: 0, endAngle: 360, antiClockwise: false };
40
+
41
+ const percentX = (showName, showValue, mode, x) => {
42
+ if (showValue) {
43
+ return '';
44
+ }
45
+ if (showName) {
46
+ if (mode == 'vertical') {
47
+ return x;
48
+ } else {
49
+ return '';
50
+ }
51
+ } else {
52
+ return x;
53
+ }
54
+ };
55
+
56
+ const percentDx = (showName, showValue, mode) => {
57
+ if (showValue) {
58
+ return '0.5em';
59
+ }
60
+ if (showName) {
61
+ if (mode == 'vertical') {
62
+ return 0;
63
+ } else {
64
+ return '0.5em';
65
+ }
66
+ } else {
67
+ return 0;
68
+ }
69
+ };
70
+
71
+ const percentDy = (showName, showValue, mode) => {
72
+ if (showValue) {
73
+ return 0;
74
+ }
75
+ if (showName) {
76
+ if (mode == 'vertical') {
77
+ return '1.5em';
78
+ } else {
79
+ return 0;
80
+ }
81
+ } else {
82
+ return 0;
83
+ }
84
+ };
85
+
86
+ const valueDx = (showName, mode) => {
87
+ if (!showName) {
88
+ return '';
89
+ }
90
+ if (mode == 'vertical') {
91
+ return '';
92
+ } else {
93
+ return '0.5em';
94
+ }
95
+ };
96
+
97
+ const getCoord = (deg, radius) => {
98
+ var x = Math.cos(deg) * radius,
99
+ y = Math.sin(deg) * radius;
100
+ return [x, y];
101
+ };
102
+
103
+ const getRoseRadius = ({ innerRadius, baseRadius }) =>
104
+ innerRadius + (1 - innerRadius) * baseRadius;
105
+
106
+ const getAngle = ({ startAngle, endAngle, antiClockwise, ...rest }) => {
107
+ if (antiClockwise)
108
+ return {
109
+ ...rest,
110
+ startAngle: endAngle - 180,
111
+ endAngle: startAngle - 180,
112
+ };
113
+ return { ...rest, startAngle, endAngle };
114
+ };
115
+
116
+ const getArc = (
117
+ radius,
118
+ {
119
+ padAngle = 0,
120
+ innerRadius = 0,
121
+ outerRadius = 1,
122
+ cornerRadius = 0,
123
+ startAngle = 0,
124
+ endAngle = 360,
125
+ ...rest
126
+ },
127
+ series
128
+ ) => ({
129
+ ...rest,
130
+ type: 'pie',
131
+ fieldName: series.fieldName,
132
+ displayName: series.displayName || rest.data.s,
133
+ series: series,
134
+ innerRadius: innerRadius * radius,
135
+ outerRadius: outerRadius * radius,
136
+ arc: arc()
137
+ .innerRadius(innerRadius * radius)
138
+ .outerRadius(outerRadius * radius)
139
+ .cornerRadius(cornerRadius)
140
+ .startAngle(startAngle)
141
+ .endAngle(endAngle)
142
+ .padAngle(padAngle),
143
+ });
144
+
145
+ const getCircleScale = ({ count, color, width, length }=tick, radius)=>{
146
+ let data = [],
147
+ arcs = [],
148
+ centroids = [];
149
+ for (let i = 0; i < count; i++) {
150
+ data.push(1);
151
+ }
152
+ let scaleData = pie()(data);
153
+ scaleData.map((data) => {
154
+ let _arc = arc()
155
+ .innerRadius(radius + length/2)
156
+ .outerRadius(radius + length/2)
157
+ .startAngle(data.startAngle)
158
+ .endAngle(data.endAngle);
159
+ arcs.push(_arc());
160
+ centroids.push(_arc.centroid());
161
+ });
162
+ return (
163
+ <g>
164
+ {centroids.map((center, index) => {
165
+ let x = center[0],
166
+ y = center[1];
167
+ let rate = length / Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
168
+ return (
169
+ <path
170
+ key={index}
171
+ d={`M${x},${y}l${x * rate},${y * rate}`}
172
+ strokeWidth={width}
173
+ stroke={color}
174
+ />
175
+ );
176
+ })}
177
+ </g>
178
+ );
179
+ }
180
+
181
+ const Component = memo(
182
+ ({
183
+ config: {
184
+ chart: {
185
+ dimension: {
186
+ chartDimension: { width, height },
187
+ },
188
+ label,
189
+ legend: { formatter = legendFormatter, ...legend },
190
+ margin: { marginLeft, marginTop },
191
+ },
192
+ fan: {
193
+ chart = defaultChart,
194
+ chart: { outerRadius = defaultChart.outerRadius,padAngle },
195
+ angle = defaultAngle,
196
+ stroke: { show, strokeWidth, color } = { show: false },
197
+ decorate,
198
+ decorate2,
199
+ categoryText,
200
+ outerDecorate,
201
+ current,
202
+ } = {},
203
+ order,
204
+ series,
205
+ animation: {
206
+ on,
207
+ current: { heighten=0, opacity=0, width:radiusWidthAdd=0, color:animateColor, gap=0 },
208
+ rotate = 0
209
+ },
210
+ },
211
+ state: { currentIndex, trigger },
212
+ onEvent,
213
+ data = [],
214
+ }) => {
215
+ const prevIndex = useRef(null);
216
+ const { precision: legendPrecision } = legend.config.percent;
217
+ const {
218
+ id,
219
+ width: chartWidth,
220
+ height: chartHeight,
221
+ triggerOnRelative,
222
+ onEmit,
223
+ } = useContext(chartContext);
224
+
225
+ const [y, setY] = useState(1);
226
+ const radius = (Math.min(chartWidth, chartHeight) / 2) * outerRadius;
227
+
228
+ const arcsFunc = useMemo(() => {
229
+ const { startAngle = 0, endAngle = 360 } = getAngle(angle);
230
+ const arcsFunc = pie()
231
+ .startAngle((startAngle * PI) / 180)
232
+ .endAngle((endAngle * PI) / 180)
233
+ .value((d) => d.y);
234
+ return arcsFunc;
235
+ }, [angle]);
236
+
237
+ const arcs = useMemo(() => {
238
+ const _chart = Object.assign(defaultChart, chart);
239
+ const {
240
+ innerRadius,
241
+ outerRadius,
242
+ rose,
243
+ cornerRadius,
244
+ padAngle,
245
+ roseType,
246
+ } = _chart;
247
+ const _padAngle = (padAngle * Math.PI) / 180;
248
+
249
+ switch (order) {
250
+ case '':
251
+ arcsFunc.sort(null);
252
+ break;
253
+ case 'desc':
254
+ arcsFunc.sort((a, b) => b.y - a.y);
255
+ break;
256
+ case 'asc':
257
+ arcsFunc.sort((a, b) => a.y - b.y);
258
+ break;
259
+ }
260
+
261
+ const arcs = arcsFunc(data);
262
+ const legendDataWithPercent = getDataWithPercent(arcs, legendPrecision);
263
+ const _legendDataWithPercent = sortPie(legendDataWithPercent, order);
264
+
265
+ if (rose) {
266
+ const domain = extent(_legendDataWithPercent, (d) => d.value);
267
+ const roseRadius = getRoseRadius(_chart);
268
+ const scaler = scaleLinear().domain(domain).range([roseRadius, 1]);
269
+
270
+ const angle = (PI * 2) / _legendDataWithPercent.length;
271
+ return _legendDataWithPercent.map(
272
+ ({ startAngle, endAngle, ...arc }, index) => ({
273
+ ...arc,
274
+ id: id + '_linear_' + index,
275
+ startAngle: roseType == 'area' ? angle * index : startAngle,
276
+ endAngle: roseType == 'area' ? angle * (index + 1) : endAngle,
277
+ cornerRadius,
278
+ padAngle: _padAngle,
279
+ innerRadius,
280
+ outerRadius: scaler(arc.value),
281
+ })
282
+ );
283
+ }
284
+ return _legendDataWithPercent.map((arc, index) => ({
285
+ ...arc,
286
+ id: id + '_linear_' + index,
287
+ cornerRadius,
288
+ padAngle: _padAngle,
289
+ innerRadius,
290
+ outerRadius,
291
+ }));
292
+ }, [data, arcsFunc, chart, legendPrecision]);
293
+
294
+ const _arcs = useMemo(() => {
295
+ const seriesLength = series.size;
296
+ if (!seriesLength) return [];
297
+ const _series = [...series.values()];
298
+ return arcs.map((arc, index) => getArc(radius, arc, _series[index]));
299
+ }, [series, arcs, radius]);
300
+ const onClick = useCallback(
301
+ (e) =>
302
+ onEvent({
303
+ currentIndex: +e.currentTarget.dataset.index,
304
+ type: 'onClick',
305
+ }),
306
+ [onEvent]
307
+ );
308
+
309
+ const onMouseEnter = useCallback(
310
+ (e) =>
311
+ onEvent({
312
+ currentIndex: +e.currentTarget.dataset.index,
313
+ type: 'onMouseEnter',
314
+ }),
315
+ [onEvent]
316
+ );
317
+
318
+ const onMouseLeave = useCallback(
319
+ (e) =>
320
+ onEvent({
321
+ currentIndex: +e.currentTarget.dataset.index,
322
+ type: 'onMouseLeave',
323
+ }),
324
+ [onEvent]
325
+ );
326
+
327
+ useLayoutEffect(() => {
328
+ let animation;
329
+ if (!!on) {
330
+ animation = animate({
331
+ from: 0,
332
+ to: 1,
333
+ duration: 500,
334
+ ease: linear,
335
+ onPlay: () => {},
336
+ onUpdate: (v) => {
337
+ setY(v);
338
+ },
339
+ onComplete: () => {
340
+ const _data = arcs[+currentIndex].data;
341
+ triggerOnRelative(_data);
342
+ onEmit('carousel', _data);
343
+ },
344
+ });
345
+ } else {
346
+ if (currentIndex !== null && trigger === 'onClick') {
347
+ const _data = arcs[+currentIndex].data;
348
+ triggerOnRelative(_data);
349
+ onEmit(trigger, _data);
350
+ }
351
+ }
352
+ return () => {
353
+ prevIndex.current = currentIndex;
354
+ animation && animation.stop();
355
+ animation = null;
356
+ };
357
+ }, [
358
+ JSON.stringify(arcs),
359
+ on,
360
+ currentIndex,
361
+ trigger,
362
+ onEmit,
363
+ triggerOnRelative,
364
+ ]);
365
+
366
+ const halfChartWidth = chartWidth / 2;
367
+ const halfChartHeight = chartHeight / 2;
368
+
369
+ const rotate_ = decorate2?-(arcs[+currentIndex].startAngle+arcs[+currentIndex].endAngle)*90/Math.PI+rotate:0;
370
+ let maxRadius = 0;
371
+ _arcs.map(d=>{
372
+ maxRadius=Math.max(maxRadius,d.outerRadius);
373
+ })
374
+ let centerRadius =0.5*maxRadius + 0.5*_arcs[0].innerRadius
375
+ return (
376
+ outerDecorate?<>
377
+ <ChartContainer //用于生成甜甜圈图,判断依据是外环装饰这个配置项(outerDecorate)
378
+ width={width}
379
+ height={height}
380
+ marginLeft={marginLeft}
381
+ marginTop={marginTop}
382
+ >
383
+ <g
384
+ style={{
385
+ transition:"transform ease-in-out 0.3s",
386
+ transform:'translate(' + halfChartWidth + 'px, ' + halfChartHeight + 'px) rotate('+rotate_+"deg)"
387
+ }}
388
+ >
389
+ {
390
+ //用于生成外环装饰的刻度
391
+ outerDecorate.tick.show && getCircleScale(outerDecorate.tick, maxRadius)
392
+ }
393
+ <circle //外环装饰
394
+ cx='0'
395
+ cy='0'
396
+ r={maxRadius+2}
397
+ fill='none'
398
+ stroke={outerDecorate.color}
399
+ strokeWidth={outerDecorate.width}
400
+ />
401
+ {
402
+ _arcs.map(
403
+ ({ id, value, series, arc, innerRadius, outerRadius, index: dataIndex }, index) => {
404
+ const arcWidth = (outerRadius-innerRadius);
405
+ const path = arc
406
+ .innerRadius(centerRadius)
407
+ .outerRadius(centerRadius)(value);
408
+ const dashLength=Math.ceil(Math.PI*(centerRadius)*2/_arcs.length);
409
+ const pie = getColorList(series.color);
410
+ return (
411
+ <Fragment key={index}>
412
+ <path
413
+ className={ringCss['inner-arc']}
414
+ style={{
415
+ strokeDasharray:`${dashLength},${2*dashLength}`,
416
+ strokeDashoffset: dashLength,
417
+ animationDelay: `${index * 2000}ms`
418
+ }}
419
+ data-index={dataIndex}
420
+ onClick={onClick}
421
+ onMouseEnter={onMouseEnter}
422
+ onMouseLeave={onMouseLeave}
423
+ d={path.split("L")[0]}
424
+ stroke={'url(#' + id + ')'}
425
+ strokeWidth={arcWidth}
426
+ fill="none"
427
+ />
428
+ <defs>
429
+ <LinearGradient
430
+ id={id}
431
+ colors={pie}
432
+ rotate={series.color.linear.angle + 180}
433
+ // gradientUnits='objectBoundingBox'
434
+ />
435
+ </defs>
436
+ </Fragment>
437
+ );
438
+ }
439
+ )
440
+ }
441
+ {label && <Label config={{...label,maxRadius: maxRadius+2}} arcs={_arcs} animation={true}/>}
442
+ </g>
443
+ </ChartContainer>
444
+ <Legend {...legend} series={_arcs} formatter={formatter}/>
445
+ </> : <>
446
+ <ChartContainer
447
+ width={width}
448
+ height={height}
449
+ marginLeft={marginLeft}
450
+ marginTop={marginTop}
451
+ >
452
+ <g
453
+ style={{
454
+ transition:"transform ease-in-out 0.3s",
455
+ transform:'translate(' + halfChartWidth + 'px, ' + halfChartHeight + 'px) rotate('+rotate_+"deg)"
456
+ }}
457
+ >
458
+ {_arcs.map(
459
+ ({ id, value, series, arc, innerRadius, outerRadius, index: dataIndex }, index) => {
460
+ const current = index == currentIndex;
461
+ const prev = index == prevIndex.current;
462
+ const offset = current ? y : prev ? 1 - y : 0;
463
+
464
+ const fillOpacity = animateColor?1:(current ? opacity / 100 : 1);
465
+ const deltaHeighten= offset*heighten;
466
+ const path = arc
467
+ .innerRadius(innerRadius + deltaHeighten)
468
+ .outerRadius(outerRadius + deltaHeighten)(value);
469
+ const pie = getColorList(series.color);
470
+ const currentPie = animateColor?getColorList(animateColor):getColorList(series.color);
471
+ let textPath="",categoryTextStyle={};
472
+ if(categoryText && categoryText.show){ //如果有类目文本,则需要计算文字路径
473
+ //let offsetWidth=decorate2.radiusWidth/2 + radiusWidthAdd/2; //当前文字需生成在装饰物内,故而半径需要减小
474
+ let textArc=arc.innerRadius(outerRadius+(current?gap:categoryText.gap))
475
+ .outerRadius(outerRadius+(current?gap:categoryText.gap))(value);
476
+ let lastA=textArc.lastIndexOf('A');
477
+ textPath=textArc.slice(0, lastA > 0 ? lastA : textArc.length); //文字路径
478
+ categoryTextStyle=categoryText.textStyle; //这里把textstyle拿出来
479
+ }
480
+
481
+ return (
482
+ <Fragment key={index}>
483
+ <path
484
+ data-index={dataIndex}
485
+ onClick={onClick}
486
+ onMouseEnter={onMouseEnter}
487
+ onMouseLeave={onMouseLeave}
488
+ d={path}
489
+ stroke={show ? color : 'none'}
490
+ strokeWidth={show ? strokeWidth : '0'}
491
+ fill={'url(#' + id + ')'}
492
+ fillOpacity={fillOpacity}
493
+ />
494
+ { //装饰物2,产生于每个弧的外部
495
+ decorate2 && decorate2.show &&
496
+ <path
497
+ data-index={dataIndex}
498
+ onClick={onClick}
499
+ onMouseEnter={onMouseEnter}
500
+ onMouseLeave={onMouseLeave}
501
+ d={arc.innerRadius(outerRadius)
502
+ .outerRadius(outerRadius + decorate2.radiusWidth + radiusWidthAdd)(value)}
503
+ stroke={show ? color : 'none'}
504
+ strokeWidth={show ? strokeWidth : '0'}
505
+ fill={'url(#' + id + ')'}
506
+ fillOpacity={decorate2.opacity/100}
507
+ />
508
+ }
509
+ { //类目文本
510
+ categoryText && categoryText.show &&<g>
511
+ <path
512
+ onClick={onClick}
513
+ onMouseEnter={onMouseEnter}
514
+ onMouseLeave={onMouseLeave}
515
+ id={id + '_text_' + index}
516
+ d={textPath}
517
+ fill='none'
518
+ stroke='none'
519
+ />
520
+ <text
521
+ textAnchor='middle'
522
+ style={{
523
+ ...categoryTextStyle,
524
+ fontWeight:categoryTextStyle.bold?"bold":"normal",
525
+ fontStyle:categoryTextStyle.italic?"italic":"normal"
526
+ }}
527
+ fill={categoryText.textStyle.color}
528
+ >
529
+ <textPath
530
+ startOffset='50%'
531
+ href={'#' + id + '_text_' + index}
532
+ >
533
+ {_arcs[index].displayName || _arcs[index].fieldName}
534
+ </textPath>
535
+ </text>
536
+ </g>
537
+ }
538
+ <defs>
539
+ <LinearGradient
540
+ id={id}
541
+ colors={current?currentPie:pie}
542
+ rotate={current?(animateColor?animateColor.linear.angle + 180:series.color.linear.angle + 180):series.color.linear.angle + 180}
543
+ // gradientUnits='objectBoundingBox'
544
+ />
545
+ </defs>
546
+ </Fragment>
547
+ );
548
+ }
549
+ )}
550
+ {label && <Label config={label} arcs={_arcs} />}
551
+ {current && (
552
+ <g fillOpacity={y} style={{transform:"rotate("+(-rotate_)+"deg)"}}>
553
+ <Current
554
+ config={current}
555
+ data={_arcs}
556
+ currentIndex={+currentIndex}
557
+ />
558
+ </g>
559
+ )}
560
+ </g>
561
+ </ChartContainer>
562
+ {decorate && (
563
+ <ConicalGradient
564
+ width={width}
565
+ height={height}
566
+ centerX={halfChartWidth + marginLeft}
567
+ centerY={halfChartHeight + marginTop}
568
+ config={decorate}
569
+ arcs={_arcs}
570
+ radius={radius}
571
+ />
572
+ )}
573
+ <Legend {...legend} series={_arcs} formatter={formatter} />
574
+ </>
575
+ );
576
+ }
577
+ );
578
+
579
+ const Current = ({
580
+ config: {
581
+ show,
582
+ gap,
583
+ name: { show: showName, font: nameFont },
584
+ percent: {
585
+ show: showPercent,
586
+ font: percentFont,
587
+ precision,
588
+ translate: { x: translatePercentX, y: translatePercentY },
589
+ },
590
+ value: {
591
+ show: showValue,
592
+ font: valueFont,
593
+ translate: { x: translateValueX, y: translateValueY },
594
+ suffix: {
595
+ show: showSuffix,
596
+ fontSize,
597
+ text,
598
+ translate: { x: translateSuffixX, y: translateSuffixY },
599
+ },
600
+ },
601
+ },
602
+ data,
603
+ currentIndex,
604
+ }) => {
605
+ const _data = useMemo(() => {
606
+ const legendDataWithPercent = getDataWithPercent(data, precision);
607
+ return sortPie(legendDataWithPercent, '');
608
+ }, [data, precision]);
609
+ const currentData = _data[currentIndex];
610
+
611
+ if (!currentData) return null;
612
+
613
+ const { displayName, fieldName, value, percent } = currentData;
614
+
615
+ return (
616
+ show && (
617
+ <>
618
+ {showName && (
619
+ <text
620
+ textAnchor='middle'
621
+ dy={
622
+ (showValue && showPercent
623
+ ? -1
624
+ : showValue || showPercent
625
+ ? -0.5
626
+ : 0) * gap
627
+ }
628
+ {...getFontStyle(nameFont, 'svg')}
629
+ >
630
+ {displayName || fieldName}
631
+ </text>
632
+ )}
633
+ {showValue && (
634
+ <text
635
+ textAnchor='middle'
636
+ dy={
637
+ (showName && showPercent
638
+ ? 0
639
+ : showName && !showPercent
640
+ ? 0.5
641
+ : showPercent
642
+ ? -0.5
643
+ : 0) *
644
+ gap +
645
+ translateValueY
646
+ }
647
+ dx={translateValueX}
648
+ {...getFontStyle(valueFont, 'svg')}
649
+ >
650
+ {value}
651
+ {showSuffix && text && (
652
+ <tspan
653
+ dx={translateSuffixX}
654
+ dy={translateSuffixY}
655
+ fontSize={fontSize}
656
+ >
657
+ {text}
658
+ </tspan>
659
+ )}
660
+ </text>
661
+ )}
662
+ {showPercent && (
663
+ <text
664
+ textAnchor='middle'
665
+ dy={
666
+ (showName && showValue ? 1 : showName || showValue ? 0.5 : 0) *
667
+ gap +
668
+ translatePercentY
669
+ }
670
+ dx={translatePercentX}
671
+ {...getFontStyle(percentFont, 'svg')}
672
+ >
673
+ {percent + '%'}
674
+ </text>
675
+ )}
676
+ </>
677
+ )
678
+ );
679
+ };
680
+
681
+ const Label = ({
682
+ config: {
683
+ maxRadius = 0,
684
+ lineLength,
685
+ lineColor,
686
+ distance,
687
+ mode,
688
+ show,
689
+ translate: { x: translateX, y: translateY },
690
+ name: { show: showName, font: nameFont },
691
+ value: {
692
+ show: showValue,
693
+ font: valueFont,
694
+ suffix: {
695
+ show: showSuffix,
696
+ text,
697
+ fontSize: suffixFontSize,
698
+ translate: { x: suffixTranslateX, y: suffixTranslateY },
699
+ },
700
+ sameColor: valueSameColor = false,
701
+ },
702
+ percent: {
703
+ show: showPercent,
704
+ font: percentFont,
705
+ precision,
706
+ sameColor: percentSameColor = false,
707
+ },
708
+ },
709
+ arcs,
710
+ animation
711
+ }) => {
712
+ // const [labels, setLabels] = useState(null);
713
+ // const [opacity, setOpacity] = useState(0);
714
+
715
+ const _arcs = useMemo(
716
+ () => getDataWithPercent(arcs, precision),
717
+ [arcs, precision]
718
+ );
719
+ // useEffect(() => {
720
+ // if (labels) {
721
+ // const children = [...labels.children];
722
+ // const bbox = children.reduce(
723
+ // (prev, current) => {
724
+ // const { topRight, bottomRight, bottomLeft, topLeft } = prev;
725
+ // const { x, y, height } = current.getBBox();
726
+
727
+ // current._y1 = y;
728
+ // current._y2 = y + height;
729
+ // current._delta = 0;
730
+
731
+ // if (x > 0) {
732
+ // if (y > 0) {
733
+ // bottomRight.push(current);
734
+ // } else {
735
+ // topRight.push(current);
736
+ // }
737
+ // } else {
738
+ // if (y > 0) {
739
+ // bottomLeft.push(current);
740
+ // } else {
741
+ // topLeft.push(current);
742
+ // }
743
+ // }
744
+ // return prev;
745
+ // },
746
+ // {
747
+ // topRight: [],
748
+ // bottomRight: [],
749
+ // bottomLeft: [],
750
+ // topLeft: [],
751
+ // }
752
+ // );
753
+ // console.log('bbox: ', bbox);
754
+ // }
755
+ // }, [labels]);
756
+
757
+ return (
758
+ <g
759
+ // style={{ opacity }} ref={setLabels}
760
+ >
761
+ {_arcs.map(
762
+ (
763
+ {
764
+ series: {
765
+ color: {
766
+ type,
767
+ pure,
768
+ linear: { stops },
769
+ },
770
+ },
771
+ displayName,
772
+ value,
773
+ percent,
774
+ arc,
775
+ outerRadius,
776
+ index:actualIndex
777
+ },
778
+ index
779
+ ) => {
780
+
781
+ const [x, y] = arc.centroid();
782
+
783
+ const midAngle = Math.atan2(y, x);
784
+
785
+ const [x1, y1] = getCoord(midAngle, maxRadius?maxRadius:outerRadius);
786
+
787
+ const radius = (maxRadius?maxRadius:outerRadius) + distance;
788
+ const [x2, y2] = getCoord(midAngle, radius);
789
+
790
+ const direction = x2 < 0 ? -1 : 1;
791
+ const x3 = x2 + lineLength * direction;
792
+
793
+ const _x = x3 + (translateX + 6) * direction;
794
+
795
+ const _showName = showName && displayName;
796
+ const _showValue = showValue && (value || showSuffix);
797
+
798
+ return (
799
+ show &&
800
+ (_showName || showPercent || _showValue) && (
801
+ <g key={index}>
802
+ <path
803
+ className={animation? ringCss['label-line']:""}
804
+ style={{ animationDelay:`${animation? ((actualIndex+1) * 2000 - 800) : 0}ms`}}
805
+ d={
806
+ 'M' + x1 + ', ' + y1 + 'L' +
807
+ x2 + ', ' + y2 + 'L' +
808
+ x3 + ', ' + y2
809
+ }
810
+ stroke={lineColor?lineColor:(type == 'pure' ? pure : stops[0].color)}
811
+ fill='none'
812
+ />
813
+ <text
814
+ className={animation? ringCss['label-text']:""}
815
+ style={{ animationDelay:`${animation? ((actualIndex+1) * 2000 - 800) : 0}ms`}}
816
+ x={_x}
817
+ y={y2 + translateY}
818
+ dominantBaseline='middle'
819
+ textAnchor={x3 >= 0 ? 'start' : 'end'}
820
+ >
821
+ {_showName && (
822
+ <tspan style={getFontStyle(nameFont, 'svg')}>
823
+ {displayName + (showValue || showPercent ? ':' : '')}
824
+ </tspan>
825
+ )}
826
+ {_showValue && (
827
+ <>
828
+ <tspan
829
+ x={!!(_showName && mode == 'vertical') ? _x : ''}
830
+ dx={valueDx(_showName, mode)}
831
+ dy={!!(_showName && mode == 'vertical') ? '1.5em' : ''}
832
+ style={getFontStyle(valueFont, 'svg')}
833
+ >
834
+ {value}
835
+ </tspan>
836
+ {showSuffix && (
837
+ <tspan
838
+ style={{
839
+ ...getFontStyle(valueFont, 'svg'),
840
+ fontSize: suffixFontSize,
841
+ }}
842
+ dx={suffixTranslateX}
843
+ dy={suffixTranslateY}
844
+ >
845
+ {text}
846
+ </tspan>
847
+ )}
848
+ </>
849
+ )}
850
+ {showPercent && (
851
+ <tspan
852
+ x={percentX(_showName, _showValue, mode, _x)}
853
+ dx={percentDx(_showName, _showValue, mode)}
854
+ dy={
855
+ percentDy(_showName, _showValue, mode) +
856
+ (_showValue && showSuffix ? suffixTranslateY * -1 : "")
857
+ }
858
+ style={getFontStyle(percentFont, 'svg')}
859
+ >
860
+ {(_showValue ? '(' : '') +
861
+ percent +
862
+ '%' +
863
+ (_showValue ? ')' : '')}
864
+ </tspan>
865
+ )}
866
+ </text>
867
+ </g>
868
+ )
869
+ );
870
+ }
871
+ )}
872
+ </g>
873
+ );
874
+ };
875
+
876
+ export default Mapping(Carousel(Component));