看一下最终效果:
canvas波浪进度球.gif
首先:
HTML放三个canvas标签
这里考虑到需求页面有三个类似小球,且后续可能还会用到,所以对绘制小球的方法进行封装:
1、定义方法,并创建画布cW,cH为canvas宽高
function drawRate(id, rate, color1, color2, color3, color4){
//创建画布
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
//canvas属性
var clientW = document.documentElement.clientWidth > 1000 ? document.documentElement.clientWidth : 1000; //由于画布width和height自适应宽高
var cW = canvas.width = 309/1920 * clientW;
var cH = canvas.height = 309/1920 * clientW;
}
2、添加球的属性以及后续sin曲线的属性
function drawRate(id, rate, color1, color2, color3, color4){
//创建画布
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
//canvas属性
var clientW = document.documentElement.clientWidth > 1000 ? document.documentElement.clientWidth : 1000; //由于画布width和height自适应宽高
var cW = canvas.width = 309/1920 * clientW;
var cH = canvas.height = 309/1920 * clientW;
var lineWidth = 2;
console.log(cW ,cH,clientW)
//内圆属性
var r = 0.8 * cW / 2; //半径
var cR = r - 2 * lineWidth;
//sin曲线属性
var sX = 0; //sin函数的初始x值
var axisLength = cW; //轴长
var waveWidth = 0.035; //波浪宽度,数越小越宽
var waveHeight = 6; //波浪高度,数越大越高
var speed = 0.05; //波浪速度,数越大速度越快
var xOffset = 0; //波浪x偏移量
}
//画圈函数
ctx.lineWidth = lineWidth;
var IsdrawCircled = false;
var drawCircle = function () {
ctx.beginPath();
ctx.strokeStyle = color1;
ctx.arc(cW / 2, cH / 2, cR + 21, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle = color1;
ctx.fill();
ctx.beginPath();
ctx.strokeStyle = color4;
ctx.arc(cW/2, cH/2, cR + 11, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle = color2;
ctx.fill();
ctx.beginPath();
ctx.strokeStyle = color4;
ctx.arc(cW/2, cH/2, cR + 1, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(cW / 2, cH / 2, cR, 0, 2 * Math.PI);
ctx.fillStyle = color2;
ctx.fill();
ctx.clip();
IsdrawCircled = true
}
4、绘制sin曲线:
//画sin 曲线函数
var drawSin = function (xOffset) {
ctx.save();
ctx.rect(0, 0, cW, cH);
ctx.fillStyle = color3;
ctx.fill();
//用于存放绘制Sin曲线的点
var points = [];
ctx.beginPath();
//在整个轴长上取点
for (var x = sX; x < sX + axisLength; x += 20 / axisLength) {
//公式 “振幅高*sin(x*振幅宽 + 振幅偏移量)”
var y = Math.sin((-sX - x) * waveWidth + xOffset);
var dY = cH * (1 - rate / 100) - 10;
points.push([x, dY + y * waveHeight]);
ctx.lineTo(x, dY + y * waveHeight);
}
//绘制路径
ctx.lineTo(axisLength, cH);
ctx.lineTo(sX, cH);
ctx.lineTo(points[0][0], points[0][1]);
//填充sin曲线画出的区域
ctx.fillStyle = color4;
ctx.fill();
ctx.restore();
};
5、小球内部写入百分比
//写百分比文本函数
var drawText = function () {
ctx.save();
var size = 0.3 * cR;
ctx.font = size + 'px Microsoft Yahei';
ctx.textAlign = 'center';
ctx.fillStyle = "#ffffff";
ctx.fillText(rate + '%', cW/2, cW/2 + size / 2);
ctx.restore();
};
6、最后绘制的方法:
var render = function () {
ctx.clearRect(0, 0, cW, cH);
if (IsdrawCircled == false) {
drawCircle();
}
//drawSin(xOffset + Math.PI * 0.7);
drawSin(xOffset);
drawText();
xOffset += speed;
requestAnimationFrame(render);
}
render();
最后贴一个封装好的方法:
//画波浪球id:dom节点id, rate:占比, color1-4:由外到内圆的颜色
function drawRate(id, rate, color1, color2, color3, color4){
//创建画布
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
//canvas属性
var clientW = document.documentElement.clientWidth > 1000 ? document.documentElement.clientWidth : 1000; //由于画布width和height自适应宽高
var cW = canvas.width = 309/1920 * clientW;
var cH = canvas.height = 309/1920 * clientW;
var lineWidth = 2;
console.log(cW ,cH,clientW)
//内圆属性
var r = 0.8 * cW / 2; //半径
var cR = r - 2 * lineWidth;
//sin曲线属性
var sX = 0; //sin函数的初始x值
var axisLength = cW; //轴长
var waveWidth = 0.035; //波浪宽度,数越小越宽
var waveHeight = 6; //波浪高度,数越大越高
var speed = 0.05; //波浪速度,数越大速度越快
var xOffset = 0; //波浪x偏移量
ctx.lineWidth = lineWidth;
//画圈函数
var IsdrawCircled = false;
var drawCircle = function () {
ctx.beginPath();
ctx.strokeStyle = color1;
ctx.arc(cW / 2, cH / 2, cR + 21, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle = color1;
ctx.fill();
ctx.beginPath();
ctx.strokeStyle = color4;
ctx.arc(cW/2, cH/2, cR + 11, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle = color2;
ctx.fill();
ctx.beginPath();
ctx.strokeStyle = color4;
ctx.arc(cW/2, cH/2, cR + 1, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(cW / 2, cH / 2, cR, 0, 2 * Math.PI);
ctx.fillStyle = color2;
ctx.fill();
ctx.clip();
IsdrawCircled = true
}
//画sin 曲线函数
var drawSin = function (xOffset) {
ctx.save();
ctx.rect(0, 0, cW, cH);
ctx.fillStyle = color3;
ctx.fill();
var points = []; //用于存放绘制Sin曲线的点
ctx.beginPath();
//在整个轴长上取点
for (var x = sX; x < sX + axisLength; x += 20 / axisLength) {
//此处坐标(x,y)的取点,依靠公式 “振幅高*sin(x*振幅宽 + 振幅偏移量)”
var y = Math.sin((-sX - x) * waveWidth + xOffset);
var dY = cH * (1 - rate / 100) - 10;
points.push([x, dY + y * waveHeight]);
ctx.lineTo(x, dY + y * waveHeight);
}
//封闭路径
ctx.lineTo(axisLength, cH);
ctx.lineTo(sX, cH);
ctx.lineTo(points[0][0], points[0][1]);
ctx.fillStyle = color4;
ctx.fill();
ctx.restore();
};
//写百分比文本函数
var drawText = function () {
ctx.save();
var size = 0.3 * cR;
ctx.font = size + 'px Microsoft Yahei';
ctx.textAlign = 'center';
ctx.fillStyle = "#ffffff";
ctx.fillText(rate + '%', cW/2, cW/2 + size / 2);
ctx.restore();
};
var render = function () {
ctx.clearRect(0, 0, cW, cH);
if (IsdrawCircled == false) {
drawCircle();
}
//drawSin(xOffset + Math.PI * 0.7);
drawSin(xOffset);
drawText();
xOffset += speed;
requestAnimationFrame(render);
}
render();
}
使用封装好的方法绘制进度球,并且在页面大小变化时重新绘制进度球的大小:
$(function () {
window.onresize = function () {
initRates();
}
})
function initRates() {
drawRate('rate-one', '50', '#e9faff', '#afecff', '#94e5ff', '#29caff');
drawRate('rate-two', '30', '#fefbed', '#fdefbc', '#fce79a', '#fad44b');
drawRate('rate-three', '70', '#feefef', '#fcd4d4', '#f9b3b3', '#f36666');
}