'How to connect from the edge of a circle instead of the center
Here im added the link from circle center to circle center but i want to connect from circle edge to edge
I want to connect the links from node edge to edge but im getting node center to center is i did mistake in my code please help me out if any one know answer for this problem
here is my full working code
const VocabularyGraphh = () => {
const svgRef = useRef(null);
React.useEffect(() => {
const svg = d3.select(svgRef.current),
diameter = +svg.attr("width"),
g = svg.append("g").attr("transform", "translate(2,2)"),
format = d3.format(",d");
const links = [
{ source: "animate1", target: "animate4" },
{ source: "animate6", target: "animate9" },
// { source: "animate9", target: "animate6" },
{ source: "animate3", target: "animate2" },
{ source: "animate1", target: "animate8" },
{ source: "animate3", target: "animate5" },
// { source: "analytics1", target: "analytics2" },
];
let root = {
children: [
{
name: "analytics1",
children: [
{
name: "animate1",
size: 1500,
},
{
name: "animate2",
size: 1500,
},
{
name: "animate3",
size: 1500,
},
{
name: "animate33",
size: 1500,
},
{
name: "animate23",
size: 1500,
},
{
name: "animate32",
size: 1500,
},
{
name: "animate11",
size: 1500,
},
{
name: "animate22",
size: 1500,
},
{
name: "animate34",
size: 1500,
},
{
name: "animate16",
size: 1500,
},
{
name: "animate20",
size: 1500,
},
{
name: "animate3",
size: 1500,
},
],
},
{
name: "analytics2",
children: [
{
name: "animate4",
size: 1500,
},
{
name: "animate5",
size: 1500,
},
{
name: "animate6",
size: 1500,
},
],
},
{
name: "analytics3",
children: [
{
name: "animate7",
size: 1500,
},
{
name: "animate8",
size: 1500,
},
{
name: "animate9",
size: 1500,
},
],
},
],
};
// svg
// .append("svg:defs")
// .append("svg:marker")
// .attr("id", "arrow")
// .attr("viewBox", "0 0 10 10")
// .attr("refX", 10)
// .attr("refY", 5)
// .attr("markerUnits", "strokeWidth")
// .attr("markerWidth", 6)
// .attr("markerHeight", 3)
// .attr("orient", "auto")
// .append("svg:path")
// .style("stroke", "none")
// .attr("d", "M 0 0 L 10 5 L 0 10 z");
const pack = d3
.pack()
.size([diameter / 2, diameter / 2])
.padding(100);
root = d3
.hierarchy(root)
.sum(function (d) {
return d.size;
})
.sort(function (a, b) {
return b.value - a.value;
});
const node = g
.selectAll(".node")
.data(pack(root).descendants())
.enter()
.filter(function (d) {
return !!d.data.name;
})
.append("g")
.attr("id", function (d) {
return d.data.name;
})
.attr("class", function (d) {
return d.children ? "node" : "leaf node";
})
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("title").text(function (d) {
return d.data.name + "\n" + format(d.value);
});
const arrow = svg.selectAll("path.arrow").data(links, JSON.stringify);
arrow
.enter()
.append("path")
.attr("class", "arrow")
.attr("x1", function (d) {
console.log(d);
let translate = getTranslate(d.source);
console.log(translate);
return translate[0];
})
.attr("x2", function (d) {
let translate = getTranslate(d.target);
return translate[0];
})
.attr("y1", function (d) {
let translate = getTranslate(d.source);
return translate[1];
})
.attr("y2", function (d) {
let translate = getTranslate(d.target);
return translate[1];
})
.attr("d", function (d) {
// console.log(d);
let source = getTranslate(d.source),
target = getTranslate(d.target),
x1 = source[0],
x2 = target[0],
y1 = source[1],
y2 = target[1];
console.log(source);
console.log(target);
// let dx = x1 - x2,
// dy = y1 - y2,
// dr = Math.sqrt(dx * dx + dy * dy);
return (
"M" + x1 + "," + y1 + "A" + 0 + "," + 0 + " 0 0,1 " + x2 + "," + y2
);
})
.style("stroke", "black")
.style("fill", "none")
.style("stroke-width", 1)
.attr("marker-end", "url(#arrow)")
.attr("class", "hidden-arrow ");
// .attr("stroke-width", 1);
node
.append("circle")
.attr("r", function (d) {
console.log(d);
return d.r;
})
.attr("class", "pink");
node.filter(function (d) {
return !d.children;
});
// .append("text")
// .attr("dy", "0.3em")
// .text(function (d) {
// return d.data.name.substring(0, d.r / 3);
// });
function getTranslate(datum) {
const circle = d3.select("#" + datum);
const string = circle.attr("transform");
const translate = string
.substring(string.indexOf("(") + 1, string.indexOf(")"))
.split(",");
return translate;
}
}, []);
return (
<div>
<svg ref={svgRef} width="960" height="960"></svg>
</div>
);
};
export default VocabularyGraphh;
if anyone give this solution thats so appreciatable
Solution 1:[1]
Use connectLine to calculate the path between two circles:
const connectLine = (x1, y1, r1, x2, y2, r2) => {
const distance = Math.hypot(x1 - x2, y1 - y2);
const prop1 = r1 / distance;
const cx1 = x2 * prop1 + x1 * (1 - prop1);
const cy1 = y2 * prop1 + y1 * (1 - prop1);
const prop2 = r2 / distance;
const cx2 = x1 * prop2 + x2 * (1 - prop2);
const cy2 = y1 * prop2 + y2 * (1 - prop2);
return `M ${cx1},${cy1} L ${cx2},${cy2}`;
};
const x1 = 30;
const y1 = 50;
const r1 = 20;
const x2 = 140;
const y2 = 160;
const r2 = 30;
const svg = d3.select('svg');
svg.append('circle')
.attr('cx', x1)
.attr('cy', y1)
.attr('r', r1)
.style('fill', 'none')
.style('stroke', 'red')
svg.append('circle')
.attr('cx', x2)
.attr('cy', y2)
.attr('r', r2)
.style('fill', 'none')
.style('stroke', 'blue')
svg.append('path')
.attr('d', connectLine(x1, y1, r1, x2, y2, r2))
.style('fill', 'none')
.style('stroke', 'green');
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="200" height="200"/>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Michael Rovinsky |

