效果图,如下图所示进度分别为25%,50%,75%, 100%渲染图形
css代码
.CircelProcess{
position: relative;
width: 100%;
height: 100%;
}
.CircelProcess *{
box-sizing: border-box;
}
.CircelProcess svg{
transform: rotate(-90deg);
}
.ProcessCircle{
transition: stroke-dashoffset 500ms cubic-bezier(0.99, 0.01, 0.62, 0.94);
}
js代码
import React from 'react'
import PropTypes from 'prop-types'
import './style.css'
class CircelProcess extends React.Component {
static propTypes = {
ratio: PropTypes.number,
strokeColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
percent: PropTypes.number.isRequired
}
static defaultProps = {
strokeColor: '#F9C97B',
ratio: 0.1
}
constructor(props) {
super(props)
let {ratio} = props
let r = 50 /(1 + ratio)
let circumference = Math.PI * 2 * r
this.state = {
strokeDashoffset: circumference
}
}
componentWillUnmount() {
this.mounted = false
}
componentDidMount() {
this.mounted = true
let { percent, ratio } = this.props
let r = 50 /(1 + ratio)
let circumference = Math.PI * 2 * r
let strokeDashoffset = circumference - circumference * percent / 100.0
setTimeout(() => {
if (this.mounted) {
this.setState({
strokeDashoffset
})
}
}, 300)
}
render() {
let { ratio} = this.props
let { strokeDashoffset } = this.state
let r = 50 /(1 + ratio)
let strokeDasharray = Math.PI * 2 * r
let strokeWidth = r * ratio
return (
<div className='CircelProcess'>
<svg width='100%' height='100%'
viewBox='0 0 100 100'>
<circle
className='BackgroundCircle'
cx={50}
cy={50}
r={r}
strokeWidth={strokeWidth}
stroke='#D3D3D3'
strokeOpacity={0.2}
fill='none' />
<circle
className='ProcessCircle'
cx={50}
cy={50}
r={r}
strokeWidth={strokeWidth}
stroke='url(#strokecolor)'
// strokeLinejoin='round'
strokeLinecap='round'
strokeDasharray={strokeDasharray}
strokeDashoffset={strokeDashoffset}
fill='none' />
<defs>
<linearGradient id='strokecolor' x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor={'#00B3BC'} />
<stop offset="100%" stopColor={'#89D87A'} />
</linearGradient>
</defs>
</svg>
</div>
)
}
}
export default CircelProcess
实现思路:
1. 外层div作为组件容器,class设置宽、高为100%以自适应组件外层容器宽高,实现根据外容器宽、高变化自动变化;
<div className='CircelProcess'></div>
2.svg 通过两个circle实现进度环,一个circle作为背景,另外一个绘制进度条;
<svg width='100%' height='100%' viewBox='0 0 100 100'></svg>
定义viewBox指定画布大小,方便后续计算,width='100', height='100%',自动填充占满父容器,以宽高较小者作为圆环的外直径;
3. svg中定义底1个circle 作为进度环背景,cx、cy 设置为50,代表circle圆心在画布中点,直径 r = 50 /(1 + ratio), ratio为圆环stroke宽度和圆直径大小比例,作为组件属性由使用组件方传递,上边完整代码中默认值为0.1 ,从圆心到圆外侧边长度为circle直径 + 绘制宽度,所以 r = 50 /(1 + ratio),所以圆环环形宽度为 strokeWidth = r * ratio, stroke属性设置背景色,strokeOpacity设置 stroke 边透明度, fill='none'表明绘制的圆形不需要填充内容;
<circle
className='BackgroundCircle'
cx={50}
cy={50}
r={r}
strokeWidth={strokeWidth}
stroke='#D3D3D3'
strokeOpacity={0.2}
fill='none' />
4. 绘制进度条:定义第2个circle 用来绘制进度。
圆心,直径、绘制宽度同第1个圆环,绘制颜色(stroke)引用 defs中定义的线性渐变元素实现绘制颜色渐变;
strokeDasharray定义绘制线段的虚线段数组,长度为圆的直径,strokeDashoffset设置绘制线段偏移量,通过修改其值来绘制进度条。strokeDashoffset初始值为圆周长,线段偏移长度和园周长大小一致,所以一开始圆环线段偏移之后显示为虚线部分,所以环2在默认情况下通过设置偏移长度在界面上是看不到的,然后通过percent来计算strokeDashoffset值,再修改其值,本例实现是为了进度条动态展示,设置在300ms之后修改strokeDashoffset值。
<circle
className='ProcessCircle'
cx={50}
cy={50}
r={r}
strokeWidth={strokeWidth}
stroke='url(#strokecolor)'
// strokeLinejoin='round'
strokeLinecap='round'
strokeDasharray={strokeDasharray}
strokeDashoffset={strokeDashoffset}
fill='none' />
<defs>
<linearGradient id='strokecolor' x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor={'#00B3BC'} />
<stop offset="100%" stopColor={'#89D87A'} />
</linearGradient>
</defs>