Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/410.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript创建SVG路径自下而上vs自上而下_Javascript_Svg - Fatal编程技术网

Javascript创建SVG路径自下而上vs自上而下

Javascript创建SVG路径自下而上vs自上而下,javascript,svg,Javascript,Svg,我有一个页面显示了一个工作职位的网格,我正在通过使用SVG+路径绘制方框之间的连接来显示从一个职位到另一个职位的进度 当我将顶部的元素连接到底部的元素时,我的代码工作正常。它将查找顶框的XY和底框的XY,并将两者连接起来 我的问题是,我想翻转这段代码,从下到上。这意味着我需要底部元素的顶部XY和顶部元素的底部XY并绘制路径 我一直在尝试翻转偏移量,基本上做了与实际相反的事情,但我认为我的数学在某个地方错了 下面是自上而下的方法。很好用。 然而,自下而上的方法是不正确的。有些地方出现了一些数学错

我有一个页面显示了一个工作职位的网格,我正在通过使用SVG+路径绘制方框之间的连接来显示从一个职位到另一个职位的进度

当我将顶部的元素连接到底部的元素时,我的代码工作正常。它将查找顶框的XY和底框的XY,并将两者连接起来

我的问题是,我想翻转这段代码,从下到上。这意味着我需要底部元素的顶部XY和顶部元素的底部XY并绘制路径

我一直在尝试翻转偏移量,基本上做了与实际相反的事情,但我认为我的数学在某个地方错了

下面是自上而下的方法。很好用。

然而,自下而上的方法是不正确的。有些地方出现了一些数学错误,计算结果导致SVG被切断。

我相信答案就在
connectElements()
函数中,因为这是确定坐标的地方

有没有关于如何更正这些计算的想法

小提琴:

JS代码:

function getOffset(el) {
  var rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.pageXOffset,
    top: rect.top + window.pageYOffset,
    width: rect.width || el.offsetWidth,
    height: rect.height || el.offsetHeight
  };
}

function drawPath(svg, path, startX, startY, endX, endY) {

  // get the path's stroke width (if one wanted to be  really precize, one could use half the stroke size)
  var style = getComputedStyle(path)
  var stroke = parseFloat(style.strokeWidth);

  // check if the svg is big enough to draw the path, if not, set heigh/width
  if (svg.getAttribute("height") < endY) svg.setAttribute("height", endY);
  if (svg.getAttribute("width") < (startX + stroke)) svg.setAttribute("width", (startX + stroke));
  if (svg.getAttribute("width") < (endX + stroke * 3)) svg.setAttribute("width", (endX + stroke * 3));

  var deltaX = (endX - startX) * 0.15;
  var deltaY = (endY - startY) * 0.15;
  // for further calculations which ever is the shortest distance
  var delta = deltaY < absolute(deltaX) ? deltaY : absolute(deltaX);

  // set sweep-flag (counter/clock-wise)
  // if start element is closer to the left edge,
  // draw the first arc counter-clockwise, and the second one clock-wise
  var arc1 = 0;
  var arc2 = 1;
  if (startX > endX) {
    arc1 = 1;
    arc2 = 0;
  }
  // draw tha pipe-like path
  // 1. move a bit down, 2. arch,  3. move a bit to the right, 4.arch, 5. move down to the end 
  path.setAttribute("d", "M" + startX + " " + startY +
    " V" + (startY + delta) +
    " A" + delta + " " + delta + " 0 0 " + arc1 + " " + (startX + delta * signum(deltaX)) + " " + (startY + 2 * delta) +
    " H" + (endX - delta * signum(deltaX)) +
    " A" + delta + " " + delta + " 0 0 " + arc2 + " " + endX + " " + (startY + 3 * delta) +
    " V" + (endY - 30));
}

function connectElements(svg, path, startElem, endElem, type, direction) {

  // Define our container
  var svgContainer = document.getElementById('svgContainer'),
    svgTop = getOffset(svgContainer).top,
    svgLeft = getOffset(svgContainer).left,
    startX,
    startY,
    endX,
    endY,
    startCoord = startElem,
    endCoord = endElem;

  console.log(svg, path, startElem, endElem, type, direction)

  /** 
   * bottomUp - This means we need the top XY of the starting box and the bottom XY of the destination box
   * topDown - This means we need the bottom XY of the starting box and the top XY of the destination box
   */
  switch (direction) {

    case 'bottomUp': // Not Working

      // Calculate path's start (x,y)  coords
      // We want the x coordinate to visually result in the element's mid point
      startX = getOffset(startCoord).left + 0.5 * getOffset(startElem).width - svgLeft; // x = left offset + 0.5*width - svg's left offset
      startY = getOffset(startCoord).top + getOffset(startElem).height - svgTop; // y = top offset + height - svg's top offset

      // Calculate path's end (x,y) coords
      endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
      endY = endCoord.getBoundingClientRect().top - svgTop;

      break;

    case 'topDown': // Working

      // If first element is lower than the second, swap!
      if (startElem.offsetTop > endElem.offsetTop) {
        var temp = startElem;
        startElem = endElem;
        endElem = temp;
      }

      // Calculate path's start (x,y)  coords
      // We want the x coordinate to visually result in the element's mid point
      startX = getOffset(startCoord).left + 0.5 * getOffset(startElem).width - svgLeft; // x = left offset + 0.5*width - svg's left offset
      startY = getOffset(startCoord).top + getOffset(startElem).height - svgTop; // y = top offset + height - svg's top offset

      // Calculate path's end (x,y) coords
      endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
      endY = endCoord.getBoundingClientRect().top - svgTop;

      break;
  }

  // Call function for drawing the path
  drawPath(svg, path, startX, startY, endX, endY, type);



}

function connectAll(direction) {

  var svg = document.getElementById('svg1'),
    path = document.getElementById('path1');

  // This is just to help with example. 
  if (direction == 'topDown') {
    var div1 = document.getElementById('box_1'),
      div2 = document.getElementById('box_20');
  } else {
    var div1 = document.getElementById('box_20'),
      div2 = document.getElementById('box_1');
  }

  // connect all the paths you want!
  connectElements(svg, path, div1, div2, 'line', direction);


}

//connectAll('topDown'); // Works fine. Path goes from the bottom of box_1 to the top of box_20
connectAll('bottomUp'); // Doesn't work. I expect path to go from top of box_20 to the bottom of box_1
函数getOffset(el){ var rect=el.getBoundingClientRect(); 返回{ 左:rect.left+window.pageXOffset, 顶部:rect.top+window.pageYOffset, 宽度:矩形宽度| | el.offsetWidth, 高度:垂直高度 }; } 函数drawPath(svg、path、startX、startY、endX、endY){ //获取路径的笔划宽度(如果想要精确,可以使用笔划大小的一半) var style=getComputedStyle(路径) var stroke=parseFloat(style.strokeWidth); //检查svg是否足够大以绘制路径,如果不够大,请设置“高/宽” if(svg.getAttribute(“height”)结束发送){ arc1=1; arc2=0; } //画一条管道状的路径 //1.向下移动一点,2.拱起,3.向右移动一点,4.拱起,5.向下移动到末端 path.setAttribute(“d”,“M”+startX+“”+startY+ “V”+(星形+三角形)+ “A”+delta+“”+delta+“0”+arc1+“”+(startX+delta*signum(deltaX))+“”+(startY+2*delta)+ “H”+(endX-delta*signum(deltaX))+ “A”+delta+“”+delta+“0 0”+arc2+“”+endX+“”+(星形+3*delta)+ “V”+(endY-30)); } 功能连接元素(svg、路径、startElem、endElem、类型、方向){ //定义我们的容器 var svgContainer=document.getElementById('svgContainer'), svgTop=getOffset(svgContainer).top, svgLeft=getOffset(svgContainer)。左, startX, 斯塔蒂, endX, 恩迪, startCoord=startElem, endCoord=endElem; 日志(svg、路径、startElem、endElem、类型、方向) /** *自底向上-这意味着我们需要起始框的顶部XY和目标框的底部XY *自上而下-这意味着我们需要起始框的底部XY和目标框的顶部XY */ 开关(方向){ 案例'bottomUp'://不起作用 //计算路径的起始(x,y)坐标 //我们希望x坐标可以直观地显示元素的中点 startX=getOffset(startcord).left+0.5*getOffset(startElem).width-svgLeft;//x=left offset+0.5*width-svg的左偏移 startY=getOffset(startcord).top+getOffset(startElem).height-svgTop;//y=top offset+height-svg的top offset //计算路径的端点(x,y)坐标 endX=endCoord.getBoundingClientRect().left+0.5*endlem.offsetWidth-svgLeft; endY=endCoord.getBoundingClientRect().top-svgTop; 打破 案例“自上而下”://正在工作 //如果第一个元素低于第二个元素,则交换! 如果(startelm.offsetTop>endElem.offsetTop){ var temp=startElem; startElem=endElem; endElem=温度; } //计算路径的起始(x,y)坐标 //我们希望x坐标可以直观地显示元素的中点 startX=getOffset(startcord).left+0.5*getOffset(startElem).width-svgLeft;//x=left offset+0.5*width-svg的左偏移 startY=getOffset(startcord).top+getOffset(startElem).height-svgTop;//y=top offset+height-svg的top offset //计算路径的端点(x,y)坐标 endX=endCoord.getBoundingClientRect().left+0.5*endlem.offsetWidth-svgLeft; endY=endCoord.getBoundingClientRect().top-svgTop; 打破 } //调用函数来绘制路径 绘图路径(svg、path、startX、startY、endX、endY、类型); } 功能连接全部(方向){ var svg=document.getElementById('svg1'), path=document.getElementById('path1'); //这只是为了举例说明。 如果(方向==“自上而下”){ var div1=document.getElementById('box_1'), div2=document.getElementById('box_20'); }否则{ var div1=document.getElementById('box_20'), div2=document.getElementById('box_1'); } //连接所有你想要的路径! 连接元素(svg、路径、div1、div2、‘线’、方向); } //connectAll(‘自上而下’);//很好。路径从方框1的底部到方框20的顶部 connectAll('bottomUp');//不起作用。我希望路径从框20的顶部到框1的底部
在我看来,你可以通过
function getOffset(el) {
  var rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.pageXOffset,
    top: rect.top + window.pageYOffset,
    width: rect.width || el.offsetWidth,
    height: rect.height || el.offsetHeight
  };
}


function drawPath(svg, path, start, end) {

  // get the path's stroke width (if one wanted to be  really precise, one could use half the stroke size)
  var style = getComputedStyle(path)
  var stroke = parseFloat(style.strokeWidth);
  var arrowHeadLength = stroke * 3;

  var deltaX = (end.x - start.x) * 0.15;
  var deltaY = (end.y - start.y) * 0.15;
  // for further calculations which ever is the shortest distance
  var delta = Math.min(Math.abs(deltaX), Math.abs(deltaY));
  var xSign = Math.sign(deltaX);
  var ySign = Math.sign(deltaY);

  // set sweep-flag (counter/clock-wise)
  // If xSign and ySign are opposite, then the first turn is clockwise
  var arc1 = (xSign !== ySign) ? 1 : 0;
  var arc2 = 1 - arc1;

  // draw tha pipe-like path
  // 1. move a bit vertically, 2. arc,  3. move a bit to the horizontally, 4.arc, 5. move vertically to the end 
  path.setAttribute("d", ["M", start.x, start.y,
                          "V", start.y + delta * ySign,
                          "A", delta, delta, 0, 0, arc1, start.x + delta * xSign, start.y + 2 * delta * ySign,
                          "H", end.x - delta * xSign,
                          "A", delta, delta, 0, 0, arc2, end.x, start.y + 3 * delta * ySign,
                          "V", end.y - arrowHeadLength * ySign].join(" "));
}


function connectElements(svg, path, startElem, endElem, type, direction) {

  // Define our container
  var svgContainer = document.getElementById('svgContainer');

  // Calculate SVG size and position
  // SVG is sized to fit between the elements vertically, start at the left edge of the leftmost
  // element and end at the right edge of the rightmost element
  var startRect = getOffset(startElem),
      endRect = getOffset(endElem),
      pathStartX = startRect.left + startRect.width / 2,
      pathEndX = endRect.left + endRect.width / 2,
      startElemBottom = startRect.top + startRect.height,
      svgTop = Math.min(startElemBottom, endRect.top + endRect.height),
      svgBottom = Math.max(startRect.top, endRect.top),
      svgLeft = Math.min(pathStartX, pathEndX),
      svgHeight = svgBottom - svgTop;

  // Position the SVG
  svg.style.left = svgLeft + 'px';
  svg.style.top = svgTop + 'px';
  svg.style.width = Math.abs(pathEndX - pathStartX) + 'px';
  svg.style.height = svgHeight + 'px';

  // Call function for drawing the path
  var pathStart = {x: pathStartX - svgLeft, y: (svgTop === startElemBottom) ? 0 : svgHeight};
  var pathEnd   = {x: pathEndX - svgLeft,   y: (svgTop === startElemBottom) ? svgHeight : 0};
  drawPath(svg, path, pathStart, pathEnd);

}

function connectAll(direction) {

  var svg = document.getElementById('svg1'),
      path = document.getElementById('path1');

  // This is just to help with example. 
  if (direction == 'topDown') {
    var div1 = document.getElementById('box_1'),
      div2 = document.getElementById('box_20');
  } else {
    var div1 = document.getElementById('box_20'),
      div2 = document.getElementById('box_1');
  }

  // connect all the paths you want!
  connectElements(svg, path, div1, div2, 'line');

}

//connectAll('topDown');
connectAll('bottomUp');