Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions examples/gradient-circle.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,26 @@ const Example = () => {
strokeWidth="6"
strokeLinecap="round"
strokeColor={{
'100%': '#87d068',
'0%': '#108ee9',
'100%': '#108ee9',
'0%': '#87d068',
}}
/>
</div>
<h3>Circle With Success Percent {65}%</h3>
<div style={circleContainerStyle}>
<Circle
percent={[65, 100]}
strokeWidth="6"
strokeLinecap="round"
strokeColor={[
'#87d068',
{
'100%': '#108ee9',
'0%': '#87d068',
},
]}
/>
</div>
</div>
);
};
Expand Down
53 changes: 42 additions & 11 deletions src/Circle.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import PropTypes from 'prop-types';
import enhancer from './enhancer';
import { propTypes, defaultProps } from './types';

let gradientSeed = 0;

function stripPercentToNumber(percent) {
return +percent.replace('%', '');
}

function toArray(symArray) {
return Array.isArray(symArray) ? symArray : [symArray];
}

function getPathStyles(offset, percent, strokeColor, strokeWidth, gapDegree = 0, gapPosition) {
const radius = 50 - strokeWidth / 2;
let beginPositionX = 0;
Expand Down Expand Up @@ -51,6 +61,14 @@ function getPathStyles(offset, percent, strokeColor, strokeWidth, gapDegree = 0,
class Circle extends Component {
paths = {};

gradientId = 0;

constructor() {
super();
this.gradientId = gradientSeed;
gradientSeed += 1;
}

getStokeList() {
const {
prefixCls,
Expand All @@ -61,15 +79,16 @@ class Circle extends Component {
gapDegree,
gapPosition,
} = this.props;
const percentList = Array.isArray(percent) ? percent : [percent];
const strokeColorList = Array.isArray(strokeColor) ? strokeColor : [strokeColor];

const stroke =
Object.prototype.toString.call(strokeColor) === '[object Object]' ? 'url(#gradient)' : '';
const percentList = toArray(percent);
const strokeColorList = toArray(strokeColor);

let stackPtg = 0;
return percentList.map((ptg, index) => {
const color = strokeColorList[index] || strokeColorList[strokeColorList.length - 1];
const stroke =
Object.prototype.toString.call(color) === '[object Object]'
? `url(#${prefixCls}-gradient-${this.gradientId})`
: '';
const { pathString, pathStyle } = getPathStyles(
stackPtg,
ptg,
Expand Down Expand Up @@ -122,20 +141,32 @@ class Circle extends Component {
gapPosition,
);
delete restProps.percent;
const isGradient = Object.prototype.toString.call(strokeColor) === '[object Object]';
const strokeColorList = toArray(strokeColor);
const gradient = strokeColorList.find(
color => Object.prototype.toString.call(color) === '[object Object]',
);

return (
<svg
className={`${prefixCls}-circle ${className}`}
viewBox="0 0 100 100"
style={style}
{...restProps}
>
{isGradient && (
{gradient && (
<defs>
<linearGradient id="gradient" x1="100%" y1="0%" x2="0%" y2="0%">
{Object.keys(strokeColor).map((key, index) => (
<stop key={index} offset={key} stopColor={strokeColor[key]} />
))}
<linearGradient
id={`${prefixCls}-gradient-${this.gradientId}`}
x1="100%"
y1="0%"
x2="0%"
y2="0%"
>
{Object.keys(gradient)
.sort((a, b) => stripPercentToNumber(a) - stripPercentToNumber(b))
.map((key, index) => (
<stop key={index} offset={key} stopColor={gradient[key]} />
))}
</linearGradient>
</defs>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const propTypes = {
prefixCls: PropTypes.string,
strokeColor: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])),
PropTypes.object,
]),
strokeLinecap: PropTypes.oneOf(['butt', 'round', 'square']),
Expand Down
51 changes: 37 additions & 14 deletions tests/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { Line, Circle } from '../src';

function getGradientIdFromDef(def) {
return def.firstElementChild.attributes.getNamedItem('id').value;
}

describe('Progress', () => {
let div = null;
beforeEach(() => {
Expand Down Expand Up @@ -79,19 +83,38 @@ describe('Progress', () => {
expect(circle.state.percent).toBe('30');
});

it('circle support gradient color', () => {
const circle = ReactDOM.render(
<Circle
percent={90}
strokeWidth="6"
strokeLinecap="round"
strokeColor={{
'0%': '#108ee9',
'100%': '#87d068',
}}
/>
, div);
expect(circle.props.percent).toBe(90);
})
it('should gradient works and circles have different gradient IDs', () => {
ReactDOM.render(
<>
<Circle
percent={90}
strokeWidth="6"
strokeLinecap="round"
strokeColor={{
'0%': '#108ee9',
'100%': '#87d068',
}}
/>
<Circle
percent={90}
strokeWidth="6"
strokeLinecap="round"
strokeColor={{
'0%': '#108ee9',
'100%': '#87d068',
}}
/>
</>,
div,
);

const gradientDefs = div.querySelectorAll('defs');
const idFirst = getGradientIdFromDef(gradientDefs[0]);
const idSecond = getGradientIdFromDef(gradientDefs[1]);
const idRE = /^rc-progress-gradient-\d{1,}$/;
expect(idFirst).toMatch(idRE);
expect(idSecond).toMatch(idRE);
expect(idFirst === idSecond).toBeFalsy();
});
});
});