{
const boxHeight = 200;
const svg = d3.create('svg').attr('viewBox', [0, 0, width, boxHeight]);
const markerBoxWidth = 20;
const markerBoxHeight = 20;
const refX = markerBoxWidth / 2;
const refY = markerBoxHeight / 2;
const markerWidth = markerBoxWidth / 2;
const markerHeight = markerBoxHeight / 2;
const arrowPoints = [[0, 0], [0, 20], [20, 10]];
const circles = [
{ x: width / 3, y: boxHeight / 1.5, r: 50 },
{ x: width / 1.5, y: boxHeight / 3, r: 50 }
];
const linkSource = {
x: circles[0].x + circles[0].r,
y: circles[0].y
};
const linkTarget = {
x: circles[1].x - circles[0].r - markerWidth,
y: circles[1].y
};
const link = d3
.linkHorizontal()
.x(d => d.x)
.y(d => d.y)({
source: linkSource,
target: linkTarget
});
svg
.append('defs')
.append('marker')
.attr('id', 'arrow')
.attr('viewBox', [0, 0, markerBoxWidth, markerBoxHeight])
.attr('refX', refX)
.attr('refY', refY)
.attr('markerWidth', markerBoxWidth)
.attr('markerHeight', markerBoxHeight)
.attr('orient', 'auto-start-reverse')
.append('path')
.attr('d', d3.line()(arrowPoints))
.attr('stroke', 'black');
svg
.selectAll('circle')
.data(circles)
.join('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', d => d.r)
.style('fill', 'green');
svg
.append('path')
.attr('d', link)
.attr('marker-end', 'url(#arrow)')
.attr('stroke', 'black')
.attr('fill', 'none');
return svg.node();
}