初始化 antd-pro
This commit is contained in:
10
admin-web/src/components/Charts/WaterWave/index.d.ts
vendored
Normal file
10
admin-web/src/components/Charts/WaterWave/index.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
export interface IWaterWaveProps {
|
||||
title: React.ReactNode;
|
||||
color?: string;
|
||||
height: number;
|
||||
percent: number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export default class WaterWave extends React.Component<IWaterWaveProps, any> {}
|
||||
213
admin-web/src/components/Charts/WaterWave/index.js
Normal file
213
admin-web/src/components/Charts/WaterWave/index.js
Normal file
@@ -0,0 +1,213 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import autoHeight from '../autoHeight';
|
||||
import styles from './index.less';
|
||||
|
||||
/* eslint no-return-assign: 0 */
|
||||
/* eslint no-mixed-operators: 0 */
|
||||
// riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90
|
||||
|
||||
@autoHeight()
|
||||
class WaterWave extends PureComponent {
|
||||
state = {
|
||||
radio: 1,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.renderChart();
|
||||
this.resize();
|
||||
window.addEventListener(
|
||||
'resize',
|
||||
() => {
|
||||
requestAnimationFrame(() => this.resize());
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
}
|
||||
|
||||
componentDidUpdate(props) {
|
||||
const { percent } = this.props;
|
||||
if (props.percent !== percent) {
|
||||
// 不加这个会造成绘制缓慢
|
||||
this.renderChart('update');
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
cancelAnimationFrame(this.timer);
|
||||
if (this.node) {
|
||||
this.node.innerHTML = '';
|
||||
}
|
||||
window.removeEventListener('resize', this.resize);
|
||||
}
|
||||
|
||||
resize = () => {
|
||||
if (this.root) {
|
||||
const { height } = this.props;
|
||||
const { offsetWidth } = this.root.parentNode;
|
||||
this.setState({
|
||||
radio: offsetWidth < height ? offsetWidth / height : 1,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
renderChart(type) {
|
||||
const { percent, color = '#1890FF' } = this.props;
|
||||
const data = percent / 100;
|
||||
const self = this;
|
||||
cancelAnimationFrame(this.timer);
|
||||
|
||||
if (!this.node || (data !== 0 && !data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const canvas = this.node;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const canvasWidth = canvas.width;
|
||||
const canvasHeight = canvas.height;
|
||||
const radius = canvasWidth / 2;
|
||||
const lineWidth = 2;
|
||||
const cR = radius - lineWidth;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = lineWidth * 2;
|
||||
|
||||
const axisLength = canvasWidth - lineWidth;
|
||||
const unit = axisLength / 8;
|
||||
const range = 0.2; // 振幅
|
||||
let currRange = range;
|
||||
const xOffset = lineWidth;
|
||||
let sp = 0; // 周期偏移量
|
||||
let currData = 0;
|
||||
const waveupsp = 0.005; // 水波上涨速度
|
||||
|
||||
let arcStack = [];
|
||||
const bR = radius - lineWidth;
|
||||
const circleOffset = -(Math.PI / 2);
|
||||
let circleLock = true;
|
||||
|
||||
for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) {
|
||||
arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]);
|
||||
}
|
||||
|
||||
const cStartPoint = arcStack.shift();
|
||||
ctx.strokeStyle = color;
|
||||
ctx.moveTo(cStartPoint[0], cStartPoint[1]);
|
||||
|
||||
function drawSin() {
|
||||
ctx.beginPath();
|
||||
ctx.save();
|
||||
|
||||
const sinStack = [];
|
||||
for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) {
|
||||
const x = sp + (xOffset + i) / unit;
|
||||
const y = Math.sin(x) * currRange;
|
||||
const dx = i;
|
||||
const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y;
|
||||
|
||||
ctx.lineTo(dx, dy);
|
||||
sinStack.push([dx, dy]);
|
||||
}
|
||||
|
||||
const startPoint = sinStack.shift();
|
||||
|
||||
ctx.lineTo(xOffset + axisLength, canvasHeight);
|
||||
ctx.lineTo(xOffset, canvasHeight);
|
||||
ctx.lineTo(startPoint[0], startPoint[1]);
|
||||
|
||||
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight);
|
||||
gradient.addColorStop(0, '#ffffff');
|
||||
gradient.addColorStop(1, color);
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function render() {
|
||||
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
if (circleLock && type !== 'update') {
|
||||
if (arcStack.length) {
|
||||
const temp = arcStack.shift();
|
||||
ctx.lineTo(temp[0], temp[1]);
|
||||
ctx.stroke();
|
||||
} else {
|
||||
circleLock = false;
|
||||
ctx.lineTo(cStartPoint[0], cStartPoint[1]);
|
||||
ctx.stroke();
|
||||
arcStack = null;
|
||||
|
||||
ctx.globalCompositeOperation = 'destination-over';
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = lineWidth;
|
||||
ctx.arc(radius, radius, bR, 0, 2 * Math.PI, 1);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.save();
|
||||
ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, 1);
|
||||
|
||||
ctx.restore();
|
||||
ctx.clip();
|
||||
ctx.fillStyle = color;
|
||||
}
|
||||
} else {
|
||||
if (data >= 0.85) {
|
||||
if (currRange > range / 4) {
|
||||
const t = range * 0.01;
|
||||
currRange -= t;
|
||||
}
|
||||
} else if (data <= 0.1) {
|
||||
if (currRange < range * 1.5) {
|
||||
const t = range * 0.01;
|
||||
currRange += t;
|
||||
}
|
||||
} else {
|
||||
if (currRange <= range) {
|
||||
const t = range * 0.01;
|
||||
currRange += t;
|
||||
}
|
||||
if (currRange >= range) {
|
||||
const t = range * 0.01;
|
||||
currRange -= t;
|
||||
}
|
||||
}
|
||||
if (data - currData > 0) {
|
||||
currData += waveupsp;
|
||||
}
|
||||
if (data - currData < 0) {
|
||||
currData -= waveupsp;
|
||||
}
|
||||
|
||||
sp += 0.07;
|
||||
drawSin();
|
||||
}
|
||||
self.timer = requestAnimationFrame(render);
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { radio } = this.state;
|
||||
const { percent, title, height } = this.props;
|
||||
return (
|
||||
<div
|
||||
className={styles.waterWave}
|
||||
ref={n => (this.root = n)}
|
||||
style={{ transform: `scale(${radio})` }}
|
||||
>
|
||||
<div style={{ width: height, height, overflow: 'hidden' }}>
|
||||
<canvas
|
||||
className={styles.waterWaveCanvasWrapper}
|
||||
ref={n => (this.node = n)}
|
||||
width={height * 2}
|
||||
height={height * 2}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.text} style={{ width: height }}>
|
||||
{title && <span>{title}</span>}
|
||||
<h4>{percent}%</h4>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WaterWave;
|
||||
28
admin-web/src/components/Charts/WaterWave/index.less
Normal file
28
admin-web/src/components/Charts/WaterWave/index.less
Normal file
@@ -0,0 +1,28 @@
|
||||
@import '~antd/lib/style/themes/default.less';
|
||||
|
||||
.waterWave {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
transform-origin: left;
|
||||
.text {
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
span {
|
||||
color: @text-color-secondary;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
h4 {
|
||||
color: @heading-color;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.waterWaveCanvasWrapper {
|
||||
transform: scale(0.5);
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user