我需要使用SVG从一个点(x0,y0)
到另一个(x1,y1)
绘制漂亮的描边块箭头,就像图片上的那个一样。
我能想象的唯一方法是使用一条线(两条线基本上用于模拟笔划和填充)和标记,但由于笔划重叠,它看起来很丑陋。
理想情况下,线条和标记应该用相同的颜色填充,并且应该具有相同的笔触颜色,并且整体箭头宽度可以固定(但是如果我可以参数化它也会很酷)。基本上它应该与提供的图片看起来相同,并且应该能够通过提供两点的坐标来绘制。 它甚至可能吗?
答案 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)
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;