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 | ||
|  | 
 |