Я использую библиотеку D3 для рисования взаимосвязанного графика элементов. Мои узлы circles
и rects
соединены ориентированной линией path
s.
Моя проблема в том, что строки, указывающие на элемент rects
, имеют уродливую визуализацию, потому что линия заканчивается в верхнем левом углу прямоугольника, а не в его центре (как это происходит для кругов).
Как я могу сделать так, чтобы линии пути были ориентированы на центр как элементов circles
, так и элементов rect
?
Код для определения
defs
стрелок:
svg.append('defs')
.append('marker')
.attr('id', 'arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', 17) // As far as I understood this provides the distance from the end of the path line.
.attr('refY', -0.1)
.attr('markerWidth', 6)
.attr('markerHeight', 6)
.attr('orient', 'auto')
.attr('fill', function() {
return 'red';
})
.append('path')
.attr('d', 'M0,-5L10,0L0,5');
Определение ориентированных ссылок:
let links = svg.selectAll('.link')
.data(data.links)
.enter()
.append('path')
.attr('id', function (d) {
return d.id;
})
.attr('class', 'link')
.attr('fill', 'none')
.attr('stroke-width', 1.2)
.attr('marker-end', 'url(#arrow)')
.attr('stroke', function() {
return 'blue';
})
.style('cursor', 'pointer');
Определение квадратов
let squares = svg.selectAll('.square')
.data(data.squares, function(d) {
return d.id;
})
.enter().append('g')
.call(dragger)
.attr('class', 'square')
.style('cursor', 'pointer');
squares.append('rect')
.attr('width', 10)
.attr('height', 10)
.attr('fill', function (d) {
return '#fff';
})
.style('opacity', 0.1)
.style('stroke', function() {
return '#555';
})
.style('stroke-width', '2');
На следующем скриншоте вы можете увидеть, как он себя ведет. Круги и прямоугольники имеют низкую непрозрачность, чтобы показать проблему с целью пути.
ОБНОВЛЕНИЕ
Добавлено определение и использование функции tick
.
simulation
.nodes(data.nodes)
.on('tick', _tick);
simulation
.force('link')
.distance(80)
.links(data.links);
simulation.alpha(1).restart();
function _tick() {
links.attr('d', function(d) {
let dx = d.target.x - d.source.x;
let dy = d.target.y - d.source.y;
let 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);
});
circles.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
squares.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
}