//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]);