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 ) {
22 let { series } = item ;
33 if ( ! series || item . base === 0 )
44 return {
@@ -19,17 +19,31 @@ export function makeDonut(item, cx, cy, rx, ry) {
1919 let acc = 0 ;
2020 for ( let i = 0 ; i < series . length ; i += 1 ) {
2121 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
2323 // midProportion & midRatio are used to find the midpoint of the arc to display markers
2424 const midProportion = series [ i ] . value / 2 / sum ;
25- const midRatio = midProportion * ( Math . PI * 2 ) ;
25+ const midRatio = midProportion * ( Math . PI * piMult ) ;
2626 const { startX, startY, endX, endY, path } = createArc (
2727 [ cx , cy ] ,
2828 [ rx , ry ] ,
2929 [ acc , ratio ] ,
30- 110
30+ rotation ,
31+ degrees ,
32+ piMult
3133 ) ;
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+
3245 ratios . push ( {
46+ arcSlice : `${ path } L ${ inner . startX } ${ inner . startY } ${ inner . path } L ${ startX } ${ startY } ` ,
3347 cx,
3448 cy,
3549 ...series [ i ] ,
@@ -42,9 +56,11 @@ export function makeDonut(item, cx, cy, rx, ry) {
4256 endY,
4357 center : createArc (
4458 [ cx , cy ] ,
45- [ rx * 1.45 , ry * 1.45 ] ,
59+ [ rx * arcAmpl , ry * arcAmpl ] ,
4660 [ acc , midRatio ] ,
47- 110
61+ rotation ,
62+ degrees ,
63+ piMult
4864 ) , // center of the arc, to display the marker. rx & ry are larger to be displayed with a slight offset
4965 } ) ;
5066 acc += ratio ;
@@ -67,8 +83,8 @@ export function rotateMatrix(x) {
6783 ] ;
6884}
6985
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 ) ;
7288 const rotMatrix = rotateMatrix ( phi ) ;
7389 const [ sX , sY ] = addVector (
7490 matrixTimes ( rotMatrix , [
@@ -85,20 +101,20 @@ export function createArc([cx, cy], [rx, ry], [position, ratio], phi) {
85101 [ cx , cy ]
86102 ) ;
87103 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 ;
89105 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 ${ [
95111 rx ,
96112 ry ,
97- ( phi / ( 2 * Math . PI ) ) * 360 ,
113+ ( phi / ( piMult * Math . PI ) ) * degrees ,
98114 fA ,
99115 fS ,
100- eX ,
101- eY ,
116+ reverse ? sX : eX ,
117+ reverse ? sY : eY ,
102118 ] . join ( " " ) } `,
103119 } ;
104120}
@@ -629,13 +645,65 @@ export function calcMarkerOffsetY(arc, yOffsetTop = 16, yOffsetBottom = 16) {
629645 }
630646}
631647
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+
633701 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 } ` ;
635703 let mid = "" ;
636- if ( arc . center . endX > arc . cx ) {
704+ if ( x > arc . cx ) {
637705 mid = `${ calcMarkerOffsetX ( arc ) . x - 12 } ,${ calcMarkerOffsetY ( arc , yOffsetTop , yOffsetBottom ) - 4 } ` ;
638- } else if ( arc . center . endX < arc . cx ) {
706+ } else if ( x < arc . cx ) {
639707 mid = `${ calcMarkerOffsetX ( arc ) . x + 12 } ,${ calcMarkerOffsetY ( arc , yOffsetTop , yOffsetBottom ) - 4 } ` ;
640708 } else {
641709 mid = `${ calcMarkerOffsetX ( arc ) . x + 12 } ,${ calcMarkerOffsetY ( arc , yOffsetTop , yOffsetBottom ) - 4 } ` ;
0 commit comments