【问题标题】:Connect Line Between 2 Elements - Javascript连接两个元素之间的线 - Javascript
【发布时间】:2020-02-23 16:30:54
【问题描述】:

我目前正在研究一种使用 Javascript 创建单线图的方法。我目前可以使用以下函数连接两个 html 元素:

adjustLine (from, to, line) {
  var fT = from.offsetTop  + from.offsetHeight/2;
  var tT = to.offsetTop      + to.offsetHeight/2;
  var fL = from.offsetLeft + from.offsetWidth/2;
  var tL = to.offsetLeft     + to.offsetWidth/2;

  var CA   = Math.abs(tT - fT);
  var CO   = Math.abs(tL - fL);
  var H    = Math.sqrt(CA*CA + CO*CO);
  var ANG  = 180 / Math.PI * Math.acos( CA/H );

  if(tT > fT){
      var top  = (tT-fT)/2 + fT;
  }else{
      var top  = (fT-tT)/2 + tT;
  }
  if(tL > fL){
      var left = (tL-fL)/2 + fL;
  }else{
      var left = (fL-tL)/2 + tL;
  }

  if(( fT < tT && fL < tL) || ( tT < fT && tL < fL) || (fT > tT && fL > tL) || (tT > fT && tL > fL)){
    ANG *= -1;
  }
  top-= H/2;

  line.style["-webkit-transform"] = 'rotate('+ ANG +'deg)';
  line.style["-moz-transform"] = 'rotate('+ ANG +'deg)';
  line.style["-ms-transform"] = 'rotate('+ ANG +'deg)';
  line.style["-o-transform"] = 'rotate('+ ANG +'deg)';
  line.style["-transform"] = 'rotate('+ ANG +'deg)';
  line.style.top    = top+'px';
  line.style.left   = left+'px';
  line.style.height = H + 'px';
}

该函数有3个参数:

  • 1) 第一个html元素
  • 2) 第二个html元素
  • 3) 连接元素的线。

这工作正常并输出以下结果:

但是,连接 html 元素的线是一条直线,我希望图表的流程更自然,如下所示:

对我该如何做这件事有什么建议吗?非常感谢任何帮助!

编辑

我正在使用 html2canvas 创建生成输出的图像。这是我的代码:

var myDiv = document.getElementById('content');

html2canvas(myDiv, {useCORS: true, allowTaint : true}).then(function (canvas) {

            var imgData = canvas.toDataURL("image/png", 1.0);
            var imgData2 = canvas2.toDataURL("image/png", 1.0);

            var pdf = new jsPDF('l', 'pt', [HTML_Width, HTML_Height]);
            pdf.internal.scaleFactor = 30;
            pdf.addImage(imgData, 'PNG', 0, 0, HTML_Width, HTML_Height);

            pdf.addPage();
            pdf.addImage(imgData2, 'PNG', 0, 0, HTML_Width_2, HTML_Height_2);

            pdf.save("my_file.pdf");
});

【问题讨论】:

  • 你能上传剩下的代码吗?
  • @JacekRojek 当然,这是 CodePen 中的代码:codepen.io/MejorCodigo/pen/YzXpmYY
  • 这看起来有点矫枉过正,但我​​会这样。考虑一下曼哈顿距离:x 轴计数加倍。然后从 A 点到 B 点做 Astar。(这有利于先到顶部)。然后对于点 C 到 B,您已经绘制了画布,A 星将避免越线并应保持“旁边”。这是 5 分钟的随机想法
  • A* 实现对于这个来说是多余的,但肯定会起作用。单个对象的行数是否有限制?这个系统需要多动态?用户交互可以移动元素,实时更新线条吗?连接元素的数量是预先知道的还是动态添加的?
  • @Phelaxz 嗨,每个对象都使用 json 文件动态添加到 &lt;div&gt;... 我知道应该打印多少元素以及每个元素的父/子,用户也应该不要移动元素,因此不需要实时更新线条,理想情况下每个连接应该有 2 条线。

标签: javascript html diagram


【解决方案1】:

所以这里是我使用 SVG 的解决方案!

const xmlns   = 'http://www.w3.org/2000/svg'
  ,   svgLink = 'http://www.w3.org/1999/xlink'
  ,   elmSVG  = document.getElementById('elmSVG')
  ,   bot_inversor  = 80
  ,   top_fotovolta = 300
  ;
for (let i=0;i<4;i++)
  {
  let x = 10 + (i*60)
    , fotovolta = document.createElementNS(xmlns, 'use');

  fotovolta.setAttributeNS(svgLink, 'xlink:href', '#fotovoltaico');

  fotovolta.setAttributeNS(null, 'x', x);
  fotovolta.setAttributeNS(null, 'y', top_fotovolta);
  fotovolta.setAttributeNS(null, 'width', '50');
  fotovolta.setAttributeNS(null, 'height', '70'); 

  elmSVG.appendChild(fotovolta);

  adjustLines(i);
  }
function adjustLines(item)
  {
  let left = (item<2)    // the hard part...  
    , b1 = 25 + (item *60) + (left?0:20)
    , b2 = b1 + (left?20:-20)
    , a1 = 105 + (item *10) + (left?0:10)
    , a2 = a1 + (left?5:-5)
    , l1 = 50 + (left?item:3-item) *30
    , l2 = l1 + 10
    ;
  let jLine1 = document.createElementNS(xmlns, 'polyline');
  jLine1.setAttributeNS(null, 'points', `${b1},${top_fotovolta} ${b1},${bot_inversor+l1} ${a1},${bot_inversor+l1} ${a1},${bot_inversor}`);
  elmSVG.appendChild(jLine1);   

  let jLine2 = document.createElementNS(xmlns, 'polyline');
  jLine2.setAttributeNS(null, 'points', `${b2},${top_fotovolta} ${b2},${bot_inversor+l2} ${a2},${bot_inversor+l2} ${a2},${bot_inversor}`);
  elmSVG.appendChild(jLine2);   
  }
#elmSVG {
  width: 250px;
  height: 380px;
  background-color: #b4f0f0;
  margin: 1em;
}
#elmSVG * {
  fill:none;
  stroke:#2f363d;
  stroke-width:2px;
}
.curveSVG {
  stroke-linecap:round;
}
<h2>Connecting Lines</h2>

<svg id="elmSVG" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 380">
  <defs>
    <symbol id="inversor" viewBox="0 0 70 70">
      <rect x="0" y="0" width="70" height="70" />
      <line x1="70" x2="0" y1="0" y2="70"  />
      <line x1="10" x2="30" y1="15" y2="15" />
      <line x1="10" x2="30" y1="20" y2="20"  />
      <path d="M 40,55 Q 45,45 50,55 T 60,55" class="curveSVG" />
    </symbol>
    <symbol id="fotovoltaico"  viewBox="0 0 50 70">
      <rect x="0" y="0" width="50" height="70" />
      <line x1="0" x2="25" y1="0" y2="20"  />
      <line x1="50" x2="25" y1="0" y2="20"  />
    </symbol>
  </defs>

  <use xlink:href="#inversor" x="90"  y="10" width="70" height="70" />
</svg>

【讨论】:

  • 嗨,这个答案看起来很合适,但是,我还没有时间开始实施它,我会在接下来的几天内尝试实施它,如果有任何问题,我会回复你向上。非常感谢! :)
  • @BrianMoreno 没问题 :-)
  • 嗨@MisterJojo,我目前正在努力实现这一点,到目前为止一切正常。唯一的问题是我正在使用 html2canvas 创建图像,但 SVG 不会显示在输出中。有什么推荐吗?我已经编辑了这个问题,让您了解我正在尝试做什么。
  • @BrianMoreno 我对画布一直不太满意,但我会看看我能做什么
  • 感谢您的帮助! :D
【解决方案2】:

&lt;canvas&gt; 的其他解决方案

const eCanvas = document.getElementById('elmCanvas')
  ,   cCanvas = eCanvas.getContext('2d')
  ,   bot_inversor  = 80
  ,   top_fotovolta = 300
  ;

// set background color
cCanvas.fillStyle = 'rgb(178, 240, 240)'
cCanvas.fillRect(0, 0, eCanvas.width, eCanvas.height )

Draw_Inversor( cCanvas, (eCanvas.width/2 - 70/2), 10)

for (let i=0;i<4;i++)
  {
  Draw_Fotovoltaico( cCanvas, 10+(i*60), top_fotovolta );
  Draw_connectsLines( cCanvas, i, 4, (eCanvas.width/2), (10+(i*60)+25) );
  }

function Draw_Inversor( ctx, x, y )
  {
  ctx.beginPath();
  ctx.moveTo(x+70, y);
  ctx.lineTo(x, y+70);
  ctx.lineTo(x, y);
  ctx.lineTo(x+70, y);
  ctx.lineTo(x+70, y+70);
  ctx.lineTo(x, y+70);
  ctx.moveTo(x+10, y+15);
  ctx.lineTo(x+30, y+15);
  ctx.moveTo(x+10, y+20);
  ctx.lineTo(x+30, y+20);
  ctx.moveTo(x+50, y+55);
  ctx.arc(x+45, y+55, 5, 0, Math.PI, true);
  ctx.moveTo(x+60, y+55);
  ctx.arc(x+55, y+55, 5, 0, Math.PI, false);
  ctx.stroke();
  }
function Draw_Fotovoltaico( ctx, x, y )
  {
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo(x+25, y+20);
  ctx.lineTo(x+50, y);
  ctx.lineTo(x, y);
  ctx.lineTo(x, y+70);
  ctx.lineTo(x+50, y+70);
  ctx.lineTo(x+50, y);
  ctx.stroke();
  }
function Draw_connectsLines( ctx, no, maxOcc, topCenter, botCenter )
  {
  let mid   = maxOcc/2
    , left  = no < mid
    , decal = left ? no :(maxOcc/2)-no+1 
    , topL1 = 50+ (decal *30)
    , topL2 = topL1 +10
    , topX1 = topCenter + (left? -(mid-decal)*10 : +(mid-decal)*10 )
    , topX2 = topX1 +(left?+5:-5)
    , botX1 = botCenter + (left?-10:+10)
    , botX2 = botCenter + (left?+10:-10) 
    ;
  ctx.beginPath();
  ctx.moveTo(topX1, bot_inversor);
  ctx.lineTo(topX1, bot_inversor +topL1 );
  ctx.lineTo(botX1, bot_inversor +topL1 );
  ctx.lineTo(botX1, top_fotovolta );
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(topX2, bot_inversor);
  ctx.lineTo(topX2, bot_inversor +topL2 );
  ctx.lineTo(botX2, bot_inversor +topL2 );
  ctx.lineTo(botX2, top_fotovolta );
  ctx.stroke();
  }
#elmCanvas {
  margin: 1em;
}
&lt;canvas id="elmCanvas" width="250" height="400"&gt;&lt;/canvas&gt;

【讨论】:

    猜你喜欢
    • 2011-09-10
    • 2022-10-15
    • 1970-01-01
    • 2016-06-14
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 2015-05-06
    相关资源
    最近更新 更多