使用SVG阻止箭头

时间:2017-01-19 08:52:40

标签: svg

我需要使用SVG从一个点(x0,y0)到另一个(x1,y1)绘制漂亮的描边块箭头,就像图片上的那个一样。

arrow

我能想象的唯一方法是使用一条线(两条线基本上用于模拟笔划和填充)和标记,但由于笔划重叠,它看起来很丑陋。

理想情况下,线条和标记应该用相同的颜色填充,并且应该具有相同的笔触颜色,并且整体箭头宽度可以固定(但是如果我可以参数化它也会很酷)。基本上它应该与提供的图片看起来相同,并且应该能够通过提供两点的坐标来绘制。 它甚至可能吗?

3 个答案:

答案 0 :(得分:4)

我很无聊,所以你走了。我写了一个函数来生成一个正确形状的路径。

你只需要给它“从”和“到”坐标,线宽,箭头宽度和箭头长度。

享受!

var from = {x: 50, y: 250};
var to = {x: 250, y: 100};

var lineWidth = 30;
var arrowheadWidth = 60;
var arrowheadLength = 50;

var svg = document.getElementById("test");

drawArrow(svg, from, to, lineWidth, arrowheadWidth, arrowheadLength);


function drawArrow(svg, from, to, lineWidth, arrowheadWidth, arrowheadLength)
{
  var dx = to.x - from.x;
  var dy = to.y - from.y;
  // Calculate the length of the line
  var len = Math.sqrt(dx * dx + dy * dy);
  if (len < arrowheadLength) return;

  // The difference between the line width and the arrow width
  var dW = arrowheadWidth - lineWidth;
  // The angle of the line
  var angle = Math.atan2(dy, dx) * 180 / Math.PI;
  // Generate a path describing the arrow. For simplicity we define it as a
  // horizontal line of the right length, and starting at 0,0. Then we rotate
  // and move it into place with a transform attribute.
  var d = ['M', 0, -lineWidth/2,
           'h', len - arrowheadLength,
           'v', -dW / 2,
           'L', len, 0,
           'L', len - arrowheadLength, arrowheadWidth / 2,
           'v', -dW / 2,
           'H', 0,
           'Z' ];
  var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
  path.setAttribute("d", d.join(' '));
  path.setAttribute("transform", "translate("+from.x+","+from.y+") rotate("+angle+")");
  path.setAttribute("class", "arrow-line");
  svg.appendChild(path);
}
.arrow-line {
  fill: gold;
  stroke: black;
  stroke-width: 6;
}
<svg id="test" width="300" height="300">
</svg>

答案 1 :(得分:0)

最简单的方法是使用脚本创建箭头。 在这里,我只需从两个点p1和p2确定箭头的长度和角度,然后创建一个正确长度的简单路径并按计算的角度旋转:

svgns="http://www.w3.org/2000/svg"
function arrow(p1,p2){
  var h1=15 // line thickness
  var h2=35 // arrow height
  var w2=22 // arrow width
  var deg = Math.atan2(p1.y - p2.y, p1.x - p2.x) * (180 / Math.PI);
  var len = Math.sqrt(Math.pow(p1.y - p2.y,2)+Math.pow(p1.x - p2.x,2))
  var arr = document.createElementNS(svgns,"path")
  var d = `M${p1.x} ${p1.y-h1/2}v${h1}h${h2/2-len}v${(h2-h1)/2}l${-w2} ${-h2/2}l${w2} ${-h2/2}v${(h2-h1)/2}z`
  arr.setAttribute("d",d)
  arr.setAttribute("transform",`rotate(${deg} ${p1.x} ${p1.y})`)
  arr.classList.add("arrow")
  return arr
}

var a1 = arrow({x:50,y:50},{x:200,y:200})
var a2 = arrow({x:450,y:50},{x:300,y:200})
var a3 = arrow({x:450,y:450},{x:300,y:300})
var a4 = arrow({x:50,y:450},{x:200,y:300})
svg.appendChild(a1)
svg.appendChild(a2)
svg.appendChild(a3)
svg.appendChild(a4)
.arrow{stroke-width:3px}
.arrow:nth-of-type(1){fill:green;stroke:lime}
.arrow:nth-of-type(2){fill:red;stroke:orange}
.arrow:nth-of-type(3){fill:blue;stroke:turquoise}
.arrow:nth-of-type(4){fill:violet;stroke:pink}
<svg id="svg" viewBox="0 0 500 500" width="400" height="400">

</svg>

如果你试图想要找到一个没有脚本的解决方案,那么你必须要有很多循环... 你需要至少4个箭头,每个箭头从左上到右下,从右上到左下,从左下到右上,从右下到左上...

这是一个概念的证明,它是可行的,但我强烈反对它...

svg{overflow:visible;}
<svg width="200" height="200" style="overflow:visible" stroke="red" color="orange" opacity="0.5">
  <marker id="ah" viewBox="0 0 10 10" orient="auto" refX="10" refY="5" overflow="visible">
    <path d="M0 0L10 5L0 10z"  stroke-width="1"/>
  </marker>
  <marker id="ah2" viewBox="0 0 10 10" orient="auto" refX="10" refY="5">
    <path d="M0 0L10 5L0 10z" fill="currentColor" stroke="none"/>
  </marker>
  <marker id="block" viewBox="0 0 10 10" orient="auto" refX="9" refY="5">
    <rect x="0" y="0" width="10" height="10" stroke="white" stroke-width="1"/>
  </marker>
  <marker id="block2" viewBox="0 0 10 10" orient="auto" refX="9" refY="5">
    <rect x="0" y="0" width="10" height="10" stroke-width="5"/>
  </marker>
  <mask id="m1">
    <rect x="-10%" y="-10%" width="110%" height="110%" fill="white"/>
    <line x1="99.999%" y1="99.999%" x2="100%" y2="100%" stroke-width="20" marker-end="url(#block)"/>
  </mask>
  <line x1="0.001%" y1="0.001%" x2="0%" y2="0%" stroke-width="8" marker-end="url(#block2)"/>
  <line x1="0" y1="0" x2="100%" y2="100%" stroke-width="25"  mask="url(#m1)"/>
  <line x1="99.999%" y1="99.999%" x2="100%" y2="100%" stroke-width="20" marker-end="url(#ah)"/>
  <line x1="0" y1="0" x2="100%" y2="100%" stroke-width="20" stroke="currentColor" mask="url(#m1)"/>
  <line x1="99.999%" y1="99.999%" x2="100%" y2="100%" stroke-width="20" marker-end="url(#ah2)"/>
</svg>

答案 2 :(得分:0)

坐了几个小时三次检查我的所有数学:
在SVG defs标签中创建了一个标准化箭头 然后在提供的坐标后缩放箭头。 (增加了静态高度XD)

&#13;
&#13;
document.addEventListener("DOMContentLoaded", function(event) {
  var svgDoc = document.getElementById("arrowSvg");
  var useArrow = svgDoc.getElementById("customArrow");
  var extraData = useArrow.getAttribute("extra:data");
  extraData = extraData.split(" ");
  var x1 = parseInt(extraData[0]);
  var x2 = parseInt(extraData[1]);
  var y1 = parseInt(extraData[2]);
  var y2 = parseInt(extraData[3]);
  var arrowHeight = 15;
  //Calculate the rotation needed
  var deltaY = y1 - y2;
  var deltaX = x2 - x1;
  var angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
  //Distance between the two points.
  var distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
  useArrow.setAttribute("transform", 
                        "translate("+(x1+(deltaX/2))+" "+(y1-(deltaY/2))+") "+
                        "rotate(" + -1*angle +") " +
                        "matrix("+distance+", 0, 0, "+arrowHeight+", "+(0.5-distance*0.5)+","+(0.5-arrowHeight* 0.5)+")");

});
&#13;
svg {
  width: 50%;
  border: 1px solid black;
}
.arrow {
  stroke: black;
  stroke-width: 0.05;
  fill: yellow;
}
&#13;
<svg id="arrowSvg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:extra="ExtraNameSpace">>
  <defs>
    <path id="idArrow" class="arrow" d="M0,0.25 0.60,0.25 
                         0.60,0 1,0.5 0.60,1
                         0.60,0.75 0,0.75z" />
  </defs>
  <!--- Extra Data Param: x1 x2 y1 y2--->
  <use id="customArrow" xlink:href="#idArrow" extra:data="10 90 90 5" />

</svg>
&#13;
&#13;
&#13;