gpt4 book ai didi

javascript - 以与 css 边框相同的方式在 Canvas 上绘制虚线和点线矩形 : draw 4 same edges

转载 作者:行者123 更新时间:2023-11-30 20:59:09 25 4
gpt4 key购买 nike

我的用例是模仿 css 边框渲染。有可能吗,使用 CanvasRenderingContext2D::rect使用 CanvasRenderingContext2D::setLineDash 的方法模拟与 css 渲染器相同的边框绘制,如 border: 5px dashed red。考虑这个例子:

let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
ctx.lineWidth = 5
ctx.strokeStyle = 'red'
ctx.lineCap = 'square'
ctx.setLineDash([10, 10]);
ctx.beginPath();
ctx.moveTo(2.5,2.5);
ctx.rect(2.5, 2.5, 195, 65);
ctx.stroke();
div {
border: 5px dashed red;
width: 200px;
height: 70px;
box-sizing: border-box;
margin-bottom: 5px;
}

canvas {
display: block;
width: 200px;
height: 70px;
}
<div></div>
<canvas width=200 height=70></canvas>

您可能会注意到问题出在边缘。

Not pretty line joins on edges

我试图修改间隙和破折号的大小,但似乎不可能获得与 css 示例中相同的行为:边缘上的线条比侧面上的线条大。作为一种解决方法,我可以想象用一条线绘制每一面,但我想使用 rect 方法一次绘制。

提前谢谢你。

最佳答案

CSS border-style: dashed 算法不受规范约束,因此不可能在 Canvas API 中呈现完全相同的效果。

然后,你必须知道甚至 CSS 也是逐行渲染的:border 是所有 border-top-XXX 的简写, border-right-XXX, border-bottom-XXX, border-left-XXX.
这就是为什么它会这样:每个边框都有独立于其他边框的划线集。

无论如何,如果你想用 Canvas API 来做,最简单的解决方案是做同样的事情,使用四行,并分别设置它们的短划线。

这是对破折号进行归一化以使它们始终在边缘开始和结束的粗略尝试:

var ctx = c.getContext('2d');
ctx.lineCap = 'square';

// returns a normalized dashArray per segment
// This in no way does the same as any browser's implementation,
// this is just a lazy way to always get dashes start and end at edges
function getLineDash(x1, y1, x2, y2) {
var length = Math.hypot((x2 - x1), (y2 - y1));
var dash_length = length / 8;
var nb_of_dashes = length / dash_length;
var dash_gap = (dash_length * 0.66);
dash_length -= dash_gap * 0.33;
return [dash_length, dash_gap];
}

function draw() {
ctx.lineWidth = lineWidth_.value;
ctx.clearRect(0, 0, c.width, c.height);

var points = [
[x1_.value, y1_.value],
[x2_.value, y2_.value],
[x3_.value, y3_.value],
[x4_.value, y4_.value]
];

points.forEach(function(pt, i) {
var next = points[(i + 1) % points.length];
ctx.beginPath();
ctx.moveTo(pt[0], pt[1]);
ctx.lineTo(next[0], next[1]);
ctx.setLineDash(getLineDash(pt[0], pt[1], next[0], next[1]));
ctx.stroke();
});

}

draw();
document.oninput = function(e) {
if (e.target.parentNode.parentNode === inputs_) {
draw();
}
}
label {
display: inline-block;
}

input {
max-width: 50px;
}
<div id="inputs_">
<label>x1<input type="number" id="x1_" value="10"></label>
<label>y1<input type="number" id="y1_" value="25"></label>
<label>x2<input type="number" id="x2_" value="350"></label>
<label>y2<input type="number" id="y2_" value="25"></label>
<label>x3<input type="number" id="x3_" value="350"></label>
<label>y3<input type="number" id="y3_" value="225"></label>
<label>x4<input type="number" id="x4_" value="10"></label>
<label>y4<input type="number" id="y4_" value="225"></label>
<label>lineWidth<input type="number" id="lineWidth_" value="3"></label>

</div>
<canvas id="c" width="400" height="400"></canvas>


现在,如果您只想使用 XXXRect,您还可以创建一个包含所有破折号的巨大破折号数组...

var ctx = c.getContext('2d');
ctx.lineCap = 'square';

function getRectDashes(width, height) {
var w_array = getLineDashes(width, 0, 0, 0);
var h_array = getLineDashes(0, height, 0, 0);
dashArray = [].concat.apply([], [w_array, 0, h_array, 0, w_array, 0, h_array]);
return dashArray;
}
// same as previous snippet except that it does return all the segment's dashes
function getLineDashes(x1, y1, x2, y2) {
var length = Math.hypot((x2 - x1), (y2 - y1));
var dash_length = length / 8;
var nb_of_dashes = length / dash_length;

var dash_gap = dash_length * 0.66666;
dash_length -= dash_gap * 0.3333;

var total_length = 0;
var dasharray = [];
var next;
while (total_length < length) {
next = dasharray.length % 2 ? dash_gap : dash_length;
total_length += next;
dasharray.push(next);
}
return dasharray;
}

function draw() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.lineWidth = lineWidth_.value;
var w = width_.value,
h = height_.value;
ctx.setLineDash(getRectDashes(w, h));
ctx.strokeRect(20, 20, w, h);
}
draw();
document.oninput = function(e) {
if (e.target.parentNode.parentNode === inputs_)
draw();
};
label {
display: inline-block;
}

input {
max-width: 50px;
}
<div id="inputs_">
<label>width<input type="number" id="width_" value="200"></label>
<label>height<input type="number" id="height_" value="225"></label>
<label>lineWidth<input type="number" id="lineWidth_" value="3"></label>
</div>
<canvas id="c" width="400" height="400"></canvas>

关于javascript - 以与 css 边框相同的方式在 Canvas 上绘制虚线和点线矩形 : draw 4 same edges,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47296842/

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