Skip to content

Commit e697b47

Browse files
WendellzombieJ
authored andcommitted
πŸ› fix gradient for circle progress does not have unique id (#76)
* πŸ› fix gradient for circle progress does not have unique id * πŸ’¬ beautify code * sort gradient color and support stroke color array with gradient * fix doc * fix code style * add prefix * more strict prop type * test: add test of gradient * fix test
1 parent acdae83 commit e697b47

File tree

4 files changed

+97
-28
lines changed

4 files changed

+97
-28
lines changed

β€Žexamples/gradient-circle.jsβ€Ž

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,26 @@ const Example = () => {
3030
strokeWidth="6"
3131
strokeLinecap="round"
3232
strokeColor={{
33-
'100%': '#87d068',
34-
'0%': '#108ee9',
33+
'100%': '#108ee9',
34+
'0%': '#87d068',
3535
}}
3636
/>
3737
</div>
38+
<h3>Circle With Success Percent {65}%</h3>
39+
<div style={circleContainerStyle}>
40+
<Circle
41+
percent={[65, 100]}
42+
strokeWidth="6"
43+
strokeLinecap="round"
44+
strokeColor={[
45+
'#87d068',
46+
{
47+
'100%': '#108ee9',
48+
'0%': '#87d068',
49+
},
50+
]}
51+
/>
52+
</div>
3853
</div>
3954
);
4055
};

β€Žsrc/Circle.jsβ€Ž

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ import PropTypes from 'prop-types';
44
import enhancer from './enhancer';
55
import { propTypes, defaultProps } from './types';
66

7+
let gradientSeed = 0;
8+
9+
function stripPercentToNumber(percent) {
10+
return +percent.replace('%', '');
11+
}
12+
13+
function toArray(symArray) {
14+
return Array.isArray(symArray) ? symArray : [symArray];
15+
}
16+
717
function getPathStyles(offset, percent, strokeColor, strokeWidth, gapDegree = 0, gapPosition) {
818
const radius = 50 - strokeWidth / 2;
919
let beginPositionX = 0;
@@ -51,6 +61,14 @@ function getPathStyles(offset, percent, strokeColor, strokeWidth, gapDegree = 0,
5161
class Circle extends Component {
5262
paths = {};
5363

64+
gradientId = 0;
65+
66+
constructor() {
67+
super();
68+
this.gradientId = gradientSeed;
69+
gradientSeed += 1;
70+
}
71+
5472
getStokeList() {
5573
const {
5674
prefixCls,
@@ -61,15 +79,16 @@ class Circle extends Component {
6179
gapDegree,
6280
gapPosition,
6381
} = this.props;
64-
const percentList = Array.isArray(percent) ? percent : [percent];
65-
const strokeColorList = Array.isArray(strokeColor) ? strokeColor : [strokeColor];
66-
67-
const stroke =
68-
Object.prototype.toString.call(strokeColor) === '[object Object]' ? 'url(#gradient)' : '';
82+
const percentList = toArray(percent);
83+
const strokeColorList = toArray(strokeColor);
6984

7085
let stackPtg = 0;
7186
return percentList.map((ptg, index) => {
7287
const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1];
88+
const stroke =
89+
Object.prototype.toString.call(color) === '[object Object]'
90+
? `url(#${prefixCls}-gradient-${this.gradientId})`
91+
: '';
7392
const { pathString, pathStyle } = getPathStyles(
7493
stackPtg,
7594
ptg,
@@ -122,20 +141,32 @@ class Circle extends Component {
122141
gapPosition,
123142
);
124143
delete restProps.percent;
125-
const isGradient = Object.prototype.toString.call(strokeColor) === '[object Object]';
144+
const strokeColorList = toArray(strokeColor);
145+
const gradient = strokeColorList.find(
146+
color => Object.prototype.toString.call(color) === '[object Object]',
147+
);
148+
126149
return (
127150
<svg
128151
className={`${prefixCls}-circle ${className}`}
129152
viewBox="0 0 100 100"
130153
style={style}
131154
{...restProps}
132155
>
133-
{isGradient && (
156+
{gradient && (
134157
<defs>
135-
<linearGradient id="gradient" x1="100%" y1="0%" x2="0%" y2="0%">
136-
{Object.keys(strokeColor).map((key, index) => (
137-
<stop key={index} offset={key} stopColor={strokeColor[key]} />
138-
))}
158+
<linearGradient
159+
id={`${prefixCls}-gradient-${this.gradientId}`}
160+
x1="100%"
161+
y1="0%"
162+
x2="0%"
163+
y2="0%"
164+
>
165+
{Object.keys(gradient)
166+
.sort((a, b) => stripPercentToNumber(a) - stripPercentToNumber(b))
167+
.map((key, index) => (
168+
<stop key={index} offset={key} stopColor={gradient[key]} />
169+
))}
139170
</linearGradient>
140171
</defs>
141172
)}

β€Žsrc/types.jsβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const propTypes = {
2020
prefixCls: PropTypes.string,
2121
strokeColor: PropTypes.oneOfType([
2222
PropTypes.string,
23-
PropTypes.arrayOf(PropTypes.string),
23+
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])),
2424
PropTypes.object,
2525
]),
2626
strokeLinecap: PropTypes.oneOf(['butt', 'round', 'square']),

β€Žtests/index.spec.jsβ€Ž

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import React from 'react';
33
import ReactDOM from 'react-dom';
44
import { Line, Circle } from '../src';
55

6+
function getGradientIdFromDef(def) {
7+
return def.firstElementChild.attributes.getNamedItem('id').value;
8+
}
9+
610
describe('Progress', () => {
711
let div = null;
812
beforeEach(() => {
@@ -79,19 +83,38 @@ describe('Progress', () => {
7983
expect(circle.state.percent).toBe('30');
8084
});
8185

82-
it('circle support gradient color', () => {
83-
const circle = ReactDOM.render(
84-
<Circle
85-
percent={90}
86-
strokeWidth="6"
87-
strokeLinecap="round"
88-
strokeColor={{
89-
'0%': '#108ee9',
90-
'100%': '#87d068',
91-
}}
92-
/>
93-
, div);
94-
expect(circle.props.percent).toBe(90);
95-
})
86+
it('should gradient works and circles have different gradient IDs', () => {
87+
ReactDOM.render(
88+
<>
89+
<Circle
90+
percent={90}
91+
strokeWidth="6"
92+
strokeLinecap="round"
93+
strokeColor={{
94+
'0%': '#108ee9',
95+
'100%': '#87d068',
96+
}}
97+
/>
98+
<Circle
99+
percent={90}
100+
strokeWidth="6"
101+
strokeLinecap="round"
102+
strokeColor={{
103+
'0%': '#108ee9',
104+
'100%': '#87d068',
105+
}}
106+
/>
107+
</>,
108+
div,
109+
);
110+
111+
const gradientDefs = div.querySelectorAll('defs');
112+
const idFirst = getGradientIdFromDef(gradientDefs[0]);
113+
const idSecond = getGradientIdFromDef(gradientDefs[1]);
114+
const idRE = /^rc-progress-gradient-\d{1,}$/;
115+
expect(idFirst).toMatch(idRE);
116+
expect(idSecond).toMatch(idRE);
117+
expect(idFirst === idSecond).toBeFalsy();
118+
});
96119
});
97120
});

0 commit comments

Comments
Β (0)