Рендеринг связей между узлами в D3 (Force Directed Graphs)
Я работаю над следующим примером Робина Фришмана.
До сих пор мне удавалось отображать узлы в браузере, и все, кажется, идет гладко, но я не могу отобразить реляционные ссылки.
Я вижу элементы группировки (для узлов, текста и ссылок) в элементах dev tools, но, похоже, я не могу получить ссылки для соединения узлов, а также чтобы узлы не сходились друг с другом правильно...
Код ниже (некоторая помощь будет наиболее ценится!)
HTML:
<head>
<meta charset='utf-8'>
<title>User Interaction (FDG)</title>
<script src='https://d3js.org/d3.v4.js'></script>
</head>
<body>
<script src='../js/user-interaction.js'></script>
</body>
JS:
// Data:
const nodes = [
{ id: "mammal", group: 0, label: "Mammals", level: 1 },
{ id: "dog" , group: 0, label: "Dogs" , level: 2 },
{ id: "cat" , group: 0, label: "Cats" , level: 2 },
{ id: "fox" , group: 0, label: "Foxes" , level: 2 },
{ id: "elk" , group: 0, label: "Elk" , level: 2 },
{ id: "insect", group: 1, label: "Insects", level: 1 },
{ id: "ant" , group: 1, label: "Ants" , level: 2 },
{ id: "bee" , group: 1, label: "Bees" , level: 2 },
{ id: "fish" , group: 2, label: "Fish" , level: 1 },
{ id: "carp" , group: 2, label: "Carp" , level: 2 },
{ id: "pike" , group: 2, label: "Pikes" , level: 2 }
];
const links = [
{ target: "mammal", source: "dog" , strength: 0.7 },
{ target: "mammal", source: "cat" , strength: 0.7 },
{ target: "mammal", source: "fox" , strength: 0.7 },
{ target: "mammal", source: "elk" , strength: 0.7 },
{ target: "insect", source: "ant" , strength: 0.7 },
{ target: "insect", source: "bee" , strength: 0.7 },
{ target: "fish" , source: "carp", strength: 0.7 },
{ target: "fish" , source: "pike", strength: 0.7 },
{ target: "cat" , source: "elk" , strength: 0.1 },
{ target: "carp" , source: "ant" , strength: 0.1 },
{ target: "elk" , source: "bee" , strength: 0.1 },
{ target: "dog" , source: "cat" , strength: 0.1 },
{ target: "fox" , source: "ant" , strength: 0.1 },
{ target: "pike" , source: "cat" , strength: 0.1 }
];
const getNodeColor = (node) => {
return node.level === 1 ? 'red' : 'blue';
}
const width = 700,
height = 600;
const svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height);
const nodeElements = svg.append('g')
.attr('class', 'nodes')
.selectAll('circle')
.data(nodes)
.enter().append('circle')
.attr('r', 10)
.attr('fill', getNodeColor);
const textElements = svg.append('g')
.attr('class', 'texts')
.selectAll('text')
.data(nodes)
.enter().append('text')
.text((nodes) => {return nodes.label;})
.attr('font-size', 15)
.attr('dx', -10)
.attr('dy', 25);
const linkElements = svg.append('g')
.attr('class', 'links')
.selectAll('line')
.data(links)
.enter().append('line')
.attr('stroke-width', 1.5)
.attr('stroke', 'rgba(50, 50, 50, 0.2)');
const linkForce = d3.forceLink()
.id((link) => {return link.id;})
.strength((link) => {return link.strength;});
const simulation = d3.forceSimulation()
.force('link', linkForce)
.force('charge', d3.forceManyBody().strength(-50))
.force('center', d3.forceCenter(width/2, height/2));
simulation.nodes(nodes).on('tick', () => {
nodeElements
.attr('cx', (nodes) => {return nodes.x;})
.attr('cy', (nodes) => {return nodes.y;})
textElements
.attr('x', (nodes) => {return nodes.x;})
.attr('y', (nodes) => {return nodes.y;})
linkElements
.attr('x1', (link) => {return link.source.x;})
.attr('y1', (link) => {return link.source.y;})
.attr('x2', (link) => {return link.target.x;})
.attr('y2', (link) => {return link.target.y;})
});