我试图模仿画布上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;
答案 0 :(得分:0)
似乎浏览器会以某种方式纠正半径,如果它超出了形状。我已经创建了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();
&#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;