Сеть d3 с несколькими ссылками в одном направлении

1

Я пытаюсь изменить пример мобильных патентов, чтобы разрешить несколько ссылок в одном направлении.

У меня есть данные (да, я знаю, что Джим на самом деле не Pam boss):

source          target          relationship          
Michael Scott   Jan Levenson    pro
Jan Levenson    Michael Scott   personal
Jim Halpert     Pam Beasley     pro
Jim Halpert     Pam Beasley     personal

Многоканальная функциональность примера Mobil Patents Suit позволяет правильно отображать первые две строки (две дуги). Однако для двух последних строк представлена только одна смешанная дуга.

Вопрос: Как разрешить ссылки с той же направленностью, которые будут показаны как несколько дуг, а не одна дуга?

Вот мой код дуги (разорванный прямо из примера мобильных патентов):

function tick() {
  path.attr("d", linkArc);
  circle.attr("transform", transform);
  text.attr("transform", transform);
}

function linkArc(d) {
  var dx = d.target.x - d.source.x,
      dy = d.target.y - d.source.y,
      dr = Math.sqrt(dx * dx + dy * dy);
  return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}

function transform(d) {
  return "translate(" + d.x + "," + d.y + ")";
}

Любая помощь вообще была бы весьма признательна. Спасибо!

Теги:
d3.js

1 ответ

2
Лучший ответ

Вероятно, для этого существует несколько потенциальных подходов, один приходит на ум довольно быстро: используйте другой генератор путей для каждого отношения типов между узлами. У вас должно быть свойство, указывающее характер отношений (которые у вас есть в вашем вопросе), и используйте это, чтобы установить выравнивание по пути.

В нижеприведенном фрагменте я проверяю, какая связь рисуется, и уменьшаем радиус дуги в личных отношениях на 50% по сравнению с радиусом радиуса профессиональных отношений. Соответствующая часть:

function linkArc(d) {

  var dx = d.target.x - d.source.x,
      dy = d.target.y - d.source.y,
      dr = Math.sqrt(dx * dx + dy * dy);
  if(d.relationship == "pro") { 
     return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
  }
  else {
    return "M" + d.source.x + "," + d.source.y + "A" + (dr * 0.3) + "," + (dr * 0.3) + " 0 0,1 " + d.target.x + "," + d.target.y;
  }
}

Здесь все на практике:

var links = [
  { source: "Michael Scott",
    target:"Jan Levenson",
    relationship: "pro"
  },
  { source:"Jan Levenson",
    target:"Michael Scott",
    relationship: "Personal"
  },
  { source: "Jim Halpert",
    target: "Pam Beasley",
    relationship: "pro"
  },
  {
    source: "Jim Halpert",
    target: "Pam Beasley",
    relationship: "Personal" 
  }
  ]
  
  var nodes = {};

// Compute the distinct nodes from the links.
links.forEach(function(link) {
  link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
  link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});

var width = 960,
    height = 500;

var force = d3.layout.force()
    .nodes(d3.values(nodes))
    .links(links)
    .size([width, height])
    .linkDistance(60)
    .charge(-300)
    .on("tick", tick)
    .start();

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
    .data(["suit", "licensing", "resolved"])
  .enter().append("marker")
    .attr("id", function(d) { return d; })
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 15)
    .attr("refY", -1.5)
    .attr("markerWidth", 6)
    .attr("markerHeight", 6)
    .attr("orient", "auto")
  .append("path")
    .attr("d", "M0,-5L10,0L0,5");

var path = svg.append("g").selectAll("path")
    .data(force.links())
  .enter().append("path")
    .attr("class", function(d) { return "link " + d.type; })
    .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });

var circle = svg.append("g").selectAll("circle")
    .data(force.nodes())
  .enter().append("circle")
    .attr("r", 6)
    .call(force.drag);

var text = svg.append("g").selectAll("text")
    .data(force.nodes())
  .enter().append("text")
    .attr("x", 8)
    .attr("y", ".31em")
    .text(function(d) { return d.name; });

// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
  path.attr("d", linkArc);
  circle.attr("transform", transform);
  text.attr("transform", transform);
}

function linkArc(d) {

  var dx = d.target.x - d.source.x,
      dy = d.target.y - d.source.y,
      dr = Math.sqrt(dx * dx + dy * dy);
  if(d.relationship == "pro") { 
     return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
  }
  else {
    return "M" + d.source.x + "," + d.source.y + "A" + (dr * 0.3) + "," + (dr * 0.3) + " 0 0,1 " + d.target.x + "," + d.target.y;
  }
}

function transform(d) {
  return "translate(" + d.x + "," + d.y + ")";
}
.link {
  fill: none;
  stroke: #666;
  stroke-width: 1.5px;
}

#licensing {
  fill: green;
}

.link.licensing {
  stroke: green;
}

.link.resolved {
  stroke-dasharray: 0,2 1;
}

circle {
  fill: #ccc;
  stroke: #333;
  stroke-width: 1.5px;
}

text {
  font: 10px sans-serif;
  pointer-events: none;
  text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню