How can I center the text in a node? - javascript

I'm learning about d3.js and the system of forces. I have a blocker because I am not able to add a text and it is perfectly centered within the circle. I had tried to create <text> but it does not work. How can I achieve it?
In this piece I tried to create a text element but it does not work.
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 20)
.attr("fill", function(d){
return colorNode(d.group);
})
.style("stroke", function(d){
return colorNode(d.group);
})
UPDATE
I know that I must somehow make that within a g element, this content the circle and a text, but I can not make it work. obviously, I also do not know how to center the text inside the circle. My result is that the circle appears outside the force diagram. I have tried this, but not works:
var node = g.append("g")
.attr("class", "nodes")
.selectAll("g")
.data(graph.nodes)
.enter()
.append("g");
node.append("circle")
.attr("r", 20)
.attr("fill", function(d){
return colorNode(d.group);
})
.style("stroke", function(d){
return colorNode(d.group);
})
this is my full code:
https://plnkr.co/edit/JhjhFKQgKVtmYQXmgbzF?p=preview

All you need is setting the dominant-baseline to central, which centers the text vertically, and text-anchor to middle, which centers the text horizontally. Also, get rid of those x and y attributes.
This should be the selection:
var text = g.append("g")
.attr("class", "labels")
.selectAll("text")
.data(graph.nodes)
.enter()
.append("text")
.style("dominant-baseline", "central")
.style("text-anchor", "middle")
.style("font-family", "sans-serif")
.style("font-size", "0.7em")
.text(function(d) {
return d.lotid;
});
Here is your code with those changes:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .9;
}
</style>
<body>
<div id="grafica_back" style="width:100wh"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
width = w.innerWidth || e.clientWidth || g.clientWidth,
height = w.innerHeight || e.clientHeight || g.clientHeight;
var colorNode = d3.scaleOrdinal()
.range(d3.schemeCategory20),
colorLink = d3.scaleOrdinal()
.range(d3.schemeCategory10)
var svg = d3.select("#grafica_back").append("svg")
.attr("width", width)
.attr("height", height);
var graph = {
"nodes": [{
"id": "18362286",
"lotid": "TEST",
"epoch": 1511295513000,
"group": 1,
"sourceOnly": true
},
{
"id": "18362287",
"lotid": "TEST",
"epoch": 1511324313000,
"group": 2,
"sourceOnly": false
}
],
"links": [{
"source": "18362286",
"target": "18362287",
"reltype": "GENEALOGY"
}]
};
var width = 400,
height = 200;
var simulation = d3.forceSimulation()
.nodes(graph.nodes);
simulation
.force("charge_force", d3.forceManyBody().strength(-100))
.force("center_force", d3.forceCenter(width / 2, height / 2))
.force("links", d3.forceLink(graph.links).id(function(d) {
return d.id;
}).distance(100).strength(0.1))
.force("collide", d3.forceCollide().radius(2))
;
simulation
.on("tick", ticked);
//add encompassing group for the zoom
var g = svg.append("g")
.attr("class", "everything");
//Create deffinition for the arrow markers showing relationship directions
g.append("defs").append("marker")
.attr("id", "arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 23)
.attr("refY", 0)
.attr("markerWidth", 8)
.attr("markerHeight", 8)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var link = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke", function(d) {
console.log(d);
return colorLink(d.group);
})
.attr("marker-end", "url(#arrow)");
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 20)
.attr("fill", function(d) {
return colorNode(d.group);
})
.style("stroke", function(d) {
return colorNode(d.group);
})
//add drag capabili
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);
drag_handler(node);
var text = g.append("g")
.attr("class", "labels")
.selectAll("text")
.data(graph.nodes)
.enter()
.append("text")
.style("dominant-baseline", "central")
.style("text-anchor", "middle")
.style("font-family", "sans-serif")
.style("font-size", "0.7em")
.text(function(d) {
return d.lotid;
});
node.on("click", function(d) {
d3.event.stopImmediatePropagation();
self.onNodeClicked.emit(d.id);
});
node.append("title")
.text(function(d) {
d.lotid;
});
//add zoom capabilities
var zoom_handler = d3.zoom()
.on("zoom", zoom_actions);
zoom_handler(svg);
//Drag functions
//d is the node
function drag_start(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
//make sure you can't drag the circle outside the box
function drag_drag(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function drag_end(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
//Zoom functions
function zoom_actions() {
g.attr("transform", d3.event.transform)
}
function ticked() {
//update circle positions each tick of the simulation
node
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
//update link positions
link
.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
text
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
</script>

Related

Using D3.js fill node circle with a base64 jpeg image that is not a URL

I am trying to use D3.js on an html page and fill in the node circles with a .jpeg image that is in base64 format and is ** not a URL **. I have found lots of examples with URLs and have made a working Network Force Graph with URLs but I need to be able to just pass base64 in my json file.
Can anyone help me? Thank you.
Here is the relevant snippet. d.img contains the base64 text.:
var images = node.append("svg:image")
.attr("xlink:href", "data:image/jpeg;base64," + function(d) { return "data:image/jpeg;base64," + d.img;})
//.attr("xlink:href", function(d) { return "data:image/jpeg;base64," + "data:image/jpeg;base64," + d.img;})
.attr("x", function(d) { return -25;})
.attr("y", function(d) { return -25;})
.attr("height", 50)
.attr("width", 50);
Here is the full javascript file:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<title>8.6 - Node-link diagrams</title>
<!-- Bootstrap Core CSS -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<!-- Custom CSS -->
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<nav class="navbar navbar-default"></nav>
<svg width="600" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
circleRadius = 30,
chargeStrength = -5000; // -50
var color = d3.scaleOrdinal(d3.schemeCategory10);
// Add "forces" to the simulation here
var simulation = d3.forceSimulation()
.force("center", d3.forceCenter(width / 2, height / 2))
.force("charge", d3.forceManyBody().strength(chargeStrength))
.force("collide", d3.forceCollide(circleRadius).strength(0.9))
.force("link", d3.forceLink().id(function(d) { return d.id; }));
// For each id.
d3.json("data/force2.json", function(error, graph) {
if (error) throw error;
console.log(graph);
// Add lines for every link in the dataset
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return
Math.sqrt(d.value); });
// Add circles for every node in the dataset
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter()
.append("g")
.attr("class", "node");
var circles = node.append("circle")
.attr("r", circleRadius)
.attr("fill", function(d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
// Add Supervisory Org Label
var text2 = node.append("text")
.style("text-anchor", "middle")
.attr("y", 40)
.text(function(d) {return d.org });
// Add id (name) label
var text = node.append("text")
.style("text-anchor", "middle")
.attr("y", 55)
.text(function(d) {return d.id });
var images = node.append("svg:image")
.attr("xlink:href", "data:image/jpeg;base64," +
function(d) { return "data:image/jpeg;base64," + d.img;})
//.attr("xlink:href", function(d) { return d.img;})
.attr("x", function(d) { return -25;})
.attr("y", function(d) { return -25;})
.attr("height", 50)
.attr("width", 50);
// make the image grow a little on mouse over and add the text
details on click
var setEvents = images
.on( 'mouseenter', function() {
// select element in current context
d3.select( this )
.transition()
.attr("x", function(d) { return -60;})
.attr("y", function(d) { return -60;})
.attr("height", 100)
.attr("width", 100);
})
// set back
.on( 'mouseleave', function() {
d3.select( this )
.transition()
.attr("x", function(d) { return -25;})
.attr("y", function(d) { return -25;})
.attr("height", 50)
.attr("width", 50);
});
// Basic tooltips
node.append("title")
.text(function(d) { return d.id; });
// Attach nodes to the simulation, add listener on the "tick" event
simulation
.nodes(graph.nodes)
.on("tick", ticked);
// Associate the lines with the "link" force
simulation.force("link")
.links(graph.links)
// Dynamically update the position of the nodes/links as time passes
function ticked() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
//node
//.attr("cx", function(d) { return d.x; })
// .attr("cy", function(d) { return d.y; });
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
var legend = svg.selectAll(".legend")
//.data(color.domain())
.data([1,2])
.enter().append("g")
.attr("class", "legend")
//.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 100)
.attr("y", height - 90)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return color(1) });
legend.append("rect")
.attr("x", width - 100)
.attr("y", height - 113)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return color(2) });
legend.append("text")
.attr("x", width - 78)
.attr("y", height - 80)
.attr("dy", ".35em")
.style("text-anchor", "begin")
.text("MatchUP")
//.text("MatchUPXXXXXXXXXXXXXXXXXXXX");
legend.append("text")
.attr("x", width - 78)
.attr("y", height - 103)
.attr("dy", ".35em")
.style("text-anchor", "begin")
.text("Connection")
});
// Change the value of alpha, so things move around when we drag a node
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.7).restart();
d.fx = d.x;
d.fy = d.y;
}
// Fix the position of the node that we are looking at
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
// Let the node do what it wants again once we've looked at it
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
</script>
</body>
the function must be:
function(d) { return "data:image/jpeg;base64," + d.img; }
otherwise you concatenate a string and a function which results in a string and you therefore losse the function.

D3 force-directed graph adding new nodes causes x & y to be NaN

When I click on a node, I want a new node to be added to it. They should both have labels (I'm trying to build a thesaurus visualization).
I'm very new to D3, so I apologize if you have to explain things in a bit more detail.
This is my code so far:
var width = 960;
var height = 500;
var force = d3.layout.force()
.gravity(0.05)
.distance(100)
.charge(-100)
.size([width, height])
.nodes([{ "name": "One", "group": 1 }])
.start();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var nodes = force.nodes();
var links = force.links();
var link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 10)
.on("mousedown", onClick);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(d => d.name);
force.on("tick", function() {
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 => {
// d.x & d.y are NaN for new nodes
return "translate(" + d.x + "," + d.y + ")";
});
});
restart();
function restart() {
node = node.data(nodes);
node.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 10)
.on("mousedown", onClick);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(d => d.name);
node.exit().remove();
link = link.data(links);
}
function onClick(clicked_node) {
console.log("click!");
console.log(clicked_node);
var new_node = { name: "Test", group: 2 };
nodes.push(new_node);
// Has x & y set to NaN after adding
links.push({ source: clicked_node, target: new_node });
restart();
}
As soon as I click on the first node, causing the node
{ name: "Test", group: 2 };
to be added, D3 throws errors within
node.attr("transform", d => {
// d.x & d.y are NaN for new nodes
return "translate(" + d.x + "," + d.y + ")";
});
because the d.x and d.y for this new node are NaN.
I tried setting them explicitly:
{ name: "Test", group: 2, x: clicked_node.y, y: clicked_node.y };
But I get the same error. In the inspector, when this node is added to the screen, the x and y values becomes the px and py values instead!
I don't understand why this happens.
You are missing one line of code. After you add your new node you need to restart the simulation for d3 to calculate it's position:
function restart() {
node = node.data(nodes);
node.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 10)
.on("mousedown", onClick);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(d => d.name);
node.exit().remove();
link = link.data(links);
force.start(); //<-- start simulation
}
Running code:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.17" data-semver="3.5.17" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
</head>
<body>
<script>
var width = 960;
var height = 500;
var force = d3.layout.force()
.gravity(0.05)
.distance(100)
.charge(-100)
.size([width, height])
.nodes([{ "name": "One", "group": 1 }])
.start();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var nodes = force.nodes();
var links = force.links();
var link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 10)
.on("mousedown", onClick);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(d => d.name);
force.on("tick", function() {
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 => {
// d.x & d.y are NaN for new nodes
return "translate(" + d.x + "," + d.y + ")";
});
});
restart();
function restart() {
node = node.data(nodes);
node.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 10)
.on("mousedown", onClick);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(d => d.name);
node.exit().remove();
link = link.data(links);
force.start();
}
function onClick(clicked_node) {
console.log("click!");
console.log(clicked_node);
var new_node = { name: "Test", group: 2 };
nodes.push(new_node);
// Has x & y set to NaN after adding
links.push({ source: clicked_node, target: new_node });
restart();
}
</script>
</body>
</html>

D3.js Force Direct Graph - png's in circles - making the images circular

I asked this question yesterday and got a great duplicate question answer - many thanks Gerardo.
The example used images with transparent backgrounds (see Opera and Chrome image below) and it works a treat however, I would like to provide square images which fit inside the circle.
I've tried the border radius in CSS and Bootstrap circular image but these don't work - probably because it is an tag not an tag.
Here is the rendered tag in case that is helpful.
<image xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="female1.png" class="circle-image" height="40" width="40" x="-20" y="-20"></image>
Would setting it up as a pattern help?
You can use a SVG pattern:
var defs = svg.append("defs");
defs.append('pattern')
.attr("id", "foo")
.attr("width", 1)
.attr("height", 1)
.append("svg:image")
.attr("xlink:href", "foo.jpg")
.attr("width", someValue)
.attr("height", someValue)
.attr("y", someValue)
.attr("x", someValue);
Then, in your circles:
.attr("fill", "url(#foo")
Here is a demo:
var width = 400;
var height = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var defs = svg.append("defs");
defs.append('pattern')
.attr("id", "dog")
.attr("width", 1)
.attr("height", 1)
.append("svg:image")
.attr("xlink:href", "http://cdn2-www.dogtime.com/assets/uploads/2010/12/senior-dog-2.jpg")
.attr("width", 100)
.attr("height", 100)
.attr("y", -20)
.attr("x", -20);
defs.append('pattern')
.attr("id", "cat")
.attr("width", 1)
.attr("height", 1)
.append("svg:image")
.attr("xlink:href", "https://s-media-cache-ak0.pinimg.com/736x/92/9d/3d/929d3d9f76f406b5ac6020323d2d32dc.jpg")
.attr("width", 120)
.attr("height", 120)
.attr("x", -30)
.attr("y", -10);
var nodes = [{id:"foo"},{id:"bar"}, {id:"baz"},{id:"barbaz"}];
var edges = [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 2
}, {
"source": 0,
"target": 3
}];
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().distance(80))
.force("charge", d3.forceManyBody().strength(-100))
.force("center", d3.forceCenter(width / 2, height / 2));
var links = svg.selectAll("foo")
.data(edges)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", 1);
var node = svg.selectAll("foo")
.data(nodes)
.enter()
.append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var nodeCircle = node.append("circle")
.attr("r", 30)
.attr("stroke", "gray")
.attr("stroke-width", "2px")
.attr("fill", function(d,i){
return i%2 === 0 ? "url(#dog)" : "url(#cat)"
});
var texts = node.append("text")
.style("fill", "black")
.attr("dx", 36)
.attr("dy", 8)
.text(function(d) {
return d.id;
});
simulation.nodes(nodes);
simulation.force("link")
.links(edges);
simulation.on("tick", function() {
links.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
})
node.attr("transform", (d) => "translate(" + d.x + "," + d.y + ")")
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

Making D3 like Force-Directed Graph with PNGs

I've been trying to make D3 like Force-Directed Graph (example: https://bl.ocks.org/mbostock/4062045) with PNGs (meaning the dots should be pictures).
Here is a visual idea:
A different approach I tried is to map each graphic element into parallax.js (http://matthew.wagerfield.com/parallax/) and draw a line between the center of each graphic element, but I do not know how to do that, just yet.
Since you didn't post your code to create the force, I'll provide a general answer. You may have to adapt it according to your specific code.
The basic idea here is appending group elements for each node, and appending both the circles and the images to those groups. Here I'm using 40x40 PNGs:
var node = svg.selectAll("foo")
.data(nodes)
.enter()
.append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var nodeCircle = node.append("circle")
.attr("r", 20)
.attr("stroke", "gray")
.attr("fill", "none");
var nodeImage = node.append("image")
.attr("xlink:href", d => d.image)
.attr("height", "40")
.attr("width", "40")
.attr("x", -20)
.attr("y", -20);
The url of each image is in the data array of the nodes:
var nodes = [{
"id": "foo",
"image": "https://icons.iconarchive.com/icons/google/chrome/48/Google-Chrome-icon.png"
}, {
"id": "bar",
"image": "https://icons.iconarchive.com/icons/carlosjj/mozilla/48/Firefox-icon.png"
}, {
"id": "baz",
"image": "https://icons.iconarchive.com/icons/johanchalibert/mac-osx-yosemite/48/safari-icon.png"
}, {
"id": "barbaz",
"image": "https://icons.iconarchive.com/icons/ampeross/smooth/48/Opera-icon.png"
}];
Here is a demo:
var width = 300;
var height = 200;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var nodes = [{
"id": "Chrome",
"image": "https://icons.iconarchive.com/icons/google/chrome/48/Google-Chrome-icon.png"
}, {
"id": "Firefox",
"image": "https://icons.iconarchive.com/icons/carlosjj/mozilla/48/Firefox-icon.png"
}, {
"id": "Safari",
"image": "https://icons.iconarchive.com/icons/johanchalibert/mac-osx-yosemite/48/safari-icon.png"
}, {
"id": "Opera",
"image": "https://icons.iconarchive.com/icons/ampeross/smooth/48/Opera-icon.png"
}];
var edges = [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 2
}, {
"source": 0,
"target": 3
}];
var simulation = d3.forceSimulation()
.force("link", d3.forceLink())
.force("charge", d3.forceManyBody().strength(-1000))
.force("center", d3.forceCenter(width / 2, height / 2));
var links = svg.selectAll("foo")
.data(edges)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", 1);
var color = d3.scaleOrdinal(d3.schemeCategory20);
var node = svg.selectAll("foo")
.data(nodes)
.enter()
.append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var nodeCircle = node.append("circle")
.attr("r", 20)
.attr("stroke", "gray")
.attr("stroke-width", "2px")
.attr("fill", "white");
var nodeImage = node.append("image")
.attr("xlink:href", d => d.image)
.attr("height", "40")
.attr("width", "40")
.attr("x", -20)
.attr("y", -20)
var texts = node.append("text")
.style("fill", "black")
.attr("dx", 20)
.attr("dy", 8)
.text(function(d) {
return d.id;
});
simulation.nodes(nodes);
simulation.force("link")
.links(edges);
simulation.on("tick", function() {
links.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
})
node.attr("transform", (d) => "translate(" + d.x + "," + d.y + ")")
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

Trying to display circle and text by nesting in g element, failing. what is wrong?

I want to display one <circle> and <text> for each node. My code looks like this, having added the suggested code from the answer below. Please note the different
var width = 960,
height = 500;
var color = d3.scale.category10();
var nodes = [],
links = [];
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.charge(-250)
.linkDistance(25)
.size([width, height])
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var node = svg.selectAll(".node")
.data(force.nodes(), function(d) { return d.id;}),
link = svg.selectAll(".link");
var text=svg.selectAll("text") //simply add text to svg
.data(force.nodes())
.enter()
.append("text")
.attr("class", "nodeText")
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "red");
function start() {
link = link.data(force.links(), function(d) { return d.source.id + "-" + d.target.id; });
link.enter().insert("line", ".node")
.attr("class", function(d) { return "link " + d.edgeType; })
.attr("id", function(d) { return d.source.id + "-" + d.target.id; });
link.exit().remove();
v1: <line>s exist and are displayed, no <circle>s or <text> exist
var g = node.enter().append("g");
g.append("circle")
.attr("class", function(d) { return "node " + d.id; })
.attr("id", function(d) { return d.id; })
.attr("r", 8)
.on("click", nodeClick);
g.append("text")
.text(function(d) {return d.id; });
/v1
v2: <line>s and <circle>s exist and are displayed. <text>s exist within <circle>s but aren't displayed
node = node.data(force.nodes(), function(d) { return d.id;});
node.enter()
.append("circle")
.attr("class", function(d) { return "node " + d.id; })
.attr("id", function(d) { return d.id; })
.attr("r", 8)
.on("click", nodeClick);
node.append("text")
.text(function(d) {return d.id; });
/v2
node.exit().remove();
force.start();
}
function nodeClick() {
var node_id = event.target.id;
handleClick(node_id, "node");
}
function tick() {
text.attr("dx", function(d) { return d.x+5; })
.attr("dy", function(d) { return d.y+5; })
.text(function(d){return d.id});
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
}
Simply add text element as following in your js
var text=svg.selectAll("text") //simply add text to svg
.data(Your_nodes_array)
.enter()
.append("text")
.attr("class", "nodeText")
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "red");
And inside tick do this :
text.attr("dx", function(d) { return d.x+5;}) //to keep it away from node
.attr("dy", function(d) { return d.y+5; })
.text(function(d){return d.id});
This will solve circle and text problems as this time we are adding text directly now

Categories

Resources