美好的一天 Stackoverflowers,
我正在使用 Canvas 创建平面图。我有点卡在在行旁边添加标签的部分。它应该水平和垂直居中并放置在线条之外。
这就是我想要实现的目标。
该平面图由 4 条线组成。我希望根据行数为每行创建一个标签。
this.floorplan.getWalls().forEach((wall) => {
this.drawWall(wall);
});
private drawWall(wall: Wall) {
var startX = wall.startX();
var startY = wall.startY();
var endX = wall.endX();
var endY = wall.endY();
this.context.beginPath();
this.context.moveTo(startX, startY);
this.context.lineTo(endX, endY);
this.context.lineWidth = width;
this.context.strokeStyle = color;
this.context.stroke();
// add labels here
var label = wall.getLabel();
}
希望有人能够照亮。
谢谢。
最佳答案
为了确保您知道线条的哪一侧是外侧还是内侧,您必须统一线条方向,以便它们始终沿顺时针方向移动。
这样就很容易找到线的哪一边在外面了。如果站在队伍的起点并沿着队伍看,外面就是你的左边。
该示例展示了如何将已转换(沿线)未转换文本和沿线文本(确保其始终向上)的文本渲染到该线的左侧
将未转换的文本移离线条,使文本中心位于线条中心左侧 90 度,并移动以使 Angular 尽可能靠近。我从行中心到文本添加了一条细线,以显示文本中心与行对齐的位置。
requestAnimationFrame(mainLoop);
const w = canvas.width;
const h= canvas.height;
const ctx = canvas.getContext("2d");
function drawLabledLine(label, x, y, x1, y1, fontSize = 12) {
ctx.font = fontSize + "px arial";
ctx.lineWidth = 1;
ctx.fillStyle = ctx.strokeStyle = "black";
ctx.textAlign = "center";
ctx.textBaseline = "middle"; // Rather than mess around with this
// I use the same alignment and just change the
// position to put the text where it is needed
// normalize line
var nx = x1 - x;
var ny = y1 - y;
const dist = (nx * nx + ny * ny) ** 0.5;
nx /= dist;
ny /= dist;
// set the transform
ctx.setTransform(nx, ny, -ny, nx, x, y);
// The transformed is now aligned to the line. Along the line is X and
// 90 deg clockwise is right of the line
ctx.beginPath();
ctx.lineTo(0, 0);
ctx.lineTo(dist, 0);
ctx.lineTo(dist - 4, -4);
ctx.stroke();
var offset = -fontSize * 0.6;
var distAlong = dist / 2; /// where to put the line
// Use the normal's of the line to workout how
// to render the text so it is always readable
if (nx < 0) {
ctx.setTransform(-nx, -ny, ny, -nx, x, y);
offset = -offset;
distAlong = - distAlong;
}
ctx.fillText(label, distAlong, offset);
}
function drawLabledLineTextHor(label, x, y, x1, y1, fontSize = 12) {
ctx.font = fontSize + "px arial";
ctx.lineWidth = 1;
ctx.fillStyle = ctx.strokeStyle = "black";
ctx.textAlign = "center";
ctx.textBaseline = "middle"; // Rather than mess around with this
// I use the same alignment and just change the
// position to put the text where it is needed
// normalize line
var nx = x1 - x;
var ny = y1 - y;
const dist = (nx * nx + ny * ny) ** 0.5;
nx /= dist;
ny /= dist;
// set the transform
ctx.setTransform(nx, ny, -ny, nx, x, y);
// The transformed is now aligned to the line. Along the line is X and
// 90 deg clockwise is right of the line
ctx.beginPath();
ctx.lineTo(0, 0);
ctx.lineTo(dist, 0);
ctx.lineTo(dist - 4, -4);
ctx.stroke();
// need the text width so that the text can be moved away from the line
const textW = ctx.measureText(label).width;
// Offset a little more than half the font size to stop text from
// touching (top and (bottom if hanging char eg `jgq`))
var offset = -fontSize * 0.575 - (textW / 2 * -ny) * (-ny < 0 ? -1 : 1);
var distAlong = dist / 2; // where along the line to move out from (left)
// to place the text
// Show center line
ctx.lineWidth = 0.25;
ctx.beginPath();
ctx.lineTo(dist / 2, 5);
ctx.lineTo(dist / 2, offset + fontSize / 2 );
ctx.stroke();
// set transform origin to center of line
ctx.setTransform(
1, 0, // x Axis
0, 1, // y Axis
x + nx * distAlong, // origin
y + ny * distAlong,
);
// The vector -ny,nx is CW (right of the line) so the offset is negative
// to that direction as we want to move left of the line
ctx.fillText(label, -ny * offset, nx * offset);
}
const points = [
{x: -40, y: -40, tx: 0, ty: 0}, // tx,ty is tranformed pos
{x: 40, y: -40, tx: 0, ty: 0},
{x: 40, y: 40, tx: 0, ty: 0},
{x: -40, y: 40, tx: 0, ty: 0},
];
const lines = [
{txt: "A", p1: points[0], p2: points[1], method: drawLabledLine},
{txt: "B", p1: points[1], p2: points[2], method: drawLabledLineTextHor},
{txt: "Line C", p1: points[2], p2: points[3], method: drawLabledLine},
{txt: "Line D", p1: points[3], p2: points[0], method: drawLabledLineTextHor},
]
function mainLoop(time) {
ctx.setTransform(1,0,0,1,0,0); // default transform
ctx.clearRect(0,0,w,h);
var ang = time / 1000;
// rotate and move to center of canvas all points
const xAx = Math.cos(ang);
const xAy = Math.sin(ang);
for (const p of points) {
p.tx = p.x * xAx - p.y * xAy + w / 2;
p.ty = p.x * xAy + p.y * xAx + h / 2;
}
// render the lines
for(const l of lines) {
l.method(l.txt, l.p1.tx, l.p1.ty, l.p2.tx, l.p2.ty);
}
requestAnimationFrame(mainLoop);
}
<canvas id="canvas" width="200" height="200"></canvas>
关于javascript - 根据线条( Canvas )的位置添加文本标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58689034/