11import * as React from 'react' ;
22import classNames from 'classnames' ;
3- import { useTransitionDuration , defaultProps } from './common' ;
3+ import { defaultProps , useTransitionDuration } from './common' ;
44import type { ProgressProps } from './interface' ;
55import useId from './hooks/useId' ;
66
@@ -16,20 +16,19 @@ function toArray<T>(value: T | T[]): T[] {
1616const VIEW_BOX_SIZE = 100 ;
1717
1818const getCircleStyle = (
19- radius : number ,
19+ perimeter : number ,
20+ perimeterWithoutGap : number ,
2021 offset : number ,
2122 percent : number ,
23+ rotateDeg : number ,
24+ gapDegree ,
25+ gapPosition : ProgressProps [ 'gapPosition' ] | undefined ,
2226 strokeColor : string | Record < string , string > ,
23- gapDegree = 0 ,
24- gapPosition : ProgressProps [ 'gapPosition' ] ,
2527 strokeLinecap : ProgressProps [ 'strokeLinecap' ] ,
2628 strokeWidth ,
29+ stepSpace = 0 ,
2730) => {
28- const rotateDeg = gapDegree > 0 ? 90 + gapDegree / 2 : - 90 ;
29- const perimeter = Math . PI * 2 * radius ;
30- const perimeterWithoutGap = perimeter * ( ( 360 - gapDegree ) / 360 ) ;
3131 const offsetDeg = ( offset / 100 ) * 360 * ( ( 360 - gapDegree ) / 360 ) ;
32-
3332 const positionDeg =
3433 gapDegree === 0
3534 ? 0
@@ -45,7 +44,7 @@ const getCircleStyle = (
4544 // https://github.com/ant-design/ant-design/issues/35009
4645 if ( strokeLinecap === 'round' && percent !== 100 ) {
4746 strokeDashoffset += strokeWidth / 2 ;
48- // when percent is small enough (<= 1%), keep smallest value to avoid it's disapperance
47+ // when percent is small enough (<= 1%), keep smallest value to avoid it's disappearance
4948 if ( strokeDashoffset >= perimeterWithoutGap ) {
5049 strokeDashoffset = perimeterWithoutGap - 0.01 ;
5150 }
@@ -54,7 +53,7 @@ const getCircleStyle = (
5453 return {
5554 stroke : typeof strokeColor === 'string' ? strokeColor : undefined ,
5655 strokeDasharray : `${ perimeterWithoutGap } px ${ perimeter } ` ,
57- strokeDashoffset,
56+ strokeDashoffset : strokeDashoffset + stepSpace ,
5857 transform : `rotate(${ rotateDeg + offsetDeg + positionDeg } deg)` ,
5958 transformOrigin : '50% 50%' ,
6059 transition :
@@ -66,9 +65,10 @@ const getCircleStyle = (
6665const Circle : React . FC < ProgressProps > = ( {
6766 id,
6867 prefixCls,
68+ steps,
6969 strokeWidth,
7070 trailWidth,
71- gapDegree,
71+ gapDegree = 0 ,
7272 gapPosition,
7373 trailColor,
7474 strokeLinecap,
@@ -81,14 +81,21 @@ const Circle: React.FC<ProgressProps> = ({
8181 const mergedId = useId ( id ) ;
8282 const gradientId = `${ mergedId } -gradient` ;
8383 const radius = VIEW_BOX_SIZE / 2 - strokeWidth / 2 ;
84+ const perimeter = Math . PI * 2 * radius ;
85+ const rotateDeg = gapDegree > 0 ? 90 + gapDegree / 2 : - 90 ;
86+ const perimeterWithoutGap = perimeter * ( ( 360 - gapDegree ) / 360 ) ;
87+ const { count : stepCount , space : stepSpace } =
88+ typeof steps === 'object' ? steps : { count : steps , space : 2 } ;
8489
8590 const circleStyle = getCircleStyle (
86- radius ,
91+ perimeter ,
92+ perimeterWithoutGap ,
8793 0 ,
8894 100 ,
89- trailColor ,
95+ rotateDeg ,
9096 gapDegree ,
9197 gapPosition ,
98+ trailColor ,
9299 strokeLinecap ,
93100 strokeWidth ,
94101 ) ;
@@ -105,12 +112,14 @@ const Circle: React.FC<ProgressProps> = ({
105112 const color = strokeColorList [ index ] || strokeColorList [ strokeColorList . length - 1 ] ;
106113 const stroke = color && typeof color === 'object' ? `url(#${ gradientId } )` : undefined ;
107114 const circleStyleForStack = getCircleStyle (
108- radius ,
115+ perimeter ,
116+ perimeterWithoutGap ,
109117 stackPtg ,
110118 ptg ,
111- color ,
119+ rotateDeg ,
112120 gapDegree ,
113121 gapPosition ,
122+ color ,
114123 strokeLinecap ,
115124 strokeWidth ,
116125 ) ;
@@ -132,7 +141,7 @@ const Circle: React.FC<ProgressProps> = ({
132141 // React will call the ref callback with the DOM element when the component mounts,
133142 // and call it with `null` when it unmounts.
134143 // Refs are guaranteed to be up-to-date before componentDidMount or componentDidUpdate fires.
135-
144+
136145 paths [ index ] = elem ;
137146 } }
138147 />
@@ -141,6 +150,52 @@ const Circle: React.FC<ProgressProps> = ({
141150 . reverse ( ) ;
142151 } ;
143152
153+ const getStepStokeList = ( ) => {
154+ // only show the first percent when pass steps
155+ const current = Math . round ( stepCount * ( percentList [ 0 ] / 100 ) ) ;
156+ const stepPtg = 100 / stepCount ;
157+
158+ let stackPtg = 0 ;
159+ return new Array ( stepCount ) . fill ( null ) . map ( ( _ , index ) => {
160+ const color = index <= current - 1 ? strokeColorList [ 0 ] : trailColor ;
161+ const stroke = color && typeof color === 'object' ? `url(#${ gradientId } )` : undefined ;
162+ const circleStyleForStack = getCircleStyle (
163+ perimeter ,
164+ perimeterWithoutGap ,
165+ stackPtg ,
166+ stepPtg ,
167+ rotateDeg ,
168+ gapDegree ,
169+ gapPosition ,
170+ color ,
171+ 'butt' ,
172+ strokeWidth ,
173+ stepSpace ,
174+ ) ;
175+ stackPtg +=
176+ ( ( perimeterWithoutGap - circleStyleForStack . strokeDashoffset + stepSpace ) * 100 ) /
177+ perimeterWithoutGap ;
178+
179+ return (
180+ < circle
181+ key = { index }
182+ className = { `${ prefixCls } -circle-path` }
183+ r = { radius }
184+ cx = { VIEW_BOX_SIZE / 2 }
185+ cy = { VIEW_BOX_SIZE / 2 }
186+ stroke = { stroke }
187+ // strokeLinecap={strokeLinecap}
188+ strokeWidth = { strokeWidth }
189+ opacity = { 1 }
190+ style = { circleStyleForStack }
191+ ref = { ( elem ) => {
192+ paths [ index ] = elem ;
193+ } }
194+ />
195+ ) ;
196+ } ) ;
197+ } ;
198+
144199 return (
145200 < svg
146201 className = { classNames ( `${ prefixCls } -circle` , className ) }
@@ -160,17 +215,19 @@ const Circle: React.FC<ProgressProps> = ({
160215 </ linearGradient >
161216 </ defs >
162217 ) }
163- < circle
164- className = { `${ prefixCls } -circle-trail` }
165- r = { radius }
166- cx = { VIEW_BOX_SIZE / 2 }
167- cy = { VIEW_BOX_SIZE / 2 }
168- stroke = { trailColor }
169- strokeLinecap = { strokeLinecap }
170- strokeWidth = { trailWidth || strokeWidth }
171- style = { circleStyle }
172- />
173- { getStokeList ( ) }
218+ { ! stepCount && (
219+ < circle
220+ className = { `${ prefixCls } -circle-trail` }
221+ r = { radius }
222+ cx = { VIEW_BOX_SIZE / 2 }
223+ cy = { VIEW_BOX_SIZE / 2 }
224+ stroke = { trailColor }
225+ strokeLinecap = { strokeLinecap }
226+ strokeWidth = { trailWidth || strokeWidth }
227+ style = { circleStyle }
228+ />
229+ ) }
230+ { stepCount ? getStepStokeList ( ) : getStokeList ( ) }
174231 </ svg >
175232 ) ;
176233} ;
0 commit comments