前言:
伙计儿,来点干货吧!效果看上去还想这么回事,嘻嘻~ canvas也就这么几步,没事自己多研究研究,废话不多说,上代码咯!
body {
display: flex;
flex-flow: column wrap;
justify-content: center;
align-items: center;
}
#c {
margin-top: 20px;
}
input[type=range]::before {content: attr(min); color: #000; padding-right: 5px;}
input[type=range]::after { content: attr(max); color: #000; padding-left: 5px;}
canvas = document.getElementById("c");
ctx = canvas.getContext("2d");
oRange = document.getElementsByName("range")[0];
M = Math;
Sin = M.sin;
Cos = M.cos;
Sqrt = M.sqrt;
Pow = M.pow;
PI = M.PI;
Round = M.round;
oW = canvas.width = 200;
oH = canvas.height = 200;
// 线宽
lineWidth = 2;
// 大半径
r = (oW / 2);
cR = r - 10*lineWidth;
ctx.beginPath();
ctx.lineWidth = lineWidth;
// 水波动画初始参数
axisLength = 2*r - 16*lineWidth; // Sin 图形长度
unit = axisLength / 9; // 波浪宽
range = .4 // 浪幅
nowrange = range;
xoffset = 8*lineWidth; // x 轴偏移量
data = ~~(oRange.value) / 100; // 数据量
sp = 0; // 周期偏移量
nowdata = 0;
waveupsp = 0.006; // 水波上涨速度
// 圆动画初始参数
arcStack = []; // 圆栈
bR = r-8*lineWidth;
soffset = -(PI/2); // 圆动画起始位置
circleLock = true; // 起始动画锁
// 获取圆动画轨迹点集
for(var i = soffset; i< soffset + 2*PI; i+=1/(8*PI)) {
arcStack.push([
r + bR * Cos(i),
r + bR * Sin(i)
])
}
// 圆起始点
cStartPoint = arcStack.shift();
ctx.strokeStyle = "#1c86d1";
ctx.moveTo(cStartPoint[0],cStartPoint[1]);
// 开始渲染
render();
function drawSine () {
ctx.beginPath();
ctx.save();
var Stack = []; // 记录起始点和终点坐标
for (var i = xoffset; i<=xoffset + axisLength; i+=20/axisLength) {
var x = sp + (xoffset + i) / unit;
var y = Sin(x) * nowrange;
var dx = i;
var dy = 2*cR*(1-nowdata) + (r - cR) - (unit * y);
ctx.lineTo(dx, dy);
Stack.push([dx,dy])
}
// 获取初始点和结束点
var startP = Stack[0]
var endP = Stack[Stack.length - 1]
ctx.lineTo(xoffset + axisLength,oW);
ctx.lineTo(xoffset,oW);
ctx.lineTo(startP[0], startP[1])
ctx.fillStyle = "#fbec99";
ctx.fill();
ctx.restore();
}
function drawText () {
ctx.globalCompositeOperation = 'source-over';
var size = 0.2*cR;
ctx.font = 'bold ' + size + 'px Microsoft Yahei';
txt = (nowdata.toFixed(2)*100).toFixed(0) + '%';
var fonty = r + size/2;
var fontx = r - size * 0.8;
ctx.fillStyle = "#f6b71e";
ctx.textAlign = 'center';
ctx.fillText(txt, r+5, r+5)
}
//最外面淡黄色圈
function drawCircle(){
ctx.beginPath();
ctx.lineWidth = 15;
ctx.strokeStyle = '#fff89d';
ctx.arc(r, r, cR+7, 0, 2 * Math.PI);
ctx.stroke();
ctx.restore();
}
//灰色圆圈
function grayCircle(){
ctx.beginPath();
ctx.lineWidth = 6;
ctx.strokeStyle = '#FBEC99';
ctx.arc(r, r, cR-5, 0, 2 * Math.PI);
ctx.stroke();
ctx.restore();
ctx.beginPath();
}
//橘黄色进度圈
function orangeCircle(){
ctx.beginPath();
ctx.strokeStyle = '#fbdb32';
//使用这个使圆环两端是圆弧形状
ctx.lineCap = 'round';
ctx.arc(r, r, cR-5,0 * (Math.PI / 180.0) - (Math.PI / 2),(nowdata * 360) * (Math.PI / 180.0) - (Math.PI / 2));
ctx.stroke();
ctx.save()
}
//裁剪中间水圈
function clipCircle(){
ctx.beginPath();
ctx.arc(r, r, cR-15, 0, 2 * Math.PI,false);
ctx.clip();
}
//渲染canvas
function render () {
ctx.clearRect(0,0,oW,oH);
//最外面淡黄色圈
// drawCircle();
//灰色圆圈
grayCircle();
//橘黄色进度圈
// orangeCircle();
//裁剪中间水圈
clipCircle();
// 控制波幅
oRange.addEventListener("change", function () {
data = ~~(oRange.value) / 100;
console.log("data="+data)
},0);
if (data >= 0.85) {
if (nowrange > range/4) {
var t = range * 0.01;
nowrange -= t;
}
} else if (data <= 0.1) {
if (nowrange < range*1.5) {
var t = range * 0.01;
nowrange += t;
}
} else {
if (nowrange <= range) {
var t = range * 0.01;
nowrange += t;
}
if (nowrange >= range) {
var t = range * 0.01;
nowrange -= t;
}
}
if((data - nowdata) > 0) {
nowdata += waveupsp;
}
if((data - nowdata) < 0){
nowdata -= waveupsp
}
sp += 0.07;
// 开始水波动画
drawSine();
// 写字
drawText();
requestAnimationFrame(render)
}