Skip to content

Instantly share code, notes, and snippets.

@tingletech
Created April 21, 2011 02:03
Show Gist options
  • Save tingletech/933535 to your computer and use it in GitHub Desktop.
Save tingletech/933535 to your computer and use it in GitHub Desktop.
chaotic graph visualization
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>arbor.js project template</title>
<link rel="stylesheet" href="style.css" type="text/css">
</head>
<body>
<canvas id="viewport" width="800" height="600"></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<!-- run from the original source files: -->
<!-- <script src="../../src/etc.js"></script>
<script src="../../src/kernel.js"></script>
<script src="../../src/graphics/colors.js"></script>
<script src="../../src/graphics/primitives.js"></script>
<script src="../../src/graphics/graphics.js"></script>
<script src="../../src/tween/easing.js"></script>
<script src="../../src/tween/tween.js"></script>
<script src="../../src/physics/atoms.js"></script>
<script src="../../src/physics/physics.js"></script>
<script src="../../src/physics/system.js"></script>
<script src="../../src/dev.js"></script> -->
<!-- run from the minified library file: -->
<script src="../../lib/arbor.js"></script>
<script src="main.js"></script>
</body>
</html>
//
// main.js
//
// A project template for using arbor.js
//
(function($){
var Renderer = function(canvas){
var canvas = $(canvas).get(0)
var ctx = canvas.getContext("2d");
var particleSystem
var that = {
init:function(system){
//
// the particle system will call the init function once, right before the
// first frame is to be drawn. it's a good place to set up the canvas and
// to pass the canvas size to the particle system
//
// save a reference to the particle system for use in the .redraw() loop
particleSystem = system
// inform the system of the screen dimensions so it can map coords for us.
// if the canvas is ever resized, screenSize should be called again with
// the new dimensions
particleSystem.screenSize(canvas.width, canvas.height)
particleSystem.screenPadding(80) // leave an extra 80px of whitespace per side
// set up some event handlers to allow for node-dragging
that.initMouseHandling()
},
redraw:function(){
//
// redraw will be called repeatedly during the run whenever the node positions
// change. the new positions for the nodes can be accessed by looking at the
// .p attribute of a given node. however the p.x & p.y values are in the coordinates
// of the particle system rather than the screen. you can either map them to
// the screen yourself, or use the convenience iterators .eachNode (and .eachEdge)
// which allow you to step through the actual node objects but also pass an
// x,y point in the screen's coordinate system
//
ctx.fillStyle = "white"
ctx.fillRect(0,0, canvas.width, canvas.height)
particleSystem.eachEdge(function(edge, pt1, pt2){
// edge: {source:Node, target:Node, length:#, data:{}}
// pt1: {x:#, y:#} source position in screen coords
// pt2: {x:#, y:#} target position in screen coords
// draw a line from pt1 to pt2
ctx.strokeStyle = "rgba(0,0,0, .333)"
ctx.lineWidth = 1
ctx.beginPath()
ctx.moveTo(pt1.x, pt1.y)
ctx.lineTo(pt2.x, pt2.y)
ctx.stroke()
})
particleSystem.eachNode(function(node, pt){
// node: {mass:#, p:{x,y}, name:"", data:{}}
// pt: {x:#, y:#} node position in screen coords
// determine the box size and round off the coords if we'll be
// drawing a text label (awful alignment jitter otherwise...)
var w = ctx.measureText(node.name||"").width + 6
var label = node.name
if (!(label||"").match(/^[ \t]*$/)){
pt.x = Math.floor(pt.x)
pt.y = Math.floor(pt.y)
}else{
label = null
}
// clear any edges below the text label
// ctx.fillStyle = 'rgba(255,255,255,.6)'
// ctx.fillRect(pt.x-w/2, pt.y-7, w,14)
ctx.clearRect(pt.x-w/2, pt.y-7, w,14)
// draw the text
if (label){
ctx.font = "bold 11px Arial"
ctx.textAlign = "center"
// if (node.data.region) ctx.fillStyle = palette[node.data.region]
// else ctx.fillStyle = "#888888"
ctx.fillStyle = "#888888"
// ctx.fillText(label||"", pt.x, pt.y+4)
ctx.fillText(label||"", pt.x, pt.y+4)
}
})
},
initMouseHandling:function(){
// no-nonsense drag and drop (thanks springy.js)
var dragged = null;
// set up a handler object that will initially listen for mousedowns then
// for moves and mouseups while dragging
var handler = {
clicked:function(e){
var pos = $(canvas).offset();
_mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
dragged = particleSystem.nearest(_mouseP);
if (dragged && dragged.node !== null){
// while we're dragging, don't let physics move the node
dragged.node.fixed = true
}
$(canvas).bind('mousemove', handler.dragged)
$(window).bind('mouseup', handler.dropped)
return false
},
dragged:function(e){
var pos = $(canvas).offset();
var s = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
if (dragged && dragged.node !== null){
var p = particleSystem.fromScreen(s)
dragged.node.p = p
}
return false
},
dropped:function(e){
if (dragged===null || dragged.node===undefined) return
if (dragged.node !== null) dragged.node.fixed = false
dragged.node.tempMass = 1000
dragged = null
$(canvas).unbind('mousemove', handler.dragged)
$(window).unbind('mouseup', handler.dropped)
_mouseP = null
return false
}
}
// start listening
$(canvas).mousedown(handler.clicked);
},
}
return that
}
$(document).ready(function(){
var sys = arbor.ParticleSystem( { repelsion: 1, stiffness: 6000, friction: 50 } ) // create the system with sensible repulsion/stiffness/friction
sys.parameters({gravity:true}) // use center-gravity to make the graph settle nicely (ymmv)
sys.renderer = Renderer("#viewport") // our newly created renderer will have its .init() method called shortly by sys...
// add some nodes to the graph and watch it go...
associatedWith = { }
correspondedWith = { }
indicesUrl = 'http://archive1.village.virginia.edu:8080/rex/snac/indices/name-idx?key=identity&value='
// identity = encodeURIComponent("Sierra Club.")
identity = "Eisenhower, Dwight D. (Dwight David), 1890-1969."
// look up node id
$.getJSON( indicesUrl + encodeURIComponent(identity) , function(data) {
nodeId = data.results[0]._id
edges = 'http://archive1.village.virginia.edu:8080/rex/snac/vertices/' + nodeId + '/inE'
// nested inside for scope... do a second request to grab the edges
$.getJSON(edges, function(data) {
arr = data.results // loop through rexster results array
for(var i=0,len=arr.length; value=arr[i], i<len; i++) {
sys.addEdge(value.from_name, value.to_name, { arcrole: value._label });
}
});
})
})
})(this.jQuery)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment