[ Launch: Tributary inlet ] 5718230 by panamantis
-
-
Save panamantis/5718230 to your computer and use it in GitHub Desktop.
Tributary inlet
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"description":"Tributary inlet","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"readme.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"d3.layout.force3d.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"index.html":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
// D3.layout.force3d.js | |
// (C) 2012 ziggy.jonsson.nyc@gmail.com | |
// BSD license (http://opensource.org/licenses/BSD-3-Clause) | |
d3.layout.force3d = function() { | |
var forceXY = d3.layout.force() | |
,forceZ = d3.layout.force() | |
,zNodes = {} | |
,zLinks = {} | |
,nodeID = 1 | |
,linkID = 1 | |
,tickFunction = Object | |
var force3d = {} | |
Object.keys(forceXY).forEach(function(d) { | |
force3d[d] = function() { | |
var result = forceXY[d].apply(this,arguments) | |
if (d !="nodes" && d!="links") forceZ[d].apply(this,arguments) | |
return (result == forceXY) ? force3d : result | |
} | |
}) | |
force3d.on = function(name,fn) { | |
tickFunction = fn | |
return force3d | |
} | |
forceXY.on("tick",function() { | |
// Refresh zNodes add new, delete removed | |
var _zNodes = {} | |
forceXY.nodes().forEach(function(d,i) { | |
if (!d.id) d.id = nodeID++ | |
_zNodes[d.id] = zNodes[d.id] || {x:d.z,px:d.z,py:d.z,y:d.z,id:d.id} | |
d.z = _zNodes[d.id].x | |
}) | |
zNodes = _zNodes | |
// Refresh zLinks add new, delete removed | |
var _zLinks = {} | |
forceXY.links().forEach(function(d) { | |
var nytt = false | |
if (!d.linkID) { d.linkID = linkID++;nytt=true} | |
_zLinks[d.linkID] = zLinks[d.linkID] || {target:zNodes[d.target.id],source:zNodes[d.source.id]} | |
}) | |
zLinks = _zLinks | |
// Update the nodes/links in forceZ | |
forceZ.nodes(d3.values(zNodes)) | |
forceZ.links(d3.values(zLinks)) | |
forceZ.start() // Need to kick forceZ so we don't lose the update mechanism | |
// And run the user defined function, if defined | |
tickFunction() | |
}) | |
// Expose the sub-forces for debugging purposes | |
force3d.xy = forceXY | |
force3d.z = forceZ | |
return force3d | |
} | |
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<script src="http://d3js.org/d3.v2.js?2.9.1"></script> | |
<script type="text/javascript" src="http://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="http://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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment