It is an old topic and read many questions regarding this issue but I still can't figure it out what the error can be. My only excuse is that I am pretty new with d3.
So I'd like a custom image or svg on nodes but all I can achieve is the built-in symbols (circle).
The code is
const simulation = d3.forceSimulation(nodes)
.force('link', d3.forceLink(links).id((l: any) => l.id))
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2))
.on('tick', ticked)
const svg = d3
.select(graphRef.current)
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 960 500")
const link = svg
.append('g')
.attr('stroke', '#999')
.attr('stroke-opacity', 0.6)
.selectAll()
.data(links)
.join('line')
.attr('stroke-width', (d: any) => Math.sqrt(d.value))
const node = svg
.append('g')
.attr('stroke', '#fff')
.attr('stroke-width', 1.5)
.selectAll()
.data(nodes)
.join('circle')
.attr('r', 5)
.attr('fill', 'green')
node.call(d3.drag()
.on('start', dragStarted)
.on('drag', dragged)
.on('end', dragEnded))
I tried to mimic the code from https://gist.github.com/mbostock/950642 but it doesn't show anything, the nodes disappear, only the links can be seen (well I think the icon is displayed on the top left corner though)
const node = svg
.append('g')
.attr('stroke', '#fff')
.attr('stroke-width', 1.5)
.selectAll()
.data(nodes)
.enter()
.append("g")
.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("width", 16)
.attr("height", 16);
// .join('circle')
// .attr('r', 5)
// .attr('fill', 'green')
I'd appreciate any hint please.
Thank you!
//////////////// UPDATE //////////////////
const ticked = (): void => {
link.attr("x1", (d: any) => d.source.x)
.attr("y1", (d: any) => d.source.y)
.attr("x2", (d: any) => d.target.x)
.attr("y2", (d: any) => d.target.y);
node.attr("cx", (d: any) => d.x)
.attr("cy", (d: any) => d.y);
}
You didn't post your ticked
function which is most relevant bit to your question. So, without seeing it, I'm guessing that you probably failed to update it to position the g
holding your image and instead it is still trying to position a circle with cx
and cy
properties that don't exist on a g
/image
. The update would look something like this:
function ticked() {
link
.attr('x1', (d) => d.source.x)
.attr('y1', (d) => d.source.y)
.attr('x2', (d) => d.target.x)
.attr('y2', (d) => d.target.y);
node.attr('transform', (d) => `translate(${d.x - 8},${d.y - 8})`);
}
Notice how it is now being positioned with a transform.
Running code:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.js"></script>
</head>
<body>
<svg id="networkGraph" width="960" height="500"></svg>
<script>
const width = 300,
height = 150;
const nodes = [{ id: 'Alice' }, { id: 'Bob' }, { id: 'Carol' }];
const links = [
{ source: 'Alice', target: 'Bob' },
{ source: 'Bob', target: 'Carol' },
];
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3.forceLink(links).id((l) => l.id)
)
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2))
.on('tick', ticked);
const svg = d3
//.select(graphRef.current)
.select('#networkGraph')
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('viewBox', '0 0 960 500');
const link = svg
.append('g')
.attr('stroke', '#999')
.attr('stroke-opacity', 0.6)
.selectAll()
.data(links)
.join('line')
.attr('stroke-width', (d) => Math.sqrt(d.value));
const node = svg
.append('g')
.selectAll()
.data(nodes)
.enter()
.append('g');
node
.append('image')
.attr('xlink:href', 'https://github.com/favicon.ico')
.attr('width', 16)
.attr('height', 16);
/*
node.call(
d3
.drag()
.on('start', dragStarted)
.on('drag', dragged)
.on('end', dragEnded)
);
*/
function ticked() {
link
.attr('x1', (d) => d.source.x)
.attr('y1', (d) => d.source.y)
.attr('x2', (d) => d.target.x)
.attr('y2', (d) => d.target.y);
node.attr('transform', (d) => `translate(${d.x - 8},${d.y - 8})`);
}
</script>
</body>
</html>