I am trying to make a graph, where certain nodes should be on the left side, and certain nodes should be on the right side from the "genesis node" which should be in the center of my svg.
Setting up the force:
So at the end it looks like this:
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;}).distance(60).strength(1))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
Setting up the nodes:
I have also tried setting the attr x
and y
, instead of cx
and cy
, but nothing changes. xCenter
and yCenter
are the center of the svg where the graph is displayed.
node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node");
node.append("circle")
.attr("r", 6)
.attr("cx", function (d) {
return colors(d.position*20 + xCenter);})
.attr("cy", function (d) {return colors(yCenter);})
.style("fill", function (d) {return colors(d.group);})
Updating the simulation
function ticked() {
node
.attr("transform", function (d) {
return "translate(" + d.x + ", " + d.y + ")";});
}
I have also tried this, but not luck:
function ticked() {
node
.attr("cx", function(d) { return d.cx; })
.attr("cy", function(d) { return d.cy; });
}
This is what I get :(
And this is more what I was looking for (I can set it up by dragging myself I just want it to appear like this directly)
Data source structure: The position 0 means in the center, negative positions mean to go to the left, positive positions mean to go to the right
{
"graphNodes": [
{
"id": "Q20514253",
"label": "label",
"description": "description",
"group": 0,
"position": 0
}],
"graphLinks": [
{
"source": "Q8513",
"target": "Q20514253",
"type": "instanceOf"
}],
}
=============================== EDIT ==================================
POSITION CALCULATION:
Each node has a position number, negative means to the left, positive means to the right. 1 level to the left is -1, 2 levels to the left is -2. 1 level to the right is 1, 2 levels to the right is 2.
X position is like this: X = d.position*20 + xCenter // so each level is 20 pixeles apart
Y position I just put = yCenter, so they are all vertically centered, and then I hoped because the nodes where charged to repel each other they would distribute evenly and vertically
Full working code:
var nodeDescription = document.querySelector(".node-description")
var colors = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;
svg.append('defs').append('marker')
.attrs({'id':'arrowhead',
'viewBox':'-0 -5 10 10',
'refX':13,
'refY':0,
'orient':'auto',
'markerWidth':13,
'markerHeight':8,
'xoverflow':'visible'})
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
.attr('fill', '#999')
.style('stroke','none');
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {return d.id;}).distance(60).strength(1))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
function update(links, nodes) {
var graphPlaceholder = document.querySelector(".graph-placeholder")
width = graphPlaceholder.offsetWidth
var xCenter = width/2
height = graphPlaceholder.offsetHeight
var yCenter = height/2
svg
.attr("width", width)
.attr("height", height)
simulation.force("center", d3.forceCenter(xCenter, yCenter));
link = svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link")
.attr('marker-end','url(#arrowhead)')
link.append("title")
.text(function (d) {return d.type;});
edgepaths = svg.selectAll(".edgepath")
.data(links)
.enter()
.append('path')
.attrs({
'class': 'edgepath',
'fill-opacity': 0,
'stroke-opacity': 0,
'id': function (d, i) {return 'edgepath' + i}
})
.style("pointer-events", "none");
edgelabels = svg.selectAll(".edgelabel")
.data(links)
.enter()
.append('text')
.style("pointer-events", "none")
.attrs({
'class': 'edgelabel',
'id': function (d, i) {return 'edgelabel' + i},
'font-size': 10,
'fill': '#aaa'
});
edgelabels.append('textPath')
.attr('xlink:href', function (d, i) {return '#edgepath' + i})
.style("text-anchor", "middle")
.style("pointer-events", "none")
.attr("startOffset", "50%")
.text(function (d) {return d.type});
node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
//.on("end", dragended)
).on("click", function(d){
nodeDescription.innerHTML = d.label + ": " + d.description;
});
node.append("circle")
.attr("r", 6)
.attr("x", function (d) {return colors(d.position*20 + xCenter);})
.attr("y", function (d) {return colors(yCenter);})
.style("fill", function (d) {return colors(d.group);})
node.append("title")
.text(function (d) {return d.id;});
node.append("text")
.attr("dy", -9)
.text(function (d) {return d.label;});
simulation
.nodes(nodes)
.on("tick", ticked);
simulation.force("link")
.links(links);
}
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("transform", function (d) {return "translate(" + d.x + ", " + d.y + ")";});
edgepaths.attr('d', function (d) {
return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
});
edgelabels.attr('transform', function (d) {
if (d.target.x < d.source.x) {
var bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
}
else {
return 'rotate(0)';
}
});
}
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;
}
Full dataset
{
"graphNodes": [
{
"id": "http://www.wikidata.org/entity/Q395",
"label": "mathematics",
"description": "field of study (numbers, quantity, structure, relationships, space, change)",
"group": 0,
"position": 0
},
{
"id": "http://www.wikidata.org/entity/Q41511",
"label": "universal language",
"description": "hypothetical language that is supposed to have been spoken by all or most of the world's population",
"group": 6,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q4671286",
"label": "academic major",
"description": "academic discipline to which a student formally commits",
"group": 6,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q11862829",
"label": "academic discipline",
"description": "concentration in one academic field of study or profession",
"group": 6,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q475023",
"label": "exact science",
"description": "",
"group": 9,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q816264",
"label": "formal science",
"description": "disciplines concerned with formal systems, such as logic, mathematics, and game theory",
"group": 9,
"position": -1
},
{
"id": "Mathematics",
"label": "Mathematics",
"description": "",
"group": 13,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q30125896",
"label": "scientific hypothesis",
"description": "idea that proposes a tentative explanation about a phenomenon or a narrow set of phenomena observed in the natural world (primary features of a scientific hypothesis: falsifiability, testability)",
"group": 6,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q2623733",
"label": "fictional language",
"description": "language in fictional stories",
"group": 9,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q1047113",
"label": "specialty",
"description": "field limited to a specific area of knowledge",
"group": 9,
"position": -2
},
{
"id": "Academic disciplines",
"label": "Academic disciplines",
"description": "",
"group": 13,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q2465832",
"label": "branch of science",
"description": "field or discipline of science",
"group": 6,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q336",
"label": "science",
"description": "study and knowledge",
"group": 9,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q3968",
"label": "algebra",
"description": "topic in mathematics and definition is Algebra uses letters (like x or y) or other symbols in place of values, and plays with them using special rules.",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q8087",
"label": "geometry",
"description": "branch of mathematics that measures the shape, size and position of objects",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q12479",
"label": "number theory",
"description": "branch of pure mathematics devoted primarily to the study of the integers",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q12482",
"label": "set theory",
"description": "branch of mathematics that studies sets, which are collections of objects",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q12483",
"label": "statistics",
"description": "study of the collection, organization, analysis, interpretation, and presentation of data",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q42989",
"label": "topology",
"description": "subfield of mathematics",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q131476",
"label": "graph theory",
"description": "study of graphs, which are mathematical structures used to model pairwise relations between objects",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q149972",
"label": "calculus",
"description": "branch of mathematics",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q217413",
"label": "category theory",
"description": "logic and mathematics",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q5862903",
"label": "probability theory",
"description": "branch of mathematics concerned with probability",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q1192971",
"label": "network theory",
"description": "study of graphs as a representation of either symmetric relations or, more generally, of asymmetric relations between discrete objects",
"group": 1,
"position": 2
},
{
"id": "http://www.wikidata.org/entity/Q149999",
"label": "differential calculus",
"description": "subfield of calculus",
"group": 1,
"position": 2
},
{
"id": "http://www.wikidata.org/entity/Q150008",
"label": "integral calculus",
"description": "subfield of calculus",
"group": 1,
"position": 2
}
],
"graphLinks": [
{
"source": "http://www.wikidata.org/entity/Q41511",
"target": "http://www.wikidata.org/entity/Q395",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q4671286",
"target": "http://www.wikidata.org/entity/Q395",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q11862829",
"target": "http://www.wikidata.org/entity/Q395",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q475023",
"target": "http://www.wikidata.org/entity/Q395",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q816264",
"target": "http://www.wikidata.org/entity/Q395",
"type": "subclassOf"
},
{
"source": "Mathematics",
"target": "http://www.wikidata.org/entity/Q395",
"type": "CommonCategory"
},
{
"source": "http://www.wikidata.org/entity/Q30125896",
"target": "http://www.wikidata.org/entity/Q41511",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q2623733",
"target": "http://www.wikidata.org/entity/Q41511",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q11862829",
"target": "http://www.wikidata.org/entity/Q4671286",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q1047113",
"target": "http://www.wikidata.org/entity/Q11862829",
"type": "subclassOf"
},
{
"source": "Academic disciplines",
"target": "http://www.wikidata.org/entity/Q11862829",
"type": "CommonCategory"
},
{
"source": "http://www.wikidata.org/entity/Q2465832",
"target": "http://www.wikidata.org/entity/Q475023",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q336",
"target": "http://www.wikidata.org/entity/Q475023",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q2465832",
"target": "http://www.wikidata.org/entity/Q816264",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q475023",
"target": "http://www.wikidata.org/entity/Q816264",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q3968",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q8087",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q12479",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q12482",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q12483",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q42989",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q131476",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q149972",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q217413",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q5862903",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q131476",
"target": "http://www.wikidata.org/entity/Q1192971",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q149972",
"target": "http://www.wikidata.org/entity/Q149999",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q149972",
"target": "http://www.wikidata.org/entity/Q150008",
"type": "hasPart"
}
],
============================= EDIT 2 ===============================
I managed to get something very weird
There are a number of things wrong with your code
update()
function with the links and nodesdo not assign colors to circle
x
and y
coords
node.append("circle")
.attr("r", 6)
.attr("x", function (d) {return colors(d.position*20 + xCenter);})
.attr("y", function (d) {return colors(yCenter);})
.style("fill", function (d) {return colors(d.group);})
and setting these coords have no influence on the force simulation even if they are the correct coords
you do not have a dragEnd. The simulation runs very long after a drag or a click before it stops. The alpaTarget
is above alphaMin
so it will "never" stop. Eventually it will stop for some reason, maybe it detects if there is any significant position change. I have uncommented the on-dargenden line and added the function to set an alphaTarget
of 0.
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
//d.fx = nodeFixX(d); // snap to its target position
d.fx = null; // or let the force figure it out
d.fy = null;
}
added the missing style
<style>
.link { stroke: steelblue;}
</style>
and HTML
<div class="node-description"></div>
<svg width="800" height="600"></svg>
why do you set the forceCenter()
twice?
because I do not have the HTML you use I disabled all regarding graphPlaceholder
The solution to your problem is
forceCenter()
forceposition=0
node to the center positionforceX()
to pull the nodes to a specific column(0,0)
// or let the force figure it out
. I find using the force (as set in the complete example) reordering the nodes a bit easierHere is the main modification
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {return d.id;}).distance(columnXFactor)) // .strength(0.2)
.force("charge", d3.forceManyBody().strength(-60))
.force("columnX", d3.forceX(n => n.position*columnXFactor + xCenter)) //.strength(0.05) // or let the force figure it out
// .force("center", d3.forceCenter(xCenter, yCenter))
;
// force 1 node in the center
var pos0Node = data.graphNodes.filter(n => n.position === 0)[0];
pos0Node.fx = xCenter;
pos0Node.fy = yCenter;
function nodeFixX(n) {
return n.position*columnXFactor + xCenter;
}
data.graphNodes.forEach(n => {
//n.fx = nodeFixX(n); // snap to its target position
n.x = nodeFixX(n); // or let the force figure it out
n.y = yCenter;
});
update(data.graphLinks, data.graphNodes);
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Force Mathematics</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<style>
.link { stroke: steelblue;}
</style>
</head>
<body>
<div class="node-description"></div>
<svg width="800" height="600"></svg>
<script>
var data =
{
"graphNodes": [
{
"id": "http://www.wikidata.org/entity/Q395",
"label": "mathematics",
"description": "field of study (numbers, quantity, structure, relationships, space, change)",
"group": 0,
"position": 0
},
{
"id": "http://www.wikidata.org/entity/Q41511",
"label": "universal language",
"description": "hypothetical language that is supposed to have been spoken by all or most of the world's population",
"group": 6,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q4671286",
"label": "academic major",
"description": "academic discipline to which a student formally commits",
"group": 6,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q11862829",
"label": "academic discipline",
"description": "concentration in one academic field of study or profession",
"group": 6,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q475023",
"label": "exact science",
"description": "",
"group": 9,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q816264",
"label": "formal science",
"description": "disciplines concerned with formal systems, such as logic, mathematics, and game theory",
"group": 9,
"position": -1
},
{
"id": "Mathematics",
"label": "Mathematics",
"description": "",
"group": 13,
"position": -1
},
{
"id": "http://www.wikidata.org/entity/Q30125896",
"label": "scientific hypothesis",
"description": "idea that proposes a tentative explanation about a phenomenon or a narrow set of phenomena observed in the natural world (primary features of a scientific hypothesis: falsifiability, testability)",
"group": 6,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q2623733",
"label": "fictional language",
"description": "language in fictional stories",
"group": 9,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q1047113",
"label": "specialty",
"description": "field limited to a specific area of knowledge",
"group": 9,
"position": -2
},
{
"id": "Academic disciplines",
"label": "Academic disciplines",
"description": "",
"group": 13,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q2465832",
"label": "branch of science",
"description": "field or discipline of science",
"group": 6,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q336",
"label": "science",
"description": "study and knowledge",
"group": 9,
"position": -2
},
{
"id": "http://www.wikidata.org/entity/Q3968",
"label": "algebra",
"description": "topic in mathematics and definition is Algebra uses letters (like x or y) or other symbols in place of values, and plays with them using special rules.",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q8087",
"label": "geometry",
"description": "branch of mathematics that measures the shape, size and position of objects",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q12479",
"label": "number theory",
"description": "branch of pure mathematics devoted primarily to the study of the integers",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q12482",
"label": "set theory",
"description": "branch of mathematics that studies sets, which are collections of objects",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q12483",
"label": "statistics",
"description": "study of the collection, organization, analysis, interpretation, and presentation of data",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q42989",
"label": "topology",
"description": "subfield of mathematics",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q131476",
"label": "graph theory",
"description": "study of graphs, which are mathematical structures used to model pairwise relations between objects",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q149972",
"label": "calculus",
"description": "branch of mathematics",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q217413",
"label": "category theory",
"description": "logic and mathematics",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q5862903",
"label": "probability theory",
"description": "branch of mathematics concerned with probability",
"group": 1,
"position": 1
},
{
"id": "http://www.wikidata.org/entity/Q1192971",
"label": "network theory",
"description": "study of graphs as a representation of either symmetric relations or, more generally, of asymmetric relations between discrete objects",
"group": 1,
"position": 2
},
{
"id": "http://www.wikidata.org/entity/Q149999",
"label": "differential calculus",
"description": "subfield of calculus",
"group": 1,
"position": 2
},
{
"id": "http://www.wikidata.org/entity/Q150008",
"label": "integral calculus",
"description": "subfield of calculus",
"group": 1,
"position": 2
}
],
"graphLinks": [
{
"source": "http://www.wikidata.org/entity/Q41511",
"target": "http://www.wikidata.org/entity/Q395",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q4671286",
"target": "http://www.wikidata.org/entity/Q395",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q11862829",
"target": "http://www.wikidata.org/entity/Q395",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q475023",
"target": "http://www.wikidata.org/entity/Q395",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q816264",
"target": "http://www.wikidata.org/entity/Q395",
"type": "subclassOf"
},
{
"source": "Mathematics",
"target": "http://www.wikidata.org/entity/Q395",
"type": "CommonCategory"
},
{
"source": "http://www.wikidata.org/entity/Q30125896",
"target": "http://www.wikidata.org/entity/Q41511",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q2623733",
"target": "http://www.wikidata.org/entity/Q41511",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q11862829",
"target": "http://www.wikidata.org/entity/Q4671286",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q1047113",
"target": "http://www.wikidata.org/entity/Q11862829",
"type": "subclassOf"
},
{
"source": "Academic disciplines",
"target": "http://www.wikidata.org/entity/Q11862829",
"type": "CommonCategory"
},
{
"source": "http://www.wikidata.org/entity/Q2465832",
"target": "http://www.wikidata.org/entity/Q475023",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q336",
"target": "http://www.wikidata.org/entity/Q475023",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q2465832",
"target": "http://www.wikidata.org/entity/Q816264",
"type": "instanceOf"
},
{
"source": "http://www.wikidata.org/entity/Q475023",
"target": "http://www.wikidata.org/entity/Q816264",
"type": "subclassOf"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q3968",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q8087",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q12479",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q12482",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q12483",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q42989",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q131476",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q149972",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q217413",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q395",
"target": "http://www.wikidata.org/entity/Q5862903",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q131476",
"target": "http://www.wikidata.org/entity/Q1192971",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q149972",
"target": "http://www.wikidata.org/entity/Q149999",
"type": "hasPart"
},
{
"source": "http://www.wikidata.org/entity/Q149972",
"target": "http://www.wikidata.org/entity/Q150008",
"type": "hasPart"
}
]
};
var nodeDescription = document.querySelector(".node-description")
var colors = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;
var xCenter = width*0.5;
var yCenter = height*0.5;
var columnXFactor = 100;
svg.append('defs').append('marker')
.attrs({'id':'arrowhead',
'viewBox':'-0 -5 10 10',
'refX':13,
'refY':0,
'orient':'auto',
'markerWidth':13,
'markerHeight':8,
'xoverflow':'visible'})
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
.attr('fill', '#999')
.style('stroke','none');
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {return d.id;}).distance(columnXFactor)) // .strength(0.2)
.force("charge", d3.forceManyBody().strength(-60))
.force("columnX", d3.forceX(n => n.position*columnXFactor + xCenter)) //.strength(0.05) // or let the force figure it out
// .force("center", d3.forceCenter(xCenter, yCenter))
;
// force 1 node in the center
var pos0Node = data.graphNodes.filter(n => n.position === 0)[0];
pos0Node.fx = xCenter;
pos0Node.fy = yCenter;
function nodeFixX(n) {
return n.position*columnXFactor + xCenter;
}
data.graphNodes.forEach(n => {
//n.fx = nodeFixX(n); // snap to its target position
n.x = nodeFixX(n); // or let the force figure it out
n.y = yCenter;
});
update(data.graphLinks, data.graphNodes);
function update(links, nodes) {
// var graphPlaceholder = document.querySelector(".graph-placeholder")
// width = graphPlaceholder.offsetWidth
// height = graphPlaceholder.offsetHeight
// svg
// .attr("width", width)
// .attr("height", height)
// simulation.force("center", d3.forceCenter(xCenter, yCenter));
link = svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link")
.attr('marker-end','url(#arrowhead)')
link.append("title")
.text(function (d) {return d.type;});
edgepaths = svg.selectAll(".edgepath")
.data(links)
.enter()
.append('path')
.attrs({
'class': 'edgepath',
'fill-opacity': 0,
'stroke-opacity': 0,
'id': function (d, i) {return 'edgepath' + i}
})
.style("pointer-events", "none");
edgelabels = svg.selectAll(".edgelabel")
.data(links)
.enter()
.append('text')
.style("pointer-events", "none")
.attrs({
'class': 'edgelabel',
'id': function (d, i) {return 'edgelabel' + i},
'font-size': 10,
'fill': '#aaa'
});
edgelabels.append('textPath')
.attr('xlink:href', function (d, i) {return '#edgepath' + i})
.style("text-anchor", "middle")
.style("pointer-events", "none")
.attr("startOffset", "50%")
.text(function (d) {return d.type});
node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
).on("click", function(d){
nodeDescription.innerHTML = d.label + ": " + d.description;
});
node.append("circle")
.attr("r", 6)
//.attr("x", 0) // d => colors(d.position*20 + xCenter)
//.attr("y", 0) // d => colors(yCenter)
.style("fill", function (d) {return colors(d.group);})
node.append("title")
.text(function (d) {return d.id;});
node.append("text")
.attr("dy", -9)
.text(function (d) {return d.label;});
//.text(function (d) {return '' + d.position + d.label;});
simulation
.nodes(nodes)
.on("tick", ticked);
simulation.force("link")
.links(links);
}
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("transform", function (d) {return "translate(" + d.x + ", " + d.y + ")";});
edgepaths.attr('d', function (d) {
return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
});
edgelabels.attr('transform', function (d) {
if (d.target.x < d.source.x) {
var bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
}
return 'rotate(0)';
});
}
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 = nodeFixX(d); // snap to its target position
d.fx = null; // or let the force figure it out
d.fy = null;
}
</script>
</body>
</html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With