Javascript - Canvas CSS border-radius模仿

时间:2018-01-24 19:49:07

标签: javascript html css canvas border

我试图模仿画布上CSS border-radius属性的行为。我已经做了一些有效的工作,但浏览器正在处理一些缺失的改编,我无法在画布上重现(请参阅下面的图片链接作为示例)

  

然而,当他们离开时,我正在努力调整边界   形状。

以下是一个示例,让我们采用100px(宽度)X 100px(高度)的HTML形状,然后应用以下半径:border-radius: 100px 52px 1px 1px;

然后在具有相同参数的画布中绘制此形状。

然后我得到这个(RED SHAPE = Canvas形状,GREEN SHAPE = HTML形状) https://imgur.com/a/XGuca

(抱歉,由于我的声誉,我无法上传图片)

  

我使用此功能绘制形状

function (xx, yy, ww, hh, rad, fill, stroke) {
    if (typeof(rad) === "undefined") rad = 5;
    this.beginPath();
    this.moveTo(xx, yy);
    this.arcTo(xx + ww, yy, xx + ww, yy + hh, rad.tr);
    this.arcTo(xx + ww, yy + hh, xx, yy + hh, rad.br);
    this.arcTo(xx, yy + hh, xx, yy, rad.bl);
    this.arcTo(xx, yy, xx + ww, yy, rad.tl);
    if (stroke) this.stroke();  // Default to no stroke
    if (fill || typeof(fill) === "undefined") this.fill();  // Default to fill
};

以下是参数说明

xx: X axis position yy: Y axis position ww: Width hh: Height rad: {tl:0, tr:0, br:0, bl: 0} (For top-left, top-right, bottom-right, bottom-left RADIUS)

我没有得到我能做的事情才能让它发挥作用,有人可以帮助我或给我一个小费以便这样做吗?谢谢 !

PS:抱歉我的英文不好

(请参阅下面的代码段)



    // Ctx
    var ctx = document.getElementById("rounded-rect").getContext("2d");

    //Round rect func
    ctx.constructor.prototype.fillRoundedRect =
        function (xx, yy, ww, hh, rad, fill, stroke) {
            if (typeof(rad) === "undefined") rad = 5;
            this.beginPath();
            this.moveTo(xx, yy);
            this.arcTo(xx + ww, yy, xx + ww, yy + hh, rad.tr);
            this.arcTo(xx + ww, yy + hh, xx, yy + hh, rad.br);
            this.arcTo(xx, yy + hh, xx, yy, rad.bl);
            this.arcTo(xx, yy, xx + ww, yy, rad.tl);
            if (stroke) this.stroke();  // Default to no stroke
            if (fill || typeof(fill) === "undefined") this.fill();  // Default to fill
        };

    ctx.fillStyle = "red";
    ctx.strokeStyle = "#ddf";

    var copy = document.getElementById('copy');
    var tl = document.getElementById('tl');
    var tr = document.getElementById('tr');
    var bl = document.getElementById('bl');
    var br = document.getElementById('br');
    var off = document.getElementById('off');

    function test() {
        ctx.clearRect(0, 0, 600, 500);


        /* 1.Top left */
        /* 2. Top right */
        /* 3. Bottom right  */
        /* 4. Bottom left */
        var borders = [tl.value, tr.value, br.value, bl.value].join('px ') + 'px';

        copy.style.borderRadius = borders;
        var copyRad = borders.replace(/px/g, '').split(' ').map(function (a) {
            return parseInt(a)
        });

        var rad = {
            tl: copyRad[0],
            tr: copyRad[1],
            br: copyRad[2],
            bl: copyRad[3]
        };
        var o = +off.value;
        ctx.fillRoundedRect(15 + o, 15 + o, 100, 100, rad);
    }

    tl.oninput = test;
    tr.oninput = test;
    bl.oninput = test;
    br.oninput = test;
    off.oninput = test;
    test();

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        html, body {
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>


<div style="display:inline-block; position: absolute;
left:120px;top:120px; width: 100px; height: 100px; background:green;

border-radius: 10px 5px 10px 20px;" id="copy">

</div>

<canvas style="display: inline-block; position: absolute; zindex:0; left:0; top:0;" id="rounded-rect" width="600" height="500">

</canvas>


<div style="top: 300px; position:absolute; z-index: 1;">
    <label>
        Top left
        <input type="range" min="1" max="100" value="0" class="slider" id="tl"></label><br/>
    <label>
        Top right
        <input type="range" min="1" max="100" value="0" class="slider" id="tr"></label><br/>
    <label>
        Bottom left
        <input type="range" min="1" max="100" value="0" class="slider" id="bl"></label><br/>
    <label>
        Bottom right
        <input type="range" min="1" max="100" value="0" class="slider" id="br"></label><br/>
    <label>
        Offset
        <input type="range" min="1" max="200" value="0" class="slider" id="off"></label><br/>
</div>

</body>
</html>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

似乎浏览器会以某种方式纠正半径,如果它超出了形状。我已经创建了correctRadius函数来执行类似的操作。当然,结果并不完全相同,但至少形状没有任何差距。

&#13;
&#13;
// Ctx
var ctx = document.getElementById("rounded-rect").getContext("2d");

function correctRadius(r, w, h) {
  if (r.tl + r.tr > w) {
    r.tl -= (r.tl + r.tr - w) / 2;
    r.tr = w - r.tl;
  }
  if (r.bl + r.br > w) {
    r.br -= (r.br + r.bl - w) / 2;
    r.bl = w - r.br;
  }
  if (r.tl + r.bl > h) {
    r.tl -= (r.tl + r.bl - h) / 2;
    r.bl = h - r.tl;
  }
  if (r.tr + r.br > h) {
    r.tr -= (r.tr + r.br - h) / 2;
    r.br = h - r.tr;
  }
 }

//Round rect func
ctx.constructor.prototype.fillRoundedRect =
function (xx, yy, ww, hh, rad, fill, stroke) {
	correctRadius(rad, ww, hh);
	if (typeof(rad) === "undefined") rad = 5;
	this.beginPath();
	this.moveTo(xx, yy);
	this.arcTo(xx + ww, yy, xx + ww, yy + hh, rad.tr);
	this.arcTo(xx + ww, yy + hh, xx, yy + hh, rad.br);
	this.arcTo(xx, yy + hh, xx, yy, rad.bl);
	this.arcTo(xx, yy, xx + ww, yy, rad.tl);
	if (stroke) this.stroke();  // Default to no stroke
	if (fill || typeof(fill) === "undefined") this.fill();  // Default to fill
};

ctx.fillStyle = "red";
ctx.strokeStyle = "#ddf";

var copy = document.getElementById('copy');
var tl = document.getElementById('tl');
var tr = document.getElementById('tr');
var bl = document.getElementById('bl');
var br = document.getElementById('br');
var off = document.getElementById('off');

function test() {
ctx.clearRect(0, 0, 600, 500);


/* 1.Top left */
/* 2. Top right */
/* 3. Bottom right  */
/* 4. Bottom left */
var borders = [tl.value, tr.value, br.value, bl.value].join('px ') + 'px';

copy.style.borderRadius = borders;
var copyRad = borders.replace(/px/g, '').split(' ').map(function (a) {
	return parseInt(a)
});

var rad = {
	tl: copyRad[0],
	tr: copyRad[1],
	br: copyRad[2],
	bl: copyRad[3]
};
var o = +off.value;
ctx.fillRoundedRect(15 + o, 15 + o, 100, 100, rad);
}

tl.oninput = test;
tr.oninput = test;
bl.oninput = test;
br.oninput = test;
off.oninput = test;
test();
&#13;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        html, body {
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>


<div style="display:inline-block; position: absolute;
left:120px;top:120px; width: 100px; height: 100px; background:green;

border-radius: 10px 5px 10px 20px;" id="copy">

</div>

<canvas style="display: inline-block; position: absolute; zindex:0; left:0; top:0;" id="rounded-rect" width="600" height="500">

</canvas>


<div style="top: 300px; position:absolute; z-index: 1;">
    <label>
        Top left
        <input type="range" min="1" max="100" value="0" class="slider" id="tl"></label><br/>
    <label>
        Top right
        <input type="range" min="1" max="100" value="0" class="slider" id="tr"></label><br/>
    <label>
        Bottom left
        <input type="range" min="1" max="100" value="0" class="slider" id="bl"></label><br/>
    <label>
        Bottom right
        <input type="range" min="1" max="100" value="0" class="slider" id="br"></label><br/>
    <label>
        Offset
        <input type="range" min="1" max="200" value="0" class="slider" id="off"></label><br/>
</div>

</body>
</html>
&#13;
&#13;
&#13;