2

我正在尝试以画布上绘制的圆角矩形的形式制作进度条,这个 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/

4

1 回答 1

8

You can draw the percentage-stroke of rounded rectangle like this:

enter image description here

Full code is at the bottom and here is a Fiddle: http://jsfiddle.net/m1erickson/P2qTq/

First define the dimensions of the rect. You need the horizontal and vertical line lengths and corner radius

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

Since you will be stroking the rect incrementally, calculate at what accumulated length each segment of the rect will begin.

// 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

Then incrementally draw the rect using the specified percentage

// 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
}

You need to determine the appropriate length of each segment to draw

For lines, calculate the length of that line needed. If the line needs to be fully drawn, clamp the line size drawn to the maximum length of that line. Then draw the line from the starting point to the calculated end point.

    // 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);
    }

For corners, calculate the length of that arc needed. If the corner needs to be fully drawn, clamp the arc size to the maximum length of the corner. Then draw the arc sweeping from the calculated start to calculated end.

    // 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);    
    }

Here is full code and a Fiddle: 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>
于 2013-05-02T04:35:30.847 回答