Skip to content

Instantly share code, notes, and snippets.

@cool-Blue
Last active June 12, 2016 06:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cool-Blue/9f49525e782491c8b68a to your computer and use it in GitHub Desktop.
Save cool-Blue/9f49525e782491c8b68a to your computer and use it in GitHub Desktop.
d3 fdg with font BBox positioning and sizing of nodes
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
svg {
outline: 1px solid #282f51;
pointer-events: all;
overflow: visible;
}
g.outline {
outline: 1px solid red;
}
#panel div {
display: inline-block;
margin: 0 .25em 3px 0;
}
#panel div div {
white-space: pre;
margin: 0 .25em 3px 0;
}
div#inputDiv {
white-space: normal;
display: inline-block;
}
.node {
cursor: default;
}
.content {
transform-origin: 50% 50%;
}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css">
</head>
<body>
<div id="panel">
<div id="inputDiv">
<input id="update" type="button" value="update">
</div>
<div id="wrapAlpha">alpha:<div id="alpha"></div></div><div id="fdg"></div>
</div>
<div id="viz"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://gitcdn.xyz/repo/cool-Blue/d3-lib/master/elapsedTime/elapsedTime/elapsed%20time%201.0.js"></script>
<script src="script-array-base.js"></script>
</body>
</html>
//debug panel/////////////////////////////////////////////////////////////////////////////
d3.select("#update").on("click", (function() {
var dataSet = false;
return function() {
refresh(dataSets[(dataSet = !dataSet, +dataSet)])
}
})());
var alpha = d3.select("#alpha").text("waiting..."),
cog = d3.select("#wrapAlpha").insert("i", "#fdg").classed("fa fa-cog fa-spin", true),
fdgInst = d3.select("#fdg");
elapsedTime = ElapsedTime("#panel", {margin: 0, padding: 0})
.message(function (id) {
return 'fps : ' + d3.format(" >8.3f")(1/this.aveLap())
});
elapsedTime.consoleOn = false;
//////////////////////////////////////////////////////////////////////////////////
var dataSets = [
{
"nodes": [
{"name": "node1", "content": "the first Node"},
{"name": "node2", "content": "node2"},
{"name": "node3", "content":{"fa": "fa/*-spin*/", text: "\uf013"}},
{"name": "node4", "content":{"fa": "fa/*-spin*/", text: "\uf1ce"}}
],
"edges": [
{"source": 2, "target": 0},
{"source": 2, "target": 1},
{"source": 2, "target": 3}
]
},
{
"nodes": [
{"name": "node1", "content": "node1"},
{"name": "node2", "content":{"fa": "fa/*-spin*/", text: "\uf1ce"}},
{"name": "node3", "content":{"fa": "fa/*-spin*/", text: "\uf013"}},
{"name": "node4", "content": "4"},
{"name": "node5", "content": "5"},
{"name": "node6", "content": "6"}
],
"edges": [
{"source": 2, "target": 0},
{"source": 2, "target": 1},
{"source": 2, "target": 3},
{"source": 2, "target": 4},
{"source": 2, "target": 5}
]
}
];
var refresh = (function(){
var instID = Date.now(),
height = 160,
width = 500,
force = d3.layout.force()
.size([width, height])
.charge(-1000)
.linkDistance(50)
.on("end", function(){cog.classed("fa-spin", false); elapsedTime.stop()})
.on("start", function(){cog.classed("fa-spin", true); elapsedTime.start()});
return function refresh(data) {
force
.nodes(data.nodes)
.links(data.edges)
.on("tick", (function(instID) {
return function(e) {
elapsedTime.mark();
alpha.text(d3.format(" >8.4f")(e.alpha));
fdgInst.text("fdg instance: " + instID);
lines.attr("x1", function(d) {
return d.source.x + d.source.cx + d.source.r;
}).attr("y1", function(d) {
return d.source.y + d.source.cy;
}).attr("x2", function(d) {
return d.target.x + d.target.cx;
}).attr("y2", function(d) {
return d.target.y + d.target.cy;
});
node.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")"
});
}
})(instID))
.start();
var svg = d3.select("body").selectAll("svg").data([data]);
svg.enter().append("svg")
.attr({height: height, width: width});
var lines = svg.selectAll(".links")
.data(linksData),
linesEnter = lines.enter()
.insert("line", d3.select("#nodes") ? "#nodes" : null)
.attr("class", "links")
.attr({stroke: "steelblue", "stroke-width": 3});
var nodes = svg.selectAll("#nodes").data(nodesData),
nodesEnter = nodes.enter().append("g")
.attr("id", "nodes"),
node = nodes.selectAll(".node")
.data(id),
newNode = node.enter().append("g")
.attr("class","node")
.call(force.drag);
newNode.append("text")
.attr({class: "content", fill: "steelblue"})
newNode.insert("circle", ".node .content");
var glyphs = node.select("text")
.each(function(d) {
var node = d3.select(this);
if(d.content.fa)
node.style({'font-family': 'FontAwesome', 'font-size': '32px', 'dominant-baseline': 'central'})
.classed(d.content.fa, true)
.text(d.content.text);
else
node.text(d.content)
.attr({"class": "content", style: null});
})
.call(getBB),
backGround = node.select("circle").each(function(d) {
d3.select(this).attr(makeCircleBB(d))
}).style({"fill": "red", opacity: 0.8});
(function(id){
//adjust the bounding box after the font loads
var count = 0;
d3.timer(function() {
console.log(id);
glyphs.call(getBB);
backGround.each(function(d) {
d3.select(this).attr(makeCircleBB(d))
});
return /*false || id != instID*/++count > 10; //needs to keep running due to webkit zoom bug
})
})(instID);
lines.exit().remove();
node.exit().remove();
function nodesData(d) {
return [d.nodes];
}
function linksData(d) {
return d.edges;
}
};
function getBB(selection) {
this.each(function(d) {
d.bb = this.getBBox();
})
}
function makeCircleBB(d, i, j) {
var bb = d.bb;
d.r = Math.max(bb.width, bb.height) / 2;
delete d.bb; //plug potential memory leak!
d.cy = bb.height / 2 + bb.y;
d.cx = bb.width / 2;
return {
r: d.r, cx: d.cx, cy: d.cy, height: bb.height, width: bb.width
}
}
function id(d) {
return d;
}
})();
refresh(dataSets[0]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment