Д3.JS force layout-размещение/вращение метки края

Я довольно новый С D3.Джей-ЭС, а я тут играл с силовым макетом. Одной из вещей, которые я пробовал, было размещение ярлыков на ссылках.

один из способов сделать это путем добавления svg:text и ручной расчет translate & rotate, который работает с прямыми линиями. Но, в случае, когда ссылка является svg:path (например, arc), это работает не так, как ожидалось. В этих случаях svg:textPath предложил решение.

на демо, вы можете увидеть простой реализация добавления меток к ссылкам через svg:textPath. Единственная проблема заключается в том, что в случае, когда источник расположен справа от цели, текст отображается в противоположном направлении (с нашей точки зрения, он по-прежнему корректен с точки зрения пути). Мой вопрос в том, как с этим справиться?

только "решение" я придумал is, вручную меняя источник и цель в случае, описанном выше. здесь, вы можете видеть, что это почти строительство.

enter image description here

в состоянии, когда происходит своп, вы также можете увидеть, как дуга переворачивается на другую сторону, что выглядит неправильно. :(

1 ответов


@LarsKotthoff правильно, что textPath должен следовать направлению пути. В этом случае направление пути определяет не только направление дуги, но и прикрепление маркера стрелки на конце - это усложняет обмен направлениями на лету, так как вам тоже придется перемещать маркер.

более простое решение (хотя, возможно, не лучшее, если у вас есть большое количество ссылок) - это "тень" реального пути ссылки с невидимым путем, используемым только для текст:

var link = svg.append("svg:g").selectAll("g.link")
    .data(force.links())
  .enter().append('g')
    .attr('class', 'link');

var linkPath = link.append("svg:path")
    .attr("class", function(d) { return "link " + d.type; })
    .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });

var textPath = link.append("svg:path")
    .attr("id", function(d) { return d.source.index + "_" + d.target.index; })
    .attr("class", "textpath");

теперь у вас есть отдельный путь вы можете правильно манипулировать. Как вы заметили, есть две проблемы-вы должны изменить направление пути, и вы должны изменить направление дуги. Похоже, вы можете сделать это в командной строке path, заменив sweep-flag значение (см. docs), таким образом, вместо Arx,ry 0 0,1 вы Arx,ry 0 0,0. Вы можете уменьшить дублирование кода, имея одну функцию для создания строк пути:

function arcPath(leftHand, d) {
    var start = leftHand ? d.source : d.target,
        end = leftHand ? d.target : d.source,
        dx = end.x - start.x,
        dy = end.y - start.y,
        dr = Math.sqrt(dx * dx + dy * dy),
        sweep = leftHand ? 0 : 1;
    return "M" + start.x + "," + start.y + "A" + dr + "," + dr +
        " 0 0," + sweep + " " + end.x + "," + end.y;
}

затем вы можете обновите путь ссылки и текстовый путь отдельно:

linkPath.attr("d", function(d) {
    return arcPath(false, d);
});

textPath.attr("d", function(d) {
    return arcPath(d.source.x < d.target.x, d);
});

см. рабочий код:http://jsfiddle.net/nrabinowitz/VYaGg/2/