Created
August 16, 2013 22:44
-
-
Save cariaso/6254138 to your computer and use it in GitHub Desktop.
Protovis force directed graph. Zooming works well
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> | |
<meta charset="utf-8"> | |
<title>Protovis Graph</title> | |
<script type="text/javascript" src="http://cachedcommons.org/cache/jquery/1.4.2/javascripts/jquery-min.js"></script> | |
<script type="text/javascript" src="http://cachedcommons.org/cache/protovis/3.2.0/javascripts/protovis-min.js"></script> | |
<link rel="stylesheet" href="js.css"> | |
<script type="text/javascript"> | |
var buttonBarHeight = 30; | |
var redrawLag = 300; | |
var delay = (function(){ | |
var timer = 0; | |
return function(callback, ms){ | |
clearTimeout (timer); | |
timer = setTimeout(callback, ms); | |
}; | |
})(); | |
$(window).resize(function() { | |
delay(function(){ | |
$(".resizable").resize(); | |
}, redrawLag); | |
}); | |
$(document).ready(function() { | |
$("#chart").resize(function() { | |
vis.width($("#chart").width()); | |
vis.height($("#chart").height()-buttonBarHeight); | |
vis.render(); | |
return false; | |
} | |
) | |
}); | |
function dumpGraph(agraph) { | |
for (var oldidx in agraph.nodes) { | |
if (agraph.nodes[oldidx]) { | |
console.log(" name="+agraph.nodes[oldidx].nodeName+" is oldidx="+oldidx); | |
} else { | |
console.log(" hole at node#"+oldidx); | |
} | |
}; | |
for (var oldidx in agraph.links) { | |
if (agraph.links[oldidx]) { | |
console.log(" link "+oldidx+" :: "+agraph.links[oldidx].source+" to "+agraph.links[oldidx].target); | |
} else { | |
console.log(" hole at link#"+oldidx); | |
} | |
}; | |
} | |
function deleteSelected() { | |
// 2 pass | |
console.log("d was pressed. removing "+lastClicked.index + agraph.nodes[lastClicked.index].nodeName); | |
if (lastClicked) { | |
var numremoved = 0; | |
var removed = new Array(); | |
for (v in agraph.links) { | |
if ((agraph.links[v].source == lastClicked.index) || | |
(agraph.links[v].target == lastClicked.index)) { | |
//console.log("remove link #"+v+" :: "+agraph.nodes[agraph.links[v].source].nodeName + "--"+agraph.nodes[agraph.links[v].target].nodeName); | |
numremoved += 1; | |
agraph.links[v] = undefined; | |
removed.unshift(v); | |
} else if (agraph.links[v].source > lastClicked.index) { | |
//console.log("shifted link "+v+" source "+agraph.links[v].source+" -= "+numremoved); | |
agraph.links[v].source -= numremoved; | |
} else if (agraph.links[v].target > lastClicked.index) { | |
//console.log("shifted link "+v+" target "+agraph.links[v].target+" -= "+numremoved); | |
agraph.links[v].target -= numremoved; | |
} | |
} | |
for (v in removed) { | |
//console.log("removing link "+removed[v]); | |
agraph.links.splice(removed[v], 1); | |
} | |
//console.log("removing "+numremoved+" links and 1 node#"+lastClicked.index); | |
agraph.nodes.splice(lastClicked.index, 1); | |
//dumpGraph(agraph); | |
force.nodes(agraph.nodes); | |
force.links(agraph.links); | |
force.reset(); | |
vis.render(); | |
} | |
} | |
$(document).bind("keypress", "d", deleteSelected); | |
function resetGraph() { | |
for (v in agraph.nodes) { | |
agraph.nodes[v].x = NaN; | |
agraph.nodes[v].y = NaN; | |
agraph.nodes[v].px = NaN; | |
agraph.nodes[v].py = NaN; | |
} | |
force.reset().render() | |
} | |
function freezeGraph() { | |
for (v in agraph.nodes) { | |
d = agraph.nodes[v]; | |
if (d.fix) { | |
d.fix = undefined; | |
} else { | |
d.fix = new pv.Vector(d.x,d.y); | |
} | |
} | |
force.reset().render() | |
} | |
</script> <style type="text/css"> | |
body, html { | |
height: 100%; | |
margin: 0; | |
} | |
#chart { width: 100%; height: 100%; background: gray; border: 0px solid black;} | |
</style> | |
</head> | |
<body> | |
<div id="chart" class="resizable"> | |
<script type="text/javascript+protovis"> | |
var agraph = { | |
nodes:[ | |
{nodeName:"gs145", group:1, size:120, color:"#FFFFD0"}, | |
{nodeName:"rs12255372(T;T)", group:1, size:105, color:"#FF9090", gene:"TCF7L2"}, | |
{nodeName:"Breast cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"Prostate cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"Type-2 diabetes", group:2, size:20, color:"blue"}, | |
{nodeName:"rs6983267(G;G)", group:1, size:96, color:"#FF9090"}, | |
{nodeName:"23andMe/SNPs", group:2, size:20, color:"blue"}, | |
{nodeName:"Bladder cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"Cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"Colon cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"Colorectal cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"Coriell Personalized Medicine Collaborative", group:2, size:20, color:"blue"}, | |
{nodeName:"Liver cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"Lung cancer", group:2, size:20, color:"blue"}, | |
{nodeName:"rs2981582(T;T)", group:1, size:96, color:"#FF9090", gene:"FGFR2"}, | |
{nodeName:"gs192", group:1, size:93, color:"#FFFFD0"}, | |
{nodeName:"Homocystinuria", group:2, size:20, color:"blue"}, | |
{nodeName:"gs227", group:1, size:90, color:"#FFFFD0"}, | |
{nodeName:"Taste", group:2, size:20, color:"blue"}, | |
{nodeName:"rs3803662(T;T)", group:1, size:90, color:"#FF9090", gene:"LOC643714"}, | |
{nodeName:"rs16969968(A;A)", group:1, size:90, color:"#FF9090", gene:"CHRNA5"}, | |
{nodeName:"Addiction", group:2, size:20, color:"blue"}, | |
{nodeName:"Cholinesterase Inhibitors", group:2, size:20, color:"blue"}, | |
{nodeName:"Chronic obstructive pulmonary disease", group:2, size:20, color:"blue"}, | |
{nodeName:"ClinVar", group:2, size:20, color:"blue"}, | |
{nodeName:"Nicotine dependence", group:2, size:20, color:"blue"}, | |
{nodeName:"rs17602729(C;T)", group:1, size:90, color:"#FF9090", gene:"AMPD1"}, | |
{nodeName:"Coronary artery disease", group:2, size:20, color:"blue"}, | |
{nodeName:"rs2237717(T;T)", group:1, size:90, color:"#FF9090", gene:"MET"}, | |
], | |
links:[ | |
{source:1, target:2, value:1}, | |
{source:1, target:3, value:1}, | |
{source:1, target:4, value:1}, | |
{source:5, target:6, value:1}, | |
{source:5, target:7, value:1}, | |
{source:5, target:8, value:1}, | |
{source:5, target:9, value:1}, | |
{source:5, target:10, value:1}, | |
{source:5, target:11, value:1}, | |
{source:5, target:12, value:1}, | |
{source:5, target:13, value:1}, | |
{source:5, target:3, value:1}, | |
{source:14, target:2, value:1}, | |
{source:14, target:11, value:1}, | |
{source:15, target:16, value:1}, | |
{source:17, target:18, value:1}, | |
{source:19, target:2, value:1}, | |
{source:20, target:21, value:1}, | |
{source:20, target:22, value:1}, | |
{source:20, target:23, value:1}, | |
{source:20, target:24, value:1}, | |
{source:20, target:13, value:1}, | |
{source:20, target:25, value:1}, | |
{source:26, target:24, value:1}, | |
{source:26, target:27, value:1}, | |
], | |
}; | |
var w = $("#chart").width(), h = $("#chart").height()-buttonBarHeight; | |
var lastClicked; | |
var vis = new pv.Panel() | |
.width(w) | |
.height(h) | |
.fillStyle("white") | |
.event("mousedown", pv.Behavior.pan()) | |
.event("mousewheel", pv.Behavior.zoom()); | |
var force = vis.add(pv.Layout.Force) | |
.nodes(agraph.nodes) | |
.links(agraph.links); | |
force.link.add(pv.Line); | |
force.node.add(pv.Dot) | |
.size(function(d) d.size * Math.pow(this.scale, -1.5)) | |
.fillStyle(function(d) d.color ) | |
.strokeStyle(function() this.fillStyle().darker()) | |
.lineWidth(1) | |
.title(function(d) { | |
if (d.desc) { | |
return d.desc; | |
} else if (d.effect) { | |
return d.effect; | |
} else { | |
var s = d.nodeName; | |
var g = d.gene; | |
if (g) s += " " +g; | |
return s; | |
} | |
}) | |
.event("mousedown", pv.Behavior.drag()) | |
.event("drag", force) | |
.event("click", function(d) { | |
if (lastClicked) lastClicked.size /= 5; | |
console.log("clicked on "+d.nodeName+" #"+d.index); | |
d.size *= 5; | |
lastClicked = d; | |
vis.render(); | |
return false; | |
}) | |
.event("dblclick", function(d) { | |
if (d.group == 2) { | |
setTag(d.nodeName); | |
} else { | |
if (d.fix) { | |
d.fix = None; | |
} else { | |
d.fix = new pv.Vector(d.x,d.y); | |
} | |
} | |
}) | |
.anchor("left").add(pv.Label).text(function(d) { return d.nodeName} ); | |
vis.render(); | |
</script> | |
<button onclick="resetGraph();">Reset</button> | |
<button onclick="freezeGraph();">Freeze</button> | |
<span style="color:red"><b>d</b></span>elete | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment