带圆角的帆布矩形作为进度条?

时间:2013-05-01 23:12:29

标签: html5 canvas shapes

我正在尝试以画布上绘制的圆角矩形的形式创建一个进度条,这个jsfiddle具有以下形状:

http://jsfiddle.net/xT3ax/

this.beginPath();
this.moveTo(x + cornerRadius.upperLeft, y);
this.lineTo(x + width - cornerRadius.upperRight, y);
this.quadraticCurveTo(x + width, y, x + width, y + cornerRadius.upperRight);
this.lineTo(x + width, y + height - cornerRadius.lowerRight);
this.quadraticCurveTo(x + width, y + height, x + width - cornerRadius.lowerRight, y + height);
this.lineTo(x + cornerRadius.lowerLeft, y + height);
this.quadraticCurveTo(x, y + height, x, y + height - cornerRadius.lowerLeft);
this.lineTo(x, y + cornerRadius.upperLeft);
this.quadraticCurveTo(x, y, x + cornerRadius.upperLeft, y);
this.closePath();

有没有简单的方法来绘制这个形状的百分比?或者有一种百分比,其余的是另一种颜色?

我想不出如何做到这一点,除了可能将形状分成4或8块并绘制构成整个形状的每条线或曲线的百分比?像这样但更好:

http://jsfiddle.net/xT3ax/1/

1 个答案:

答案 0 :(得分:7)

您可以像这样绘制圆角矩形的百分比笔划:

enter image description here

完整代码位于底部,这里是一个小提琴:http://jsfiddle.net/m1erickson/P2qTq/

首先定义rect的尺寸。您需要水平和垂直线长以及角半径

// define the rectangle
var horizLineLength=80;
var vertLineLength=40;
var cornerRadius=25;

由于你将逐步抚摸矩形,计算矩形的每个段开始的累积长度。

// calc some lengths for use in percent complete
var cornerLength = 2 * cornerRadius * Math.PI;
var totalLength = cornerLength*4+horizLineLength*2+vertLineLength*2;

// calc at what accumulated length each part of the rect starts
var startT=0;                           // top line
var startTR=horizLineLength;            // top-right corner
var startR=startTR+cornerLength;        // right line
var startBR=startR+vertLineLength;      // bottom-right corner
var startB=startBR+cornerLength;        // bottom line
var startBL=startB+horizLineLength;     // bottom-left corner
var startL=startBL+cornerLength;        // left line
var startTL=startL+vertLineLength;      // top-left corner

然后使用指定的百分比

逐步绘制矩形
// incrementally draw the rectangle
// based on the specified percentage
function drawPercentRect(percent){

    // use percent to calc the length-traveled-along-rect
    accumLength = percent/100 * totalLength;

    // clear the canvas
    // draw the approprate portion of the  top line
    // draw the approprate portion of the  top-right corner
    // draw the approprate portion of the  right line
    // draw the approprate portion of the  bottom-right corner
    // draw the approprate portion of the  bottom line
    // draw the approprate portion of the  bottom-left corner
    // draw the approprate portion of the  left line
    // draw the approprate portion of the  top-left corner
}

您需要确定要绘制的每个片段的适当长度

对于线条,计算所需线条的长度。如果需要完全绘制线条,请将绘制的线条大小限制为该线条的最大长度。然后绘制从起点到计算终点的线。

    // top line
    d=accumLength-startT
    d=Math.min(d,horizLineLength);
    if(d>0){
        x1 = offsetX + cornerRadius;
        y1 = offsetY;
        x2 = offsetX + cornerRadius + d;
        y2 = offsetY;
        drawLine(x1,y1,x2,y2);
    }

对于角点,计算所需弧线的长度。如果需要完全绘制拐角,请将弧形尺寸夹紧到拐角的最大长度。然后绘制扫描从计算的开始扫描到计算结束。

    // top-right corner
    d=accumLength-startTR;
    d=Math.min(d,cornerLength);
    if(d>0){
        x = offsetX + cornerRadius + horizLineLength;
        y = offsetY + cornerRadius;
        start = -Math.PI/2;
        end   = -Math.PI/2 + (d/cornerLength * Math.PI/2) ;
        drawCorner(x,y,start,end);    
    }

以下是完整代码和小提琴:http://jsfiddle.net/m1erickson/P2qTq/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    #slider-vertical{ height:200px; position:absolute; top:60px; left:350px; }
    #percent{ width:25px; position:absolute; top:20px; left:340px; border:0; color:blue; font-weight:bold;}
</style>

<script>
    $(function(){

        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");

        // styling
        ctx.lineWidth=15;
        ctx.strokeStyle="gold";

        // define the rectangle
        var offsetX=75;
        var offsetY=100;
        var horizLineLength=80;
        var vertLineLength=40;
        var cornerRadius=25;

        // calc some lengths for use in percent complete
        var cornerLength = 2 * cornerRadius * Math.PI;
        var totalLength = cornerLength*4+horizLineLength*2+vertLineLength*2;


        // calc at what accumulated length each part of the rect starts
        var startT=0;
        var startTR=horizLineLength;
        var startR=startTR+cornerLength;
        var startBR=startR+vertLineLength;
        var startB=startBR+cornerLength;
        var startBL=startB+horizLineLength;
        var startL=startBL+cornerLength;
        var startTL=startL+vertLineLength;

        // percent complete
        var percent=100;

        // draw the radius rectangle
        function drawPercentRect(percent){

            // percent expressed as a length-traveled-along-rect
            accumLength = percent/100 * totalLength;

            // clear the canvas
            ctx.clearRect(0,0,canvas.width,canvas.height);

            // top line
            d=accumLength-startT
            d=Math.min(d,horizLineLength);
            if(d>0){
                x1 = offsetX + cornerRadius;
                y1 = offsetY;
                x2 = offsetX + cornerRadius + d;
                y2 = offsetY;
                drawLine(x1,y1,x2,y2);
            }

            // top-right corner
            d=accumLength-startTR;
            d=Math.min(d,cornerLength);
            if(d>0){
                x = offsetX + cornerRadius + horizLineLength;
                y = offsetY + cornerRadius;
                start = -Math.PI/2;
                end   = -Math.PI/2 + (d/cornerLength * Math.PI/2) ;
                drawCorner(x,y,start,end);    
            }

            // right line
            d=accumLength-startR;
            d=Math.min(d,vertLineLength);
            if(d>0){
                x1= offsetX + cornerRadius + horizLineLength + cornerRadius;
                y1= offsetY + cornerRadius;
                x2= offsetX + cornerRadius + horizLineLength + cornerRadius;
                y2= offsetY + cornerRadius + d;
                drawLine(x1,y1,x2,y2);
            }

            // bottom-right corner
            d=accumLength-startBR;
            d=Math.min(d,cornerLength);
            if(d>0){
                x = offsetX + cornerRadius + horizLineLength;
                y = offsetY + cornerRadius + vertLineLength;
                start = 0;
                end   = (d/cornerLength) * Math.PI/2;
                drawCorner(x,y,start,end);    
            }

            // bottom line
            d=accumLength-startB;
            d=Math.min(d,horizLineLength);
            if(d>0){
                x1= offsetX + cornerRadius + horizLineLength;
                y1= offsetY + cornerRadius + vertLineLength + cornerRadius;
                x2 = offsetX + cornerRadius + horizLineLength - d;
                y2 = offsetY + cornerRadius + vertLineLength + cornerRadius;
                drawLine(x1,y1,x2,y2);
            }

            // bottom-left corner
            d=accumLength-startBL;
            d=Math.min(d,cornerLength);
            if(d>0){
                x = offsetX + cornerRadius;
                y = offsetY + cornerRadius + vertLineLength;
                start = Math.PI/2;
                end   = Math.PI/2 + (d/cornerLength) * Math.PI/2;
                drawCorner(x,y,start,end);
            }

            // left line
            d=accumLength-startL;
            d=Math.min(d,vertLineLength);
            if(d>0){
                x1= offsetX;
                y1= offsetY + cornerRadius + vertLineLength;
                x2= offsetX;
                y2= offsetY + cornerRadius + vertLineLength - d;
                drawLine(x1,y1,x2,y2);
            }

            // top-left corner
            d=accumLength-startTL;
            d=Math.min(d,cornerLength);
            if(d>0){
                x = offsetX + cornerRadius;
                y = offsetY + cornerRadius;
                start = Math.PI;
                end   = Math.PI + (d/cornerLength) * Math.PI/2;
                drawCorner(x,y,start,end);
            }

        }

        function drawLine(x1,y1,x2,y2){
            ctx.beginPath();
            ctx.moveTo(x1,y1)
            ctx.lineTo(x2,y2);
            ctx.stroke();
        }

        function drawCorner(x,y,start,end){
            ctx.beginPath();
            ctx.arc(x,y,cornerRadius,start,end,false);
            ctx.stroke();
        }


        // slider for demo
        $( "#slider-vertical" ).slider({

          orientation: "vertical",
          range: "min",
          min: 0,
          max: 100,
          value: 100,
          slide: function( event, ui ) {
            $( "#percent" ).val( ui.value );
            drawPercentRect( ui.value );
          }
        });

        $( "#percent" ).val( $( "#slider-vertical" ).slider( "value" ) );

        // draw at 100% to start
        drawPercentRect(100);


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
    <input type="text" id="percent" />
    <div id="slider-vertical"></div>
</body>
</html>