Dom*_*ino 1 html javascript canvas
我有以下代码来绘制形状(主要用于矩形),但 HTML5 绘图函数似乎绘制边框,其厚度以指定的线条为中心。我想在形状表面之外有一个边框,但我不知所措。

Path.prototype.trace = function(elem, closePath) {
sd.context.beginPath();
sd.context.moveTo(this.getStretchedX(0, elem.width), this.getStretchedY(0, elem.height));
sd.context.lineCap = "square";
for(var i=1; i<this.points.length; ++i) {
sd.context.lineTo(this.getStretchedX(i, elem.width), this.getStretchedY(i, elem.height));
}
if(closePath) {
sd.context.lineTo(this.getStretchedX(0, elem.width), this.getStretchedY(0, elem.height));
}
}
Run Code Online (Sandbox Code Playgroud)
一旦形状应用于设置的元素宽度、高度和偏移位置,getStretchedX 和 getStretchedY 返回第 n 个顶点的坐标。
感谢 Ken Fyrstenberg 的回答,我已经让它适用于矩形,但遗憾的是这个解决方案不适用于其他形状。

在这里,我画了两个“宽”边框,一个在每个位置减去一半的线宽,另一个添加。它不起作用(如预期),因为它只会在一种情况下将粗线放在上方和左侧,在另一种情况下将粗线放在下方和右侧 - 而不是形状“外部”。您还可以看到斜坡周围有一个白色区域。
我尝试弄清楚如何让顶点手动绘制粗边框的路径(使用fill()而不是stroke())。

但事实证明我仍然遇到同样的问题:如何以编程方式确定边缘是内部还是外部。这需要一些三角学和繁重的算法。对于我现在的工作目的来说,这太麻烦了。我想用它来绘制建筑物的地图。房间墙壁需要绘制在给定尺寸之外,但我现在将坚持使用独立的倾斜墙壁。
小智 5
您可以通过画两条线来解决这个问题:
要收缩,请将 x 和 y 添加 50%,从宽度和高度中减去线宽(或 2x 50%)。

var ctx = document.querySelector("canvas").getContext("2d");
var lineWidth = 20;
var lw50 = lineWidth * 0.5;
// outer line
ctx.lineWidth = lineWidth; // intended line width
ctx.strokeStyle = "#975"; // color for main line
ctx.strokeRect(40, 40, 100, 100); // full line
// inner line
ctx.lineWidth = 2; // inner line width
ctx.strokeStyle = "#000"; // color for inner line
ctx.strokeRect(40 + lw50, 40 + lw50, 100 - lineWidth, 100 - lineWidth);Run Code Online (Sandbox Code Playgroud)
<canvas></canvas>Run Code Online (Sandbox Code Playgroud)

对于更复杂的形状,您将必须手动计算路径。这有点复杂,而且对于 SO 来说可能太宽泛了。您必须考虑诸如切线、弯曲角度、交叉点等因素。
“作弊”的一种方法是:
下面的值offset将决定内线的粗细,而 则directions决定分辨率。
var ctx = document.querySelector("canvas").getContext("2d");
var lineWidth = 20;
var offset = 0.5; // line "thickness"
var directions = 8; // increase to increase details
var angleStep = 2 * Math.PI / 8;
// shape
ctx.lineWidth = lineWidth; // intended line width
ctx.strokeStyle = "#000"; // color for inner line
ctx.moveTo(50, 100); // some random shape
ctx.lineTo(100, 20);
ctx.lineTo(200, 100);
ctx.lineTo(300, 100);
ctx.lineTo(200, 200);
ctx.lineTo(50, 100);
ctx.closePath();
ctx.stroke();
ctx.save()
ctx.clip(); // set as clipping mask
ctx.globalCompositeOperation = "destination-atop"; // draws "behind" existing drawings
for(var a = 0; a < Math.PI * 2; a += angleStep) {
ctx.setTransform(1,0,0,1, offset * Math.cos(a), offset * Math.sin(a));
ctx.drawImage(ctx.canvas, 0, 0);
}
ctx.restore(); // removes clipping, comp. mode, transforms
// set new color and redraw same path as previous
ctx.strokeStyle = "#975"; // color for inner line
ctx.stroke();Run Code Online (Sandbox Code Playgroud)
<canvas height=250></canvas>Run Code Online (Sandbox Code Playgroud)