【问题标题】:How to draw a rounded rectangle using HTML Canvas?如何使用 HTML Canvas 绘制圆角矩形?
【发布时间】:2010-11-18 08:05:19
【问题描述】:

HTML Canvas 提供了绘制矩形的方法,fillRect()strokeRect(),但是我找不到绘制圆角矩形的方法。我该怎么做?

【问题讨论】:

标签: html canvas


【解决方案1】:

我需要做同样的事情并创建了一个方法来做。

// Now you can just call
var ctx = document.getElementById("rounded-rect").getContext("2d");
// Draw using default border radius, 
// stroke it but no fill (function's default values)
roundRect(ctx, 5, 5, 50, 50);
// To change the color on the rectangle, just manipulate the context
ctx.strokeStyle = "rgb(255, 0, 0)";
ctx.fillStyle = "rgba(255, 255, 0, .5)";
roundRect(ctx, 100, 5, 100, 100, 20, true);
// Manipulate it again
ctx.strokeStyle = "#0f0";
ctx.fillStyle = "#ddd";
// Different radii for each corner, others default to 0
roundRect(ctx, 300, 5, 200, 100, {
  tl: 50,
  br: 25
}, true);

/**
 * Draws a rounded rectangle using the current state of the canvas.
 * If you omit the last three params, it will draw a rectangle
 * outline with a 5 pixel border radius
 * @param {CanvasRenderingContext2D} ctx
 * @param {Number} x The top left x coordinate
 * @param {Number} y The top left y coordinate
 * @param {Number} width The width of the rectangle
 * @param {Number} height The height of the rectangle
 * @param {Number} [radius = 5] The corner radius; It can also be an object 
 *                 to specify different radii for corners
 * @param {Number} [radius.tl = 0] Top left
 * @param {Number} [radius.tr = 0] Top right
 * @param {Number} [radius.br = 0] Bottom right
 * @param {Number} [radius.bl = 0] Bottom left
 * @param {Boolean} [fill = false] Whether to fill the rectangle.
 * @param {Boolean} [stroke = true] Whether to stroke the rectangle.
 */
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
  if (typeof stroke === 'undefined') {
    stroke = true;
  }
  if (typeof radius === 'undefined') {
    radius = 5;
  }
  if (typeof radius === 'number') {
    radius = {tl: radius, tr: radius, br: radius, bl: radius};
  } else {
    var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0};
    for (var side in defaultRadius) {
      radius[side] = radius[side] || defaultRadius[side];
    }
  }
  ctx.beginPath();
  ctx.moveTo(x + radius.tl, y);
  ctx.lineTo(x + width - radius.tr, y);
  ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
  ctx.lineTo(x + width, y + height - radius.br);
  ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
  ctx.lineTo(x + radius.bl, y + height);
  ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
  ctx.lineTo(x, y + radius.tl);
  ctx.quadraticCurveTo(x, y, x + radius.tl, y);
  ctx.closePath();
  if (fill) {
    ctx.fill();
  }
  if (stroke) {
    ctx.stroke();
  }

}
<canvas id="rounded-rect" width="500" height="200">
  <!-- Insert fallback content here -->
</canvas>

【讨论】:

  • 完美答案...这不是画布原生的吗?!谢谢。
  • 代码有bug,需要在填充后进行描边,否则在小矩形上填充会覆盖描边。
  • 我手头没有示例,但我必须针对我在代码上测试的案例修改该顺序。这是合乎逻辑的,如果您还没有填充矩形,它如何正确描边(使用矩形背景颜色进行平滑处理)?
  • @Juan 嘿,我的错,我注意到了这篇博文并在之后发现了这个花絮。我的意思是撤消编辑。干得好,为你 +1!?
  • Zig Mandel 是正确的:它应该被填充然后抚摸。原因是如果你先描边然后填充,那么线宽就会减半。尝试使用非常粗的线宽(例如 20)并将填充了背景颜色的圆角矩形与未填充的圆角矩形进行比较。填充的线宽将是未填充的线宽的一半。
【解决方案2】:

我从@jhoff 的解决方案开始,但将其重写为使用宽度/高度参数,使用arcTo 使其更加简洁:

CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r) {
  if (w < 2 * r) r = w / 2;
  if (h < 2 * r) r = h / 2;
  this.beginPath();
  this.moveTo(x+r, y);
  this.arcTo(x+w, y,   x+w, y+h, r);
  this.arcTo(x+w, y+h, x,   y+h, r);
  this.arcTo(x,   y+h, x,   y,   r);
  this.arcTo(x,   y,   x+w, y,   r);
  this.closePath();
  return this;
}

还返回上下文,以便您可以链接一点。例如:

ctx.roundRect(35, 10, 225, 110, 20).stroke(); //or .fill() for a filled rect

【讨论】:

  • 我不会乱用 Canvas 渲染上下文,除了那个好的解决方案。
  • 这个解决方案的问题是你不能独立控制每个角的半径。不够灵活。请参阅下面的解决方案。
  • 这是一个居中的矩形,如果有人需要一个左上角在(x,y)的矩形,保存上下文,添加翻译到(-w/2,-h/2),然后恢复上下文。
  • 谢谢,这是迄今为止唯一对我有用的,当半径大于或大于高度或宽度时,其他人会给我带来问题。已实施!
  • 请注意,此解决方案可以使任何多边形都具有圆角。一个fiddle
【解决方案3】:

HTML5 画布不提供绘制圆角矩形的方法。

使用lineTo()arc() 方法怎么样?

您也可以使用quadraticCurveTo() 方法代替arc() 方法。

【讨论】:

【解决方案4】:

Juan,我对你的方法做了一点改进,允许单独更改每个矩形角的半径:

/** 
 * Draws a rounded rectangle using the current state of the canvas.  
 * If you omit the last three params, it will draw a rectangle  
 * outline with a 5 pixel border radius  
 * @param {Number} x The top left x coordinate 
 * @param {Number} y The top left y coordinate  
 * @param {Number} width The width of the rectangle  
 * @param {Number} height The height of the rectangle 
 * @param {Object} radius All corner radii. Defaults to 0,0,0,0; 
 * @param {Boolean} fill Whether to fill the rectangle. Defaults to false. 
 * @param {Boolean} stroke Whether to stroke the rectangle. Defaults to true. 
 */
CanvasRenderingContext2D.prototype.roundRect = function (x, y, width, height, radius, fill, stroke) {
    var cornerRadius = { upperLeft: 0, upperRight: 0, lowerLeft: 0, lowerRight: 0 };
    if (typeof stroke == "undefined") {
        stroke = true;
    }
    if (typeof radius === "object") {
        for (var side in radius) {
            cornerRadius[side] = radius[side];
        }
    }

    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();
    if (stroke) {
        this.stroke();
    }
    if (fill) {
        this.fill();
    }
} 

像这样使用它:

var canvas = document.getElementById("canvas");
var c = canvas.getContext("2d");
c.fillStyle = "blue";
c.roundRect(50, 100, 50, 100, {upperLeft:10,upperRight:10}, true, true);

【讨论】:

  • 这种方法可以很好地控制圆角。为什么这不是公认的答案>
  • @VighneshRaut 可能是因为这个答案复制/粘贴了原始接受的答案并添加了圆角。我将它合并到接受的答案中,这归功于这个答案。接受的答案有一个活生生的例子,如果您确实希望所有角都具有相同的半径(这是最常见的情况),语法会更简单。最后,这个答案建议修改原生对象的原型,这是一个禁忌
【解决方案5】:

下面的drawPolygon 函数可用于绘制任何圆角多边形。

See it running here.

function drawPolygon(ctx, pts, radius) {
  if (radius > 0) {
    pts = getRoundedPoints(pts, radius);
  }
  var i, pt, len = pts.length;
  ctx.beginPath();
  for (i = 0; i < len; i++) {
    pt = pts[i];
    if (i == 0) {          
      ctx.moveTo(pt[0], pt[1]);
    } else {
      ctx.lineTo(pt[0], pt[1]);
    }
    if (radius > 0) {
      ctx.quadraticCurveTo(pt[2], pt[3], pt[4], pt[5]);
    }
  }
  ctx.closePath();
}

function getRoundedPoints(pts, radius) {
  var i1, i2, i3, p1, p2, p3, prevPt, nextPt,
      len = pts.length,
      res = new Array(len);
  for (i2 = 0; i2 < len; i2++) {
    i1 = i2-1;
    i3 = i2+1;
    if (i1 < 0) {
      i1 = len - 1;
    }
    if (i3 == len) {
      i3 = 0;
    }
    p1 = pts[i1];
    p2 = pts[i2];
    p3 = pts[i3];
    prevPt = getRoundedPoint(p1[0], p1[1], p2[0], p2[1], radius, false);
    nextPt = getRoundedPoint(p2[0], p2[1], p3[0], p3[1], radius, true);
    res[i2] = [prevPt[0], prevPt[1], p2[0], p2[1], nextPt[0], nextPt[1]];
  }
  return res;
};

function getRoundedPoint(x1, y1, x2, y2, radius, first) {
  var total = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)),
      idx = first ? radius / total : (total - radius) / total;
  return [x1 + (idx * (x2 - x1)), y1 + (idx * (y2 - y1))];
};

该函数接收一个包含多边形点的数组,如下所示:

var canvas = document.getElementById("cv");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "#000000";
ctx.lineWidth = 5;

drawPolygon(ctx, [[20,   20],
                  [120,  20],
                  [120, 120],
                  [ 20, 120]], 10);
ctx.stroke();

这是here 发布的解决方案的一个端口和更通用的版本。

【讨论】:

    【解决方案6】:

    此代码创建一个 100 像素的正方形,圆角为 30 像素。

    var canvas = document.createElement("canvas");
    document.body.appendChild(canvas);
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(100,100);
    ctx.arcTo(0,100,0,0,30);
    ctx.arcTo(0,0,100,0,30);
    ctx.arcTo(100,0,100,100,30);
    ctx.arcTo(100,100,0,100,30);
    ctx.fill();

    【讨论】:

    • 这正是我想要的
    • 最后一个简短而全面的回复确实有效。谢谢。
    【解决方案7】:

    这是我写的...使用圆弧而不是二次曲线来更好地控制半径。此外,它把抚摸和填充留给你

        /* Canvas 2d context - roundRect
     *
     * Accepts 5 parameters, the start_x and start_y points, the end_x and end_y points, and the radius of the corners
     * 
     * No return value
     */
    
    CanvasRenderingContext2D.prototype.roundRect = function(sx,sy,ex,ey,r) {
        var r2d = Math.PI/180;
        if( ( ex - sx ) - ( 2 * r ) < 0 ) { r = ( ( ex - sx ) / 2 ); } //ensure that the radius isn't too large for x
        if( ( ey - sy ) - ( 2 * r ) < 0 ) { r = ( ( ey - sy ) / 2 ); } //ensure that the radius isn't too large for y
        this.beginPath();
        this.moveTo(sx+r,sy);
        this.lineTo(ex-r,sy);
        this.arc(ex-r,sy+r,r,r2d*270,r2d*360,false);
        this.lineTo(ex,ey-r);
        this.arc(ex-r,ey-r,r,r2d*0,r2d*90,false);
        this.lineTo(sx+r,ey);
        this.arc(sx+r,ey-r,r,r2d*90,r2d*180,false);
        this.lineTo(sx,sy+r);
        this.arc(sx+r,sy+r,r,r2d*180,r2d*270,false);
        this.closePath();
    }
    

    这是一个例子:

    var _e = document.getElementById('#my_canvas');
    var _cxt = _e.getContext("2d");
    _cxt.roundRect(35,10,260,120,20);
    _cxt.strokeStyle = "#000";
    _cxt.stroke();
    

    【讨论】:

    • 这如何让您更好地控制半径?我以为你会允许 x/y 半径(椭圆角),并为每个角指定不同的半径
    • 您的r2d 可能希望被称为d2r
    • @JuanMendes:此解决方案中圆角的(基于弧的)形状比您的(基于二次的)解决方案的圆角更圆。我认为这就是他所说的“更好地控制半径”的意思。
    • 我也用过这个方法,比用quadraticCurve好。但是如果你画出比矩形更复杂的东西,那真的很痛苦。有一个类似于 Android 画布的自动方法。
    【解决方案8】:

    所以这是基于使用 lineJoin="round" 和适当的比例,数学和逻辑我已经能够制作这个函数,这并不完美,但希望它有所帮助。如果你想让每个角落都有不同的半径,请查看:https://p5js.org/reference/#/p5/rect

    来吧:

    CanvasRenderingContext2D.prototype.roundRect = function (x,y,width,height,radius) {
        radius = Math.min(Math.max(width-1,1),Math.max(height-1,1),radius);
        var rectX = x;
        var rectY = y;
        var rectWidth = width;
        var rectHeight = height;
        var cornerRadius = radius;
    
        this.lineJoin = "round";
        this.lineWidth = cornerRadius;
        this.strokeRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
        this.fillRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
        this.stroke();
        this.fill();
    }
    

    CanvasRenderingContext2D.prototype.roundRect = function (x,y,width,height,radius) {
        radius = Math.min(Math.max(width-1,1),Math.max(height-1,1),radius);
        var rectX = x;
        var rectY = y;
        var rectWidth = width;
        var rectHeight = height;
        var cornerRadius = radius;
    
        this.lineJoin = "round";
        this.lineWidth = cornerRadius;
        this.strokeRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
        this.fillRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
        this.stroke();
        this.fill();
    }
        var canvas = document.getElementById("myCanvas");
        var ctx = canvas.getContext('2d');
    function yop() {
      ctx.clearRect(0,0,1000,1000)
      ctx.fillStyle = "#ff0000";
      ctx.strokeStyle = "#ff0000";  ctx.roundRect(Number(document.getElementById("myRange1").value),Number(document.getElementById("myRange2").value),Number(document.getElementById("myRange3").value),Number(document.getElementById("myRange4").value),Number(document.getElementById("myRange5").value));
    requestAnimationFrame(yop);
    }
    requestAnimationFrame(yop);
    <input type="range" min="0" max="1000" value="10" class="slider" id="myRange1"><input type="range" min="0" max="1000" value="10" class="slider" id="myRange2"><input type="range" min="0" max="1000" value="200" class="slider" id="myRange3"><input type="range" min="0" max="1000" value="100" class="slider" id="myRange4"><input type="range" min="1" max="1000" value="50" class="slider" id="myRange5">
    <canvas id="myCanvas" width="1000" height="1000">
    </canvas>

    【讨论】:

    • 欢迎来到 StackOverflow!由于此代码可能会解决问题,因此最好添加更多有关其工作原理的说明。
    【解决方案9】:

    大家好消息!

    roundRect(x, y, width, height, radii); 现在正式成为 Canvas 2D API 的一部分。

    它暴露在 CanvasRenderingContext2D、Path2D 和 OffscreenCanvasRenderingContext2D 对象上。

    它的radii 参数是一个数组,包含其中一个

    • 单个浮点数,表示用于所有四个角的半径,
    • 两个浮点数,分别代表左上角+右下角和右上角+左下角,
    • 三个浮点数,分别为左上、右上+左下、右下,
    • 或四个花车,每个角落一个,
    • 或相同的组合,但使用 DOMPointInit 对象,表示每个角的 x 半径和 y 半径。

    目前,只有 Chrome 有一个可用的实现(在一个标志下,它仍然不支持 DOMPointInit 对象,但只支持真正的 DOMPoints),你可以在 this repo 找到我制作的 polyfill。

    const canvas = document.querySelector("canvas");
    
    const ctx = canvas.getContext("2d");
    ctx.roundRect(20,20,80,80,[new DOMPoint(60,80), new DOMPoint(110,100)]);
    ctx.strokeStyle = "green";
    ctx.stroke();
    
    const path = new Path2D();
    path.roundRect(120,30,60,90,[0,25,new DOMPoint(60,80), new DOMPoint(110,100)]);
    ctx.fillStyle = "purple";
    ctx.fill(path);
    
    // and a simple one
    ctx.beginPath();
    ctx.roundRect(200,20,80,80,[10]);
    ctx.fillStyle = "orange";
    ctx.fill();
    <script src="https://cdn.jsdelivr.net/gh/Kaiido/roundRect/roundRect.js"></script>
    <canvas></canvas>

    【讨论】:

    • 这会发生吗?
    • @swisswiss 它确实已经发生了。这是规范的一部分,Chrome 有(部分)支持。
    • @Kaiido 我找不到支持哪个版本的 chrome,甚至没有在 MDN 中记录
    • @CodingEdgar 啊,看来他们仍然将其隐藏在实验性 Web 平台标志下。对于 MDN,已准备好上传至 github.com/fserb/canvas2D/pull/18/…
    【解决方案10】:

    歌剧,ffs。

    if (window["CanvasRenderingContext2D"]) {
        /** @expose */
        CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
            if (w < 2*r) r = w/2;
            if (h < 2*r) r = h/2;
            this.beginPath();
            if (r < 1) {
                this.rect(x, y, w, h);
            } else {
                if (window["opera"]) {
                    this.moveTo(x+r, y);
                    this.arcTo(x+r, y, x, y+r, r);
                    this.lineTo(x, y+h-r);
                    this.arcTo(x, y+h-r, x+r, y+h, r);
                    this.lineTo(x+w-r, y+h);
                    this.arcTo(x+w-r, y+h, x+w, y+h-r, r);
                    this.lineTo(x+w, y+r);
                    this.arcTo(x+w, y+r, x+w-r, y, r);
                } else {
                    this.moveTo(x+r, y);
                    this.arcTo(x+w, y, x+w, y+h, r);
                    this.arcTo(x+w, y+h, x, y+h, r);
                    this.arcTo(x, y+h, x, y, r);
                    this.arcTo(x, y, x+w, y, r);
                }
            }
            this.closePath();
        };
        /** @expose */
        CanvasRenderingContext2D.prototype.fillRoundRect = function(x, y, w, h, r) {
            this.roundRect(x, y, w, h, r);
            this.fill();
        };
        /** @expose */
        CanvasRenderingContext2D.prototype.strokeRoundRect = function(x, y, w, h, r) {
            this.roundRect(x, y, w, h, r);
            this.stroke();
        };
    }
    

    由于 Opera 正在使用 WebKit,这在旧案例中也应该保持有效。

    【讨论】:

      【解决方案11】:

      为了使函数与使用画布上下文的常规方式更加一致,可以扩展画布上下文类以包含一个“fillRoundedRect”方法——可以以与调用fillRect 相同的方式调用该方法:

      var canv = document.createElement("canvas");
      var cctx = canv.getContext("2d");
      
      // If thie canvasContext class doesn't have  a fillRoundedRect, extend it now
      if (!cctx.constructor.prototype.fillRoundedRect) {
        // Extend the canvaseContext class with a fillRoundedRect method
        cctx.constructor.prototype.fillRoundedRect = 
          function (xx,yy, ww,hh, rad, fill, stroke) {
            if (typeof(rad) == "undefined") rad = 5;
            this.beginPath();
            this.moveTo(xx+rad, yy);
            this.arcTo(xx+ww, yy,    xx+ww, yy+hh, rad);
            this.arcTo(xx+ww, yy+hh, xx,    yy+hh, rad);
            this.arcTo(xx,    yy+hh, xx,    yy,    rad);
            this.arcTo(xx,    yy,    xx+ww, yy,    rad);
            if (stroke) this.stroke();  // Default to no stroke
            if (fill || typeof(fill)=="undefined") this.fill();  // Default to fill
        }; // end of fillRoundedRect method
      } 
      

      代码检查画布上下文对象的构造函数的原型是否包含“fillRoundedRect”属性并添加一个——第一次。它的调用方式与fillRect 方法相同:

        ctx.fillStyle = "#eef";  ctx.strokeStyle = "#ddf";
        // ctx.fillRect(10,10, 200,100);
        ctx.fillRoundedRect(10,10, 200,100, 5);
      

      该方法使用 arcTo 方法,就像 Grumdring 所做的那样。在该方法中,this 是对ctx 对象的引用。如果未定义,stroke 参数默认为 false。如果未定义,填充参数默认填充矩形。

      (在火狐上测试过,不知道是不是所有的实现都允许以这种方式扩展。)

      【讨论】:

      • 我建议添加:rad = Math.min( rad, ww/2, hh/2 ); 这样它就可以在@Grumdrig 的版本中使用大半径。
      【解决方案12】:

      这是一个使用lineJoin 属性来圆角的解决方案。如果您只需要一个实心形状,它就可以工作,但如果您需要一个小于边框半径的细边框,它就不行了。

      function roundedRect(ctx, options) {
          ctx.strokeStyle = options.color;
          ctx.fillStyle = options.color;
          ctx.lineJoin = "round";
          ctx.lineWidth = options.radius;
      
          ctx.strokeRect(
              options.x+(options.radius*.5),
              options.y+(options.radius*.5),
              options.width-options.radius,
              options.height-options.radius
          );
      
          ctx.fillRect(
              options.x+(options.radius*.5),
              options.y+(options.radius*.5),
              options.width-options.radius,
              options.height-options.radius
          );
      
          ctx.stroke();
          ctx.fill();
      }
      
      const canvas = document.getElementsByTagName("canvas")[0];
      const ctx = canvas.getContext("2d");
      
      roundedRect(ctx, {
          x: 10,
          y: 10,
          width: 200,
          height: 100,
          radius: 35,
          color: "red"
      });
      &lt;canvas&gt;&lt;/canvas&gt;

      【讨论】:

        【解决方案13】:

        当你想要圆角时,尝试添加这条线:ctx.lineCap = "round";

        【讨论】:

        • 嗨,欢迎来到堆栈溢出。看看here。您确定这是矩形的可用答案吗?
        【解决方案14】:

        其他答案中没有一个可以正确处理以下3种情况:

        if ((width >= radius x 2) && (height <= radius * 2))
        if ((width <= radius x 2) && (height >= radius * 2))
        if ((width <= radius x 2) && (height <= radius * 2))
        

        如果发生上述任何一种情况,您将无法获得正确绘制的矩形

        我的解决方案动态处理任何半径和任何宽度和高度,应该是默认答案

        function roundRect(ctx, x, y, width, height, radius) {
                /*
                 * Draws a rounded rectangle using the current state of the canvas.
                 */
                let w = width;
                let h = height;
                let r = radius;
                ctx.stroke()
                ctx.fill()
                ctx.beginPath();
                // Configure the roundedness of the rectangles corners
                if ((w >= r * 2) && (h >= r * 2)) {
                    // Handles width and height larger than diameter
                    // Keep radius fixed
                    ctx.moveTo(x + r, y);  // tr start
                    ctx.lineTo(x + w - r, y);  // tr
                    ctx.quadraticCurveTo(x + w, y, x + w, y + r);  //tr
                    ctx.lineTo(x + w, y + h - r);  // br
                    ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);  // br
                    ctx.lineTo(x + r, y + h);  // bl
                    ctx.quadraticCurveTo(x, y + h, x, y + h - r);  // bl
                    ctx.lineTo(x, y + r);  // tl
                    ctx.quadraticCurveTo(x, y, x + r, y);  // tl
                } else if ((w < r * 2) && (h > r * 2)) {
                    // Handles width lower than diameter
                    // Radius must dynamically change as half of width
                    r = w / 2;
                    ctx.moveTo(x + w, y + h - r);  // br start
                    ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);  // br curve
                    ctx.quadraticCurveTo(x, y + h, x, y + h - r)  // bl curve
                    ctx.lineTo(x, y + r);  // line
                    ctx.quadraticCurveTo(x, y, x + r, y);  // tl
                    ctx.quadraticCurveTo(x + w, y, x + w, y + r);  // tl
                    ctx.lineTo(x + w, y + h - r);  // line
                } else if ((w > r * 2) && (h < r * 2)) {
                    // Handles height lower than diameter
                    // Radius must dynamically change as half of height
                    r = h / 2;
                    ctx.moveTo(x + w - r, y + h);  // br start
                    ctx.quadraticCurveTo(x + w, y + h, x + w, y + r);  // br curve
                    ctx.quadraticCurveTo(x + w, y, x + w - r, y);  // tr curve
                    ctx.lineTo(x + r, y);  // line between tr tl
                    ctx.quadraticCurveTo(x, y, x, y + r);  // tl curve
                    ctx.quadraticCurveTo(x, y + h, x + r, y + h);  // bl curve
                } else if ((w < 2 * r) && (h < 2 * r)) {
                    // Handles width and height lower than diameter
                    ctx.moveTo(x + w / 2, y + h);
                    ctx.quadraticCurveTo(x + w, y + h, x + w, y + h / 2);  // bl curve
                    ctx.quadraticCurveTo(x + w, y, x + w / 2, y);  // tr curve
                    ctx.quadraticCurveTo(x, y, x, y + h / 2);  // tl curve
                    ctx.quadraticCurveTo(x, y + h, x + w / 2, y + h);  // bl curve
        
                }
                ctx.closePath();
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-13
          • 2011-08-02
          相关资源
          最近更新 更多