javascript - 根据线条( Canvas )的位置添加文本标签

标签 javascript html canvas html5-canvas

美好的一天 Stackoverflowers,

我正在使用 Canvas 创建平面图。我有点卡在在行旁边添加标签的部分。它应该水平和垂直居中并放置在线条之外。

这就是我想要实现的目标。

enter image description here

该平面图由 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/

相关文章:

javascript - while (i --> 0) 是什么意思?

javascript - 使用 Jquery 隐藏一些文本

css - 移动网站链接变为静态

javascript - 添加另一个形状时,动力学 JS 形状阴影变得更加明显

c# - WPF: Canvas 中的中心文本 block

Android 自定义 View 和 Canvas 大小

javascript - 如何在没有 SSL/TLS 的情况下实现基于表单的身份验证

javascript - 悬停个人资料图片后带箭头的工具提示框

javascript - 我怎样才能在 css-in-js Emotion 中通过自动生成的类名搜索代码?

html - 在基本 html/css 站点中正确对齐 div 元素