This is a quick hack to be able to produce http://d3js.org force layout with a third dimension. I use two force layouts in combination, the first one for the x,y axis and the third one for the z axis (I enforce x=y at each step). Each chained action of the 3d force is then applied to both of the underlying forces. Finally I use X3DOM to render the visualization.
List of controls can be found here http://www.x3dom.org/?page_id=293
xxxxxxxxxx
<html>
<head>
<script src="https://d3js.org/d3.v2.js?2.9.1"></script>
<script type="text/javascript" src="https://x3dom.org/x3dom/example/x3dom.js"></script>
<script type="text/javascript" src="d3.layout.force3d.js"></script>
</head>
<body>
<script type="text/javascript">
// Create the x3d scene
d3.ns.prefix.x3da="https://www.web3d.org/specifications/x3d-namespace"
var x3d = d3.select("body")
.append("x3d:x3d")
.attr("height","500px")
.attr("width","960px")
var scene = x3d.append("x3d:scene")
// Define the 3d force
var force = d3.layout.force3d()
.nodes(data=[])
.links(links=[])
.size([50, 50])
.gravity(0.3)
.charge(-5)
function addBubble() {
data.push({x:Math.random()*50,y:Math.random()*50,z:Math.random()*50})
if (data.length > 100) return clearInterval(timer)
if (data.length == 1) return force.start()
var selected = Math.round(Math.random()*(data.length-2))
links.push({target:data[selected],source:data[data.length-1]})
force.start()
}
force.on("tick", function(e) {
// Select the nodes, add new as spheres
var datapoints=scene.selectAll(".datapoints").data(data)
datapoints.exit().remove() // Remove any excess datapoints, if needed
datapoints.enter() // Draw a box for each new datapoint
.append("x3d:transform")
.attr("class","datapoints")
.html("<shape><appearance><material diffuseColor='"+Math.random()+" "+Math.random()+" "+Math.random()+"'></appearance><sphere radius='0.2'></shape>")
// Relocate all based on new data
datapoints.attr("translation",function(d) { return x(d.x)+" "+y(d.y)+" "+z(d.z)})
scene.selectAll(".links").data(links)
.enter().append("x3d:shape").attr("class","links")
.html("<indexedlineset coordindex='0 1 ' ><coordinate point='"+Math.random()*3+" "+Math.random()*3+" "+Math.random()*3+" 0.987 1.431 -1.654' class='line'></coordinate></indexedlineset>").select(".line")
scene.selectAll(".line").attr("point",function(d) {
return x(d.target.x)+" "+y(d.target.y)+" "+z(d.target.z)+" "
+x(d.source.x)+" "+y(d.source.y)+" "+z(d.source.z)})
});
// set up the axes
var x = d3.scale.linear().domain([0, 100]).range([0, 10]),
y = d3.scale.linear().domain([0, 100]).range([0, 10]),
z = d3.scale.linear().domain([0, 100]).range([0, 10]);
// Old axis routine... included to have bearings on the 3d space
function plotAxis(scale,location,size,numTicks) {
// the axis line
scene.append("x3d:transform")
.attr("translation",location.replace("D",(scale.range()[0]+scale.range()[1])/2))
.append("x3d:shape")
.append("x3d:box")
.attr("size",location.replace(/0/g,size).replace("D",scale.range()[1]))
// ticks along the axis
ticks=scene.selectAll("abcd").data(scale.ticks(numTicks))
.enter()
.append("x3d:transform")
.attr("translation", function(d) { return location.replace("D",scale(d))})
ticks
.append("x3d:shape")
.append("x3d:box")
.attr("size",size*3+" "+size*3+" "+size*3);
ticks
.append("x3d:billboard").append("x3d:shape")
.html(function(d) { return "<text string='"+scale.tickFormat(10)(d)+"'><fontstyle size=25></text>"})
}
plotAxis(x,"D 0 0",0.01,10)
plotAxis(y,"0 D 0",0.01,10)
plotAxis(z,"0 0 D",0.01,10)
// Start making bubbgles and zoom out the viewport
timer = setInterval(addBubble,300)
setTimeout(function() {x3d[0][0].runtime.showAll()},500);
</SCRIPT>
</body>
Modified http://d3js.org/d3.v2.js?2.9.1 to a secure url
Modified http://x3dom.org/x3dom/example/x3dom.js to a secure url
https://d3js.org/d3.v2.js?2.9.1
https://x3dom.org/x3dom/example/x3dom.js