ant-design-vue/components/vc-progress/src/Circle.js

203 lines
5.2 KiB
JavaScript

import Vue from 'vue';
import ref from 'vue-ref';
import PropTypes from '../../_util/vue-types';
import { initDefaultProps } from '../../_util/props-util';
import enhancer from './enhancer';
import { propTypes, defaultProps } from './types';
const circlePropTypes = {
...propTypes,
gapPosition: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
gapDegree: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.bool]),
};
const circleDefaultProps = {
...defaultProps,
gapPosition: 'top',
};
Vue.use(ref, { name: 'ant-ref' });
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;
let beginPositionY = -radius;
let endPositionX = 0;
let endPositionY = -2 * radius;
switch (gapPosition) {
case 'left':
beginPositionX = -radius;
beginPositionY = 0;
endPositionX = 2 * radius;
endPositionY = 0;
break;
case 'right':
beginPositionX = radius;
beginPositionY = 0;
endPositionX = -2 * radius;
endPositionY = 0;
break;
case 'bottom':
beginPositionY = radius;
endPositionY = 2 * radius;
break;
default:
}
const pathString = `M 50,50 m ${beginPositionX},${beginPositionY}
a ${radius},${radius} 0 1 1 ${endPositionX},${-endPositionY}
a ${radius},${radius} 0 1 1 ${-endPositionX},${endPositionY}`;
const len = Math.PI * 2 * radius;
const pathStyle = {
stroke: strokeColor,
strokeDasharray: `${(percent / 100) * (len - gapDegree)}px ${len}px`,
strokeDashoffset: `-${gapDegree / 2 + (offset / 100) * (len - gapDegree)}px`,
transition:
'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s', // eslint-disable-line
};
return {
pathString,
pathStyle,
};
}
const Circle = {
props: initDefaultProps(circlePropTypes, circleDefaultProps),
created() {
this.paths = {};
this.gradientId = gradientSeed;
gradientSeed += 1;
},
methods: {
getStokeList() {
const {
prefixCls,
percent,
strokeColor,
strokeWidth,
strokeLinecap,
gapDegree,
gapPosition,
} = this.$props;
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,
color,
strokeWidth,
gapDegree,
gapPosition,
);
stackPtg += ptg;
const pathProps = {
key: index,
attrs: {
d: pathString,
stroke,
'stroke-linecap': strokeLinecap,
'stroke-width': ptg === 0 ? 0 : strokeWidth,
'fill-opacity': '0',
},
class: `${prefixCls}-circle-path`,
style: pathStyle,
directives: [
{
name: 'ant-ref',
value: c => {
this.paths[index] = c;
},
},
],
};
return <path {...pathProps} />;
});
},
},
render() {
const {
prefixCls,
strokeWidth,
trailWidth,
gapDegree,
gapPosition,
trailColor,
strokeLinecap,
strokeColor,
...restProps
} = this.$props;
const { pathString, pathStyle } = getPathStyles(
0,
100,
trailColor,
strokeWidth,
gapDegree,
gapPosition,
);
delete restProps.percent;
const strokeColorList = toArray(strokeColor);
const gradient = strokeColorList.find(
color => Object.prototype.toString.call(color) === '[object Object]',
);
const pathFirst = {
attrs: {
d: pathString,
stroke: trailColor,
'stroke-linecap': strokeLinecap,
'stroke-width': trailWidth || strokeWidth,
'fill-opacity': '0',
},
class: `${prefixCls}-circle-trail`,
style: pathStyle,
};
return (
<svg class={`${prefixCls}-circle`} viewBox="0 0 100 100" {...restProps}>
{gradient && (
<defs>
<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} stop-color={gradient[key]} />
))}
</linearGradient>
</defs>
)}
<path {...pathFirst} />
{this.getStokeList().reverse()}
</svg>
);
},
};
export default enhancer(Circle);