Почему <marker>не ориентируется как <path> - PullRequest
0 голосов
/ 25 апреля 2018

Я пытаюсь создать изогнутую стрелку с 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>

А вот и результат SVG

.

Я не могу понять, почему маркер не ориентируется. Есть ли лучшая библиотека для генерации пути для решения этой проблемы?

Ответы [ 3 ]

0 голосов
/ 25 апреля 2018

Это ожидаемое поведение. Проблема в том, что в кардинальном сплайне ...

На каждом конце кривой требуются две дополнительные точки.

И эти точки, по-видимому, мешают ориентации маркера (это действительно так, см. ответ ЛеБо ).

Вы можете легко увидеть это, если измените кривую. Например, используя 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);
<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>

В вашем случае решение (возможно, взлом) может заключаться в добавлении к пути последней строки, находящейся всего в 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);
<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>
0 голосов
/ 25 апреля 2018
  • Во-первых, атрибуты ref вроде бы правильные, но может быть лучше, я думаю, сделайте refX 0, так как вы используете полный viewBox.

  • Я думаюориентация маркера правильная и обновленная.Но в зависимости от окончания пути интерполяция ориентации может выглядеть неправильно.Таким образом, вы можете проверить это поведение, обрезав вашу траекторию от последней кривой 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);});
}
0 голосов
/ 25 апреля 2018

Это потому, что последняя контрольная точка и конечная точка вашего пути имеют одинаковые координаты: (385 275).

SVG использует вектор контрольной точки, чтобы определить направление кривой в этой точке. Если ваш вектор контрольной точки от (385,275) до (385,275), то он не может определить угол. Таким образом, по умолчанию угол составляет 0 градусов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...