在两点之间寻找中间点

9
我有一堆 HTML 元素,想要通过 Canvas 用线连接它们。以下是我试图实现的示意图:

Mockup

目前,我只有线条,没有文字。我想在每条线的中间放置文字,但由于它们是对角线,我不确定该怎么做。

当前代码:

// 'connectors' is an array of points corresponding to 
// the middle of each big blue buttons' x-value 

ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<connectors.length;i++){
    var wpoint = connectors[i];
    var pos1   = {w: wpoint, h: 0};
    var pos2   = {w: canvas.width / 2, h: canvas.height};
    ctx.beginPath();
    ctx.moveTo(pos1.w,pos1.h);
    ctx.lineTo(pos2.w,pos2.h);
    ctx.stroke();

    // Write Text Halfway 
    ctx.fillStyle = "blue";
    ctx.font = "bold 16px Arial";
    ctx.fillText("2702", 100, canvas.height / 2); 
    // No idea what to put as the x value here

}

什么是实现这个的最佳方法?可能是画一半的线,写文本,然后再画剩下的线吗?
编辑:也许更好的标题/问题应该是:如何在HTML Canvas中找到两个任意点之间的中点?我想在那里绘制文本。

1
只是好奇,因为这些线是倾斜的,文字不会全部出现在同一水平线上,因为倾斜线的中间部分高度将与最直线的中间部分高度不同。 - johnny 5
1
@johnny5 很好的观点 - 我认为解决方案是找到正确的 x-value,并将 y-value 绘制到画布高度的一半。 - JVG
1
可能更容易的方法是画出线条,找到每条线上相同y轴上的一个点,然后擦除部分线条并在其上绘制文本。 - johnny 5
我的意思是这些行是否总是成比例的,还是可能会改变? - johnny 5
@johnny5 目前它是静态的,但如果我将其响应式设计,我希望只需使用 canvas.height 计算高度。 - JVG
显示剩余6条评论
1个回答

11

输入图像描述

具体步骤:

  • 计算线段的中点
  • 绘制线段
  • 在线段中点处擦除线条
  • 告诉画布以指定的[x,y]为中心水平和垂直地对任何绘制的文本进行居中处理
  • 在线段中点处绘制文本

这是代码注释和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var line={x0:20,y0:20,x1:150,y1:150};

textAtMidLine(line,'2702','verdana',14)

function textAtMidLine(line,text,fontface,fontsize){

  // save the unmodified context state
  ctx.save();

  // calc line's midpoint
  var midX=line.x0+(line.x1-line.x0)*0.50;
  var midY=line.y0+(line.y1-line.y0)*0.50;

  // calc width of text
  ctx.font=fontsize+'px '+fontface;
  var textwidth=ctx.measureText(text).width;

  // draw the line
  ctx.beginPath();
  ctx.moveTo(line.x0,line.y0);
  ctx.lineTo(line.x1,line.y1);
  ctx.lineWidth=2;
  ctx.strokeStyle='lightgray';
  ctx.stroke();

  // clear the line at the midpoint
  ctx.globalCompositeOperation='destination-out'; // "erases" 
  ctx.fillRect(midX-textwidth/2,midY-fontsize/2,textwidth,fontsize*1.286);
  ctx.globalCompositeOperation='source-over';  // reset to default

  // tell canvas to horizontally & vertically center text around an [x,y]
  ctx.textAlign='center';
  ctx.textBaseline='middle'

  // draw text at the midpoint
  ctx.fillText(text,midX,midY);

  // restore the unmodified context state
  ctx.restore();

}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>


这会找到线的中点吗?还是说?我认为操作员希望它计算横跨所有线的中间线的中点。 - johnny 5
@johnny5 它会找到每条指定线的中点。如果所有线都具有相同的 y0y1(如问题示例图像中所示),则代码将无需修改即可正常工作。是的,如果您想分配一个中间的 y,那么您可以将所有绘图夹紧到该中间 y。如果您希望该中间 y 位于垂直区域的中点,则可以使用相同的 midXmidY 计算针对该垂直区域(使用 x0=0 和 x1=0 使定义线垂直)。 - markE
1
可以用了!你可能会认为在Javascript中,这么简单的东西肯定有一个简单的方法,但不幸的是并没有。 - JVG
如果您将从“P1”到“P2”的向量归一化,得到“nx”、“ny”和线的长度,则文本需要一个间隙等于“gap = Math.sqrt(textWidth * textWidth + textHeight * textHeight)”,这是三角形斜边上的文本。然后,您从“P1.x”、“P1.y”到“P1.x + nx *(length / 2 - gap / 2)”和“P1.y + ny *(length / 2 - gap / 2)”绘制两条线,然后从“P1.x + nx *(length / 2 + gap / 2)”和“P1.y + ny *(length / 2 + gap / 2)”到“P2.x”、“P2.y”。这样可以避免清除文本区域,如果您有详细的背景,则这将会很棘手。 - Blindman67
@Blindman67。当然可以——有很多解决方案。您还可以在单独的画布上分阶段执行 line + erase + fillText,然后将分层画布的 drawImage 绘制到主画布上。 - markE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接