美文网首页
canvas实现波浪进度小球

canvas实现波浪进度小球

作者: 2025丶10丶16 | 来源:发表于2020-08-17 17:18 被阅读0次

看一下最终效果:

canvas波浪进度球.gif

首先:
HTML放三个canvas标签

<canvas id="rate-one"></canvas>
<canvas id="rate-two"></canvas>
<canvas id="rate-three"></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偏移量
}

3、内部添加画圆的方法绘制三个颜色渐变的圆,对canvas的属性和方法不熟悉的可以参考https://www.w3school.com.cn/tags/html_ref_canvas.asp

            //画圈函数
            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');
        }

相关文章

网友评论

      本文标题:canvas实现波浪进度小球

      本文链接:https://www.haomeiwen.com/subject/erpqjktx.html