美文网首页
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