我试图用svg创建一个弯曲的箭头。我使用d3.line()生成路径。
let points = [
[400,100],
[450,200],
[350,200],
[385,275]
]
let path = d3.line().curve(d3.curveCardinal)(points)
console.log(path)
// -> M400,100C400,100,458.3333333333333,183.33333333333334,450,200C441.6666666666667,216.66666666666666,360.8333333333333,187.5,350,200C339.1666666666667,212.5,385,275,385,275
但是当我尝试在svg中使用这个结果时:
<svg width="1200" height="1200" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<marker id="Triangle" viewBox="0 0 10 10" refX="1" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<path d="M400,100C400,100,458.3333333333333,183.33333333333334,450,200C441.6666666666667,216.66666666666666,360.8333333333333,187.5,350,200C339.1666666666667,212.5,385,275,385,275"
stroke-width="2" stroke="lightblue" fill="none" style="marker-end: url(#Triangle);"></path>
</svg>
&#13;
这是SVG结果
。
我无法弄清楚标记没有定位的原因。是否有更好的库来生成解决此问题的路径?
答案 0 :(得分:3)
这是预期的行为。问题在于cardinal spline ......
曲线两端需要两个额外的点。
这些点似乎干扰了标记的方向(事实确实如此,见LeBeau's answer)。
如果更改曲线,则可以轻松看到此信息。例如,使用curveBasis
:
let points = [
[400,100],
[450,200],
[350,200],
[385,275]
]
let path = d3.line().curve(d3.curveBasis)(points)
d3.select("#myPath").attr("d", path);
&#13;
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="1200" height="1200" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<marker id="Triangle" viewBox="0 0 10 10" refX="1" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<path id="myPath" stroke-width="2" stroke="lightblue" fill="none" style="marker-end: url(#Triangle);"></path>
</svg>
&#13;
在你的情况下,一个解决方案(可以说是一个黑客)可能会在路径上添加最后一行,距离最终点只有1px:
path = path + "L387,277";
以下是演示:
let points = [
[400,100],
[450,200],
[350,200],
[385,275]
]
let path = d3.line().curve(d3.curveCardinal)(points)
path = path + "L387,277";
d3.select("#myPath").attr("d", path);
&#13;
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="1200" height="1200" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<marker id="Triangle" viewBox="0 0 10 10" refX="1" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<path id="myPath" stroke-width="2" stroke="lightblue" fill="none" style="marker-end: url(#Triangle);"></path>
</svg>
&#13;
答案 1 :(得分:2)
这是因为路径的最后一个控制点和终点具有相同的坐标:(385,275)。
SVG使用控制点向量来计算出该点的曲线方向。如果您的控制点向量是从(385,275)到(385,275),那么它无法确定角度。因此它默认为0度的角度。
答案 2 :(得分:-2)
首先,ref属性是正确的,但我认为可以更好,因为你使用完整的viewBox,使refX为0。
我认为标记的方向是正确的并且已更新。但是基于路径的结尾,方向的插值可能看起来不正确。因此,您可以通过从最后一个C ...曲线中剪切路径字符串来验证此行为,并且会看到方向是正确的。
我进一步测试它是否正确,至少对于线段,这里是一个小提琴,我甚至没有使用d3:
https://jsfiddle.net/ibowankenobi/L8x19rco/2/
var path = document.querySelector("path[stroke]");
var arr = Array.apply(null,Array(path.getTotalLength()/4 << 0)).map(function(d,i){
var p = this.getPointAtLength(i*4);
return [p.x,p.y];
},path);
var length = arr.length;
animate();
function animate(index){
if(index >= length){
return;
}
var index = index || 0;
path.setAttribute("d","M"+arr.slice(1,Math.min(++index+1,length)).join("L"));
window.requestAnimationFrame(function(){animate(index);});
}