163 lines
4.5 KiB
JavaScript
163 lines
4.5 KiB
JavaScript
|
import React, { useRef, useEffect, useState, useMemo } from 'react'
|
||
|
|
||
|
const imgHeight = 951; //图片原始高度
|
||
|
const imgWidth = 184; //图片原始高度
|
||
|
const circleBorder = 2; //圆环的宽度
|
||
|
const baseSize = 170;//满状态宽度
|
||
|
const itemHeight = 370; //单个高度(包含空白)
|
||
|
const waveHeight = 29; //波浪高度
|
||
|
const colors = ["#8ee34d", "#f6c971", "#ea335d"]; //圆边框颜色
|
||
|
const colorIndexTrans = [2, 1, 0]; //调换第一个和最后一个位置
|
||
|
|
||
|
function CircleProcess(props) {
|
||
|
const sizeRef = useRef();
|
||
|
const outerRef = useRef();
|
||
|
const innerRef = useRef();
|
||
|
const [scale, setScale] = useState(1)
|
||
|
const [innerWidth, setInnerWidth] = useState(0)
|
||
|
|
||
|
//接受外部参数
|
||
|
let { percent:realPercent = 0.5, percentRule = [0, 0.8, 0.95], size = 0.9 } = props;
|
||
|
|
||
|
const percent = useMemo(() => {
|
||
|
return realPercent > 1 ? 1 : realPercent
|
||
|
}, [realPercent])
|
||
|
|
||
|
//颜色的下标
|
||
|
const colorIndex = useMemo(() => {
|
||
|
let res = 0;
|
||
|
percentRule.forEach((val, index) => {
|
||
|
if (percent > val) res = index;
|
||
|
})
|
||
|
return colorIndexTrans[res];
|
||
|
}, [percentRule, percent])
|
||
|
|
||
|
//颜色的位置
|
||
|
const positionY = useMemo(() => {
|
||
|
return -(-innerWidth + percent * innerWidth + waveHeight * scale + colorIndex * scale * itemHeight)
|
||
|
}, [innerWidth, percent, scale, colorIndex])
|
||
|
|
||
|
//计算组件宽度以及比例
|
||
|
const tableSetting = () => {
|
||
|
//组件实际宽度
|
||
|
let comWidth = sizeRef.current.clientWidth;
|
||
|
outerRef.current.style.height = comWidth * size + 'px';
|
||
|
outerRef.current.style.width = comWidth * size + 'px';
|
||
|
//波浪实际宽度
|
||
|
let innerWidth = innerRef.current.clientWidth;
|
||
|
setInnerWidth(innerWidth);
|
||
|
//计算比例
|
||
|
setScale(innerWidth / baseSize);
|
||
|
}
|
||
|
|
||
|
useEffect(() => {
|
||
|
//监听父级宽度变化
|
||
|
let innerWindow = sizeRef.current.contentDocument.defaultView;
|
||
|
innerWindow.addEventListener("resize", tableSetting);
|
||
|
tableSetting();
|
||
|
return () => {
|
||
|
innerWindow.removeEventListener("resize", tableSetting);
|
||
|
}
|
||
|
}, [])
|
||
|
|
||
|
return (
|
||
|
<div className='circle-process'>
|
||
|
<object
|
||
|
ref={sizeRef}
|
||
|
tabIndex="-1"
|
||
|
type="text/html"
|
||
|
aria-hidden="true"
|
||
|
data="about:blank"
|
||
|
style={{
|
||
|
display: "block",
|
||
|
position: "absolute",
|
||
|
top: 0,
|
||
|
left: 0,
|
||
|
width: "100%",
|
||
|
height: "100%",
|
||
|
border: "none",
|
||
|
padding: 0,
|
||
|
margin: 0,
|
||
|
opacity: 0,
|
||
|
zIndex: -1000,
|
||
|
pointerEvents: "none",
|
||
|
}} />
|
||
|
<div className='out-circle' ref={outerRef}>
|
||
|
<div className='in-circle' ref={innerRef}>
|
||
|
<div className='pic-one'></div>
|
||
|
<div className='pic-two'></div>
|
||
|
<div className='text'>{realPercent * 100 + "%"}</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<style jsx>{`
|
||
|
.circle-process{
|
||
|
position:relative;
|
||
|
height:100%;
|
||
|
}
|
||
|
.out-circle {
|
||
|
margin: auto;
|
||
|
overflow: hidden;
|
||
|
border-radius: 50%;
|
||
|
position: absolute;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
right: 0;
|
||
|
bottom: 0;
|
||
|
border: ${circleBorder}px solid;
|
||
|
border-color: ${colors[colorIndex]};
|
||
|
padding: 2px;
|
||
|
}
|
||
|
.in-circle {
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
border-radius: 50%;
|
||
|
position: relative;
|
||
|
overflow: hidden;
|
||
|
}
|
||
|
|
||
|
.in-circle .pic-one, .in-circle .pic-two {
|
||
|
background-image: url('/img/hpPercent.png');
|
||
|
background-repeat: repeat-x;
|
||
|
background-size: ${scale * imgWidth}px ${scale * imgHeight}px;
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
position: absolute;
|
||
|
background-position-y: ${positionY}px;
|
||
|
}
|
||
|
|
||
|
.in-circle .pic-one {
|
||
|
animation: 5s one linear infinite normal;
|
||
|
}
|
||
|
|
||
|
.in-circle .pic-two {
|
||
|
opacity: 0.3;
|
||
|
animation: 10s one linear infinite normal;
|
||
|
}
|
||
|
|
||
|
.in-circle .text {
|
||
|
position: absolute;
|
||
|
color: #fff;
|
||
|
text-align: center;
|
||
|
width: 100%;
|
||
|
margin-top: 12px;
|
||
|
font-size: ${scale*30}px;
|
||
|
}
|
||
|
|
||
|
@keyframes one {
|
||
|
from {
|
||
|
background-position-x: 0;
|
||
|
}
|
||
|
to {
|
||
|
background-position-x: -${imgWidth * scale}px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
`}
|
||
|
</style>
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
export default CircleProcess
|
||
|
|