gpt4 book ai didi

javascript - 使用 canvas API 复制 CSS border-radius

转载 作者:太空宇宙 更新时间:2023-11-04 07:40:36 26 4
gpt4 key购买 nike

我想将以下 CSS 形状复制到 Canvas 中。它具有以下属性:

width: 325px;
height: 200px;
background: green;
border-radius: 60px 110px / 100px 80px;

the rendered shape

我已经有了制作圆 Angular 矩形的功能,但没有那么变形......参见相关的堆栈帖子:https://stackoverflow.com/a/48491607/9264003

我尝试了 bezierCurveTo()arcTo() 函数,但没有成功。

我认为我们必须为每个 Angular 计算一个椭圆:左上角、右上角、右下角、左下角,但我完全不确定...

如果有人要重现这个形状,或者给我任何提示或公式来计算这个,那将是一个很好的开始!

最佳答案

实际上有一个ellipse 2DContext API 的方法。它的浏览器支持不是很好,但可以polyfilled .

使用这种方法简化了很多操作,因为我们可以用它在每个 Angular 上绘制四分之一的椭圆,但它并不能解决整个问题...

您仍然需要解析 CSSString 才能知道如何绘制椭圆,为此,我使用了一个简单的虚拟 div + getComputedStyle。
根据规范,如果两个 border-XXX-XXX-radius 计算值之一是 0px,那么我们应该画一个方 Angular 。
您还必须考虑 overlapping corners rule ,为此,我借用了 niklasvh 的 html2canvas implementation CSSWG 算法。

这是我尝试为 Canvas 创建这样一个 Border-radius 函数,但我没有进行广泛的测试,所以它可能会失败。

另请注意,它只接受速记 border-radius CSS 语法,但如果您还想传递普通语法,则很容易调整。

var w = c.width = 325,
h = c.height = 200,
ctx = c.getContext('2d');
ctx.fillStyle = 'blue';

inp.onchange = function() {
blurb.style.borderRadius = this.value;
ctx.clearRect(0, 0, w, h);
drawBorderRadius(ctx, this.value, w, h);
ctx.fill();
};
inp.onchange();

function drawBorderRadius(ctx, CSSRule, w, h) {
var radii = parseBorderRadiusRules(CSSRule);
fixOverlappingCorners(radii);

ctx.beginPath();
var x, y, h_, v_;

// top-left corner
if (hasZero(radii.topleft))
ctx.moveTo(0, 0);
else {
x = radii.topleft[0];
y = radii.topleft[1];
ctx.ellipse(x, y, x, y, 0, Math.PI, Math.PI * 1.5);
}
// top-right corner
if (hasZero(radii.topright))
ctx.lineTo(w, 0);
else {
x = radii.topright[0];
y = radii.topright[1];
ctx.ellipse(w - radii.topright[0], y, x, y, 0, -Math.PI / 2, 0);
}
//bottom-right corner
if (hasZero(radii.bottomright))
ctx.lineTo(w, h);
else {
x = radii.bottomright[0];
y = radii.bottomright[1];
ctx.ellipse(w - x, h - y, x, y, 0, 0, Math.PI / 2);
}
//bottom-left corner
if (hasZero(radii.bottomleft))
ctx.lineTo(0, h);
else {
x = radii.bottomleft[0];
y = radii.bottomleft[1];
ctx.ellipse(x, h - y, x, y, 0, Math.PI / 2, Math.PI);
}

// we need to check if one value is zero in order to draw a squared corner in such case
function hasZero(corner) {
return !Array.isArray(corner) ||
corner.indexOf(0) > -1 ||
corner.indexOf(NaN) > -1;
}
// returns a dictionnary of four corners [horizontal, vertical] values as px
function parseBorderRadiusRules(CSSstring) {
var elem = document.createElement('div');
elem.style.borderRadius = CSSstring;
elem.style.width = w;
elem.style.height = h;
elem.style.position = 'absolute';
elem.zIndex = -999;
document.body.appendChild(elem);
var computed = getComputedStyle(elem);
var radii = {
topleft: cleanRule(computed['border-top-left-radius']),
topright: cleanRule(computed['border-top-right-radius']),
bottomright: cleanRule(computed['border-bottom-right-radius']),
bottomleft: cleanRule(computed['border-bottom-left-radius'])
};
document.body.removeChild(elem);

return radii;

function cleanRule(str) {
var xy = str.split(' ');
if (xy.length === 1) {
xy[1] = xy[0];
}
return xy.map(toPx);
}

function toPx(str, index) {
var val = parseFloat(str);
if (str.indexOf('%') > -1) {
return percentageToPx(val, !index ? w : h);
}
return val;
}

function percentageToPx(percent, length) {
return length * (percent / 100);
}
}
// borrowed from https://github.com/niklasvh/html2canvas/blob/8788a9f458f538c004a626c5ce7ee24b53e48c1c/src/Bounds.js#L200
// https://github.com/niklasvh/html2canvas/blob/master/LICENSE
function fixOverlappingCorners(radii) {
var factors = [
w / (radii.topleft[0] + radii.topright[0]),
w / (radii.bottomleft[0] + radii.bottomright[0]),
h / (radii.topleft[1] + radii.bottomleft[1]),
h / (radii.topright[1] + radii.bottomright[1])
],
minFactor = Math.min.apply(null, factors);

if (minFactor <= 1) {
for (var key in radii) {
radii[key] = radii[key].map(scale);
}
}

function scale(value) {
return value * minFactor;
}
}
}
#blurb {
width: 325px;
height: 200px;
background: green;
}

input:checked+.cont>#blurb {
opacity: 0.5;
position: absolute;
background: red;
}

.cont {
position: relative;
}
<input id="inp" value="60px 110px / 100px 80px">
<label>overlap</label><input type="checkbox">
<div class="cont">
<div id="blurb"></div>
<canvas id="c"></canvas>
</div>

关于javascript - 使用 canvas API 复制 CSS border-radius,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48554006/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com