【问题标题】:Javascript - Canvas CSS border-radius imitationJavascript - Canvas CSS 边框半径模仿
【发布时间】:2018-07-03 23:22:32
【问题描述】:

我正在尝试在画布上模仿 CSS 边框半径属性的行为。我做了一些有效的事情,但是浏览器正在处理一些缺失的调整,我无法在画布上重现(参见下面的图片链接作为示例)

但是,当边界离开时,我正在努力适应边界 形状。

这里是一个例子,让我们取一个 100px (Width) X 100px (Height) 的 HTML 形状,然后应用以下半径:border-radius: 100px 52px 1px 1px;

然后用相同的参数在画布中绘制这个形状。

然后我得到了这个(红色形状 = 画布形状,绿色形状 = 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:对不起我的英语不好

(参见下面的 sn-p)

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

【问题讨论】:

    标签: javascript html css canvas border


    【解决方案1】:

    如果半径超出形状,浏览器似乎会以某种方式纠正半径。我创建了 correctRadius 函数来做这样的事情。当然,结果并不完全相同,但至少形状没有任何间隙。

    // 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();
    <!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>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-11
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多