1
- export function makeDonut ( item , cx , cy , rx , ry ) {
1
+ export function makeDonut ( item , cx , cy , rx , ry , piProportion = 1.99999 , piMult = 2 , arcAmpl = 1.45 , degrees = 360 , rotation = 105.25 , size = 0 ) {
2
2
let { series } = item ;
3
3
if ( ! series || item . base === 0 )
4
4
return {
@@ -19,17 +19,31 @@ export function makeDonut(item, cx, cy, rx, ry) {
19
19
let acc = 0 ;
20
20
for ( let i = 0 ; i < series . length ; i += 1 ) {
21
21
let proportion = series [ i ] . value / sum ;
22
- const ratio = proportion * ( Math . PI * 1.9999 ) ; // (Math.PI * 2) fails to display a donut with only one value > 0 as it goes full circle again
22
+ const ratio = proportion * ( Math . PI * piProportion ) ; // (Math.PI * 2) fails to display a donut with only one value > 0 as it goes full circle again
23
23
// midProportion & midRatio are used to find the midpoint of the arc to display markers
24
24
const midProportion = series [ i ] . value / 2 / sum ;
25
- const midRatio = midProportion * ( Math . PI * 2 ) ;
25
+ const midRatio = midProportion * ( Math . PI * piMult ) ;
26
26
const { startX, startY, endX, endY, path } = createArc (
27
27
[ cx , cy ] ,
28
28
[ rx , ry ] ,
29
29
[ acc , ratio ] ,
30
- 110
30
+ rotation ,
31
+ degrees ,
32
+ piMult
31
33
) ;
34
+
35
+ const inner = createArc (
36
+ [ cx , cy ] ,
37
+ [ rx - size , ry - size ] ,
38
+ [ acc , ratio ] ,
39
+ rotation ,
40
+ degrees ,
41
+ piMult ,
42
+ true
43
+ )
44
+
32
45
ratios . push ( {
46
+ arcSlice : `${ path } L ${ inner . startX } ${ inner . startY } ${ inner . path } L ${ startX } ${ startY } ` ,
33
47
cx,
34
48
cy,
35
49
...series [ i ] ,
@@ -42,9 +56,11 @@ export function makeDonut(item, cx, cy, rx, ry) {
42
56
endY,
43
57
center : createArc (
44
58
[ cx , cy ] ,
45
- [ rx * 1.45 , ry * 1.45 ] ,
59
+ [ rx * arcAmpl , ry * arcAmpl ] ,
46
60
[ acc , midRatio ] ,
47
- 110
61
+ rotation ,
62
+ degrees ,
63
+ piMult
48
64
) , // center of the arc, to display the marker. rx & ry are larger to be displayed with a slight offset
49
65
} ) ;
50
66
acc += ratio ;
@@ -67,8 +83,8 @@ export function rotateMatrix(x) {
67
83
] ;
68
84
}
69
85
70
- export function createArc ( [ cx , cy ] , [ rx , ry ] , [ position , ratio ] , phi ) {
71
- ratio = ratio % ( 2 * Math . PI ) ;
86
+ export function createArc ( [ cx , cy ] , [ rx , ry ] , [ position , ratio ] , phi , degrees = 360 , piMult = 2 , reverse = false ) {
87
+ ratio = ratio % ( piMult * Math . PI ) ;
72
88
const rotMatrix = rotateMatrix ( phi ) ;
73
89
const [ sX , sY ] = addVector (
74
90
matrixTimes ( rotMatrix , [
@@ -85,20 +101,20 @@ export function createArc([cx, cy], [rx, ry], [position, ratio], phi) {
85
101
[ cx , cy ]
86
102
) ;
87
103
const fA = ratio > Math . PI ? 1 : 0 ;
88
- const fS = ratio > 0 ? 1 : 0 ;
104
+ const fS = ratio > 0 ? reverse ? 0 : 1 : reverse ? 1 : 0 ;
89
105
return {
90
- startX : sX ,
91
- startY : sY ,
92
- endX : eX ,
93
- endY : eY ,
94
- path : `M${ sX } ${ sY } A ${ [
106
+ startX : reverse ? eX : sX ,
107
+ startY : reverse ? eY : sY ,
108
+ endX : reverse ? sX : eX ,
109
+ endY : reverse ? sY : eY ,
110
+ path : `M${ reverse ? eX : sX } ${ reverse ? eY : sY } A ${ [
95
111
rx ,
96
112
ry ,
97
- ( phi / ( 2 * Math . PI ) ) * 360 ,
113
+ ( phi / ( piMult * Math . PI ) ) * degrees ,
98
114
fA ,
99
115
fS ,
100
- eX ,
101
- eY ,
116
+ reverse ? sX : eX ,
117
+ reverse ? sY : eY ,
102
118
] . join ( " " ) } `,
103
119
} ;
104
120
}
@@ -629,13 +645,65 @@ export function calcMarkerOffsetY(arc, yOffsetTop = 16, yOffsetBottom = 16) {
629
645
}
630
646
}
631
647
632
- export function calcNutArrowPath ( arc , center = false , yOffsetTop = 16 , yOffsetBottom = 16 , toCenter = false , hideStart = false ) {
648
+ export function offsetFromCenterPoint ( {
649
+ initX,
650
+ initY,
651
+ offset,
652
+ centerX,
653
+ centerY
654
+ } ) {
655
+ const angle = Math . atan2 ( initY - centerY , initX - centerX ) ;
656
+ return {
657
+ x : initX + offset * Math . cos ( angle ) ,
658
+ y : initY + offset * Math . sin ( angle )
659
+ }
660
+ }
661
+
662
+ export function findArcMidpoint ( pathElement ) {
663
+ const el = document . createElementNS ( "http://www.w3.org/2000/svg" , 'path' )
664
+ el . setAttribute ( 'd' , pathElement )
665
+
666
+ const length = el . getTotalLength ( ) ;
667
+ let start = 0 ;
668
+ let end = length ;
669
+ let midpointParameter = length / 2 ;
670
+
671
+ const epsilon = 0.01 ;
672
+ while ( end - start > epsilon ) {
673
+ const mid = ( start + end ) / 2 ;
674
+ const midPoint = el . getPointAtLength ( mid ) ;
675
+ const midLength = midPoint . x ;
676
+
677
+ if ( Math . abs ( midLength - midpointParameter ) < epsilon ) {
678
+ midpointParameter = mid ;
679
+ break ;
680
+ } else if ( midLength < midpointParameter ) {
681
+ start = mid ;
682
+ } else {
683
+ end = mid ;
684
+ }
685
+ }
686
+ const { x, y } = el . getPointAtLength ( midpointParameter ) ;
687
+ return { x, y } ;
688
+ }
689
+
690
+ export function calcNutArrowPath ( arc , center = false , yOffsetTop = 16 , yOffsetBottom = 16 , toCenter = false , hideStart = false , arcSize = 0 ) {
691
+ const { x, y } = findArcMidpoint ( arc . path )
692
+
693
+ const { x :endX , y :endY } = offsetFromCenterPoint ( {
694
+ initX : x ,
695
+ initY : y ,
696
+ offset : arcSize ,
697
+ centerX : center ? center . x : 0 ,
698
+ centerY : center ? center . y : 0
699
+ } )
700
+
633
701
const start = `${ calcMarkerOffsetX ( arc ) . x } ,${ calcMarkerOffsetY ( arc , yOffsetTop , yOffsetBottom ) - 4 } ` ;
634
- const end = ` ${ center ? center . x : arc . center . endX } ,${ center ? center . y : arc . center . endY } ` ;
702
+ const end = ` ${ center ? center . x : endX } ,${ center ? center . y : endY } ` ;
635
703
let mid = "" ;
636
- if ( arc . center . endX > arc . cx ) {
704
+ if ( x > arc . cx ) {
637
705
mid = `${ calcMarkerOffsetX ( arc ) . x - 12 } ,${ calcMarkerOffsetY ( arc , yOffsetTop , yOffsetBottom ) - 4 } ` ;
638
- } else if ( arc . center . endX < arc . cx ) {
706
+ } else if ( x < arc . cx ) {
639
707
mid = `${ calcMarkerOffsetX ( arc ) . x + 12 } ,${ calcMarkerOffsetY ( arc , yOffsetTop , yOffsetBottom ) - 4 } ` ;
640
708
} else {
641
709
mid = `${ calcMarkerOffsetX ( arc ) . x + 12 } ,${ calcMarkerOffsetY ( arc , yOffsetTop , yOffsetBottom ) - 4 } ` ;
0 commit comments