canvas 进度条

 

自制可配制的canvas进度条,

    <!DOCTYPE html>
    <html>
    <head> 
        <meta charset="utf-8"> 
            <title>CanvasTest</title> 
            <style type="text/css">
            .ProgressBar{
                width:300px;
            }
        </style>
    </head>
    <body>


        <div class="ProgressBar" currentValue="2600" currentTarget="2200" totalTarget="2500" multiple=1.5  currentTargetShow="true">progress1</div>
        <div class="ProgressBar"  currentValue="2000" currentTarget="2200" totalTarget="2500" multiple=1 currentTargetShow="false">progress2</div>

        <script>
            //current value
            //current target
            //total target
            //multiple  进度条长度控制,1为设计长度,小于1为缩小,大于1为加长       
            //$scale 响应式布局参数        
            var ProgressBars=document.body.querySelectorAll(".ProgressBar");
            for (var i =0 ; i <=ProgressBars.length; i++) {

                var ProgressBar=ProgressBars[i];
                var canvas=document.createElement("canvas");

                var currentValue=eval(ProgressBar.getAttribute("currentValue"));
                var currentTarget=eval(ProgressBar.getAttribute("currentTarget"));
                var totalTarget=eval(ProgressBar.getAttribute("totalTarget"));
                var multiple=eval(ProgressBar.getAttribute("multiple"));
                var currentTargetShow=eval(ProgressBar.getAttribute("currentTargetShow"));
                
                var $fontSize=window.getComputedStyle(document.querySelector("body")).fontSize;
                var $scale= $fontSize.substr(0,$fontSize.length-2)/16;

                
                const totalTargetWidth=300*multiple;
                canvas.width=(160+totalTargetWidth)*$scale;
                canvas.height=50*$scale;
                
                const currentValueWidth=80*$scale;//左侧当前值宽度
                const progressHeight=30*$scale;//progress高度
                const yStart10=10*$scale;

                const textStartX=20*$scale;
                const textStartY=33*$scale;

                const currentTargetWidth=6*$scale;

                
                
                var currentOutputWidth;
                var current2TotalTarget=currentValue/totalTarget;
                var current2CurrentTarget=currentValue/currentTarget;
                var currentTargetLeft;
                var extendCurrentTargetWidth=0;
                var noProductWidth=0;
                //current value> totalTarget
                if(current2TotalTarget>=1){
                    currentOutputWidth=totalTargetWidth*$scale;
                  

                }else{ //current value< totalTarget
                    
                    if(current2CurrentTarget>=1){ //current value>currentTarget
                        currentOutputWidth=currentTarget/totalTarget*totalTargetWidth*$scale;
                        extendCurrentTargetWidth=(currentValue-currentTarget)/totalTarget*totalTargetWidth*$scale;
                        //noProductWidth=(totalTarget-currentValue)/totalTarget*totalTargetWidth*$scale;
                    }else{//currentValue<currentTarget
                        currentOutputWidth=currentValue/totalTarget*totalTargetWidth*$scale;
                       
                       // extendCurrentTargetWidth=currentOutputWidth;
                    }
                      noProductWidth=(totalTarget-currentValue)/totalTarget*totalTargetWidth*$scale;
                }
                currentTargetLeft=currentOutputWidth+currentValueWidth-3*$scale;



                //current value
                var ctx=canvas.getContext("2d");
                ctx.fillStyle="#dae3f3";
                ctx.fillRect(0,yStart10,currentValueWidth,progressHeight);
                //current value
                ctx.fillStyle="red";ctx.font="20px 微软雅黑";
                ctx.fillText(currentValue,textStartX,33);
                
                //current progress
                ctx.fillStyle="#00b050";
                ctx.fillRect(currentValueWidth,yStart10,currentOutputWidth,progressHeight);

                //extend current
                ctx.fillStyle="#92d050";
                ctx.fillRect(currentValueWidth+currentOutputWidth,yStart10,extendCurrentTargetWidth,progressHeight);
                
                //no product——未生产
                ctx.fillStyle="#CCC";
                ctx.fillRect(currentValueWidth+currentOutputWidth+extendCurrentTargetWidth,yStart10,noProductWidth,progressHeight);
                
                //total target
                ctx.fillStyle="#dae3f3";
                ctx.fillRect(canvas.width-currentValueWidth,yStart10,currentValueWidth,progressHeight);
                ctx.fillStyle="red";ctx.font="20px 微软雅黑";
                //total target
                ctx.fillText(totalTarget,(currentValueWidth*1.25+totalTargetWidth)*$scale,textStartY);

                
                 //up down rectangle
                 if(currentTargetShow){
                     ctx.strokeStyle ="blue";
                    ctx.lineWidth=2;
                    ctx.strokeRect(currentTargetLeft,yStart10/2,currentTargetWidth,yStart10);
                    ctx.strokeRect(currentTargetLeft,yStart10/2*7,currentTargetWidth,yStart10);
                 }
                
                ProgressBar.appendChild(canvas);
        }





    </script>

</body>
</html>

 

其效果图如下:

 

 

在此demo中,最重要的一点是利用下述代码查找页面中的 class="ProgressBar"的所有进度条,并利用html的自定义属性存储从后端传递到前端的progress bar参数。

document.body.querySelectorAll(".ProgressBar")

如此前端引用JS 控件就如同写html5原生的标签一样自然,减少冗余代码。


另用svg也可,但svg有一个缺点就是其绘制的图形在html中,css是可以对其进行相应的控制,若选择器使用不佳,对SVG内部会产生影响。但在选择器使用上若能避免滥用的情况下,那么用svg+CSS来实现可配置化,是一个不错的选择。

 

posted @ 2021-11-01 19:09  盛沧海  阅读(327)  评论(0编辑  收藏  举报