Team:Heidelberg/js/notebook tree
From 2014.igem.org
var svg; var color = d3.scale.category20();
var firstDate = 1403301600;//1407861000; var date = firstDate;
var heightOfSecond = 100 / 86400; // = 300 Pixel per day?! var viewportHeight = 300/heightOfSecond; var bufferHeight = 1000/heightOfSecond; var scrollSpeed = 600000; // = 20 minutes
var width = 1; var height = 1;
var bigNodes = []; //Contains [{containsDate(), [data]},...] var bigLinks = [];
var fnodes = []; var flinks = []; var force;
var node; var link;
var selectedProject;
var unhighlightedData = []
var jsonFiles = ["1388530800_1388530800.txt","1401804000_1402234200.txt","1402567200_1403101800.txt","1403301600_1403690400.txt","1403953200_1404511200.txt","1404585000_1405166400.txt","1405267200_1405871100.txt","1405980000_1406584800.txt","1406642400_1407238860.txt","1407251220_1407841200.txt","1407861000_1408447800.txt","1408474800_1409074200.txt","1409083200_1409662800.txt","1409768100_1410364800.txt","1410379200_1410962400.txt","1411034400_1411639200.txt","1411642800_1412200800.txt"];//["1412829220_1412978399.txt", "1412978399_1413064799.txt"];
var mapping = { "p/3cuNZHSvzbmc5wGLz" : "Make a liquid culture", "p/3wt4jvadcLzkvFn9X" : "Make a liquid culture", "p/4jCgLAziJ2DSmmcvR" : "Streak bacteria onto an agar plate", "p/53yEPDJz7oRihLz3M" : "Dilute DNA", "p/5K8vL8t4egnG8SRtc" : "PCA", "p/9S64Hy4vyzPvM4aiC" : "DNA purification (\"PCR Purification\")", "p/9TiKPrpdykEiSHFcy" : "Make a liquid culture", "p/ATv6a4HMeQZMa9WYX" : "Dilute DNA", "p/Ae7BXywPx8nNApvPK" : "Golden Gate Assembly", "p/CdKqzhX6FqmmHYKdE" : "Maxens neues Protokoll", "p/D9hHrT2Ere5rrcuXK" : "Make competent cells", "p/E8wraGbztRq8EsET7" : "Make a glycerol stock", "p/ENCvtL4jWZQW72hE5" : "Restriction digest", "p/F2oNT7tGTyGFCjAB9" : "Make competent cells", "p/FY69K4x7xdaJT6Lzk" : "Pick a colony from an agar plate", "p/HA9CLF2Z4kgY3J5rE" : "Make a liquid culture", "p/JPmjNykwWASQiD9PX" : "Agarose Gel Electrophoresis", "p/NgpLzurL2RKFojWWA" : "PCR", "p/Nm75fDvHCr38nXJBo" : "Plasmid Preparation", "p/P6LsqW4xkJYaXHFJN" : "Heat shock transformation", "p/PxYonEdgff39dmkhq" : "DNA purification (\"PCR Purification\")", "p/TD9txcymCuToDta7x" : "Annealing of complementary oligonucleotides", "p/WSMMH3bg6CcrcAJ3x" : "PCR", "p/ZuE3NijkBg4WwpzKc" : "Recovery of plasmid DNA from filter paper", "p/bSEHCZgLpXJ6nb9ze" : "Streak bacteria onto an agar plate", "p/gM7FyZeyNrM4hwxZk" : "Dissolve plasmid DNA from the registry distribution", "p/hmhE7AHgjXE8Khw6M" : "Gel extraction", "p/jT9cdZ9T5JgFDEJXe" : "Heat shock transformation", "p/kKiCHxutJLzPKayCC" : "Streak bacteria onto an agar plate", "p/kxBySpW3SnbWuYMRw" : "Streak bacteria onto an agar plate", "p/mJNyMCoEko3JKRv5x" : "Heat shock transformation", "p/maDx7F6ry8Mw5JmKf" : "Pick a colony from an agar plate", "p/ms6uHrB9Fv23Tge2J" : "Make a glycerol stock", "p/mzGLz4CZBhmDHNivi" : "Make Medium", "p/n4Sg8s8AfhMEtQtFH" : "Ligation", "p/oFoQguhSKQKC2Hfms" : "Gather bacteria from an agar plate", "p/ojKqKzgeLkvNvLDgw" : "Heat shock transformation", "p/ovMK2ktEeSommgLa2" : "Heat shock transformation", "p/pk9LqRH9ot8JiKx23" : "Make a glycerol stock", "p/qGNf5sATkiC4P7RqF" : "Gather bacteria from an agar plate", "p/v97Nktv4idauP3hYh" : "Make competent cells", "p/vB88pigyWbKvmKir6" : "Pick a colony from an agar plate", "p/vj752RxeBbHsHi83w" : "Pick a colony from an agar plate", "p/xBmBAjXPQntkvc8d5" : "Make a glycerol stock", "p/z46dHCjoZpLkNgm4k" : "CPEC" }
var colorMapping = {"Make a liquid culture":"#1f77b4","Streak bacteria onto an agar plate":"#aec7e8","Dilute DNA":"#ff7f0e","PCA":"#ffbb78","DNA purification (\"PCR Purification\")":"#2ca02c","Golden Gate Assembly":"#98df8a","Maxens neues Protokoll":"#d62728","Make competent cells":"#ff9896","Make a glycerol stock":"#9467bd","Restriction digest":"#c5b0d5","Pick a colony from an agar plate":"#8c564b","Agarose Gel Electrophoresis":"#c49c94","PCR":"#e377c2","Plasmid Preparation":"#f7b6d2","Heat shock transformation":"#7f7f7f","Annealing of complementary oligonucleotides":"#c7c7c7","Recovery of plasmid DNA from filter paper":"#bcbd22","Dissolve plasmid DNA from the registry distribution":"#dbdb8d","Gel extraction":"#17becf","Make Medium":"#9edae5","Ligation":"#1f77b4","Gather bacteria from an agar plate":"#aec7e8","CPEC":"#ff7f0e"};
//var circle;
$(document).ready(function(){
svg = d3.selectAll("#graph"); $svg = $("#graph"); width = $svg.width(); height = $svg.height();
$svg.bind('DOMMouseScroll mousewheel', handleScrolling);
node = svg.selectAll(".node"); link = svg.selectAll(".link"); force = d3.layout.force() .charge(-500) .linkDistance(function (d) { var dist = getHeight(d.target.date) - getHeight(d.source.date); var minDist = 50; if (dist < minDist) dist = minDist; return dist; }) .linkStrength(.1) .gravity(0) .size([width, height]) .links(flinks) .nodes(fnodes) .on("tick", tick);
setSubproject("lyso", firstDate);
});
function update(){ if(dataUpdated){ dataUpdated=false; var links = flatten(bigLinks); var nodes = flatten(bigNodes); //console.log(bigNodes, nodes);
node = node.data(nodes, function(d) { return d.id;}); node.enter() .append("circle") .attr("class", "node") .attr("r", 11) .attr("fill", function (d) { return colorMapping[mapping[d.type]]; }) .on("click", function(){if(d3.event.defaultPrevented) return ; alert("Silvan show Overlay");}) .call(force.drag) .each(function(d) { d.y = (d.date - firstDate) * heightOfSecond; fnodes.push(d); }) .append("svg:title") .text(function(d){return mapping[d.type] + ", " + d.groups;});
node.exit() .each(function(d) { removeByID(fnodes, d.id); }) .remove();
links = links.filter(function(d) { return findByID(d.target) !== undefined && findByID(d.source) !== undefined; }); links.forEach(function(d) { d.source = findByID(d.source); d.target = findByID(d.target); });
link = link.data(links); var lines = link.enter() .append("line") .each(function (d) { flinks.push(d); }) .on("click", function (d){if(d3.event.defaultPrevented) return ; scrollToDate(d.target.date-100000);}) .attr("class", "link");
//lines.filter(function () { return Math.random() > 0.5; }).attr("opacity", "0");
link.exit() .each(function(d) { var index = flinks.indexOf(findByID(d)); if(index >-1) flinks.splice(index, 1); removeLinksByIDs(flinks, d.source.id, d.target.id); }) .remove();
force.start();
unhighlightData(unhighlightedData); }
updateVis();
}
function tick(e) { force.nodes().forEach(function(d){ if(!d.fixed){ d.y += (getHeight(d.date) - d.y) * e.alpha; //d.y = getHeight(d.date); if(d.x > width * 8/10){ d.x += (width*8/10 - d.x) * e.alpha; }else if(d.x < width * 2/10){ d.x += (width* 2/10 - d.x) * e.alpha; } else{ d.x += (width/2 - d.x) * e.alpha * 0.2 ; } } });
updateVis(); }
function updateVis(){
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y - (date - firstDate) * heightOfSecond; });
link .attr("x1", function(d) { if(d.source !== undefined) return d.source.x; else return d.target.x; }) .attr("y1", function(d) { if(d.source !== undefined) return d.source.y - (date - firstDate) * heightOfSecond; else return 0;}) .attr("x2", function(d) { if(d.target !== undefined) return d.target.x; else return d.source.x; }) .attr("y2", function(d) { if(d.target !== undefined) return d.target.y - (date - firstDate) * heightOfSecond; else return viewportHeight * heightOfSecond;}); }
function setSubproject(project, d){ if(d === undefined) d = date; this.selectedProject = project; unhighlightedData = []; unloadGreaterDate(firstDate-1);
loadDate(d-bufferHeight); loadDate(d); loadDate(d+viewportHeight); loadDate(d+viewportHeight+bufferHeight); setDate(d); }
function setDate(date){ /*if(date < firstDate){ date = firstDate; }*/ var lastDateDisplayed = date + viewportHeight; loadDate(date - bufferHeight); loadDate(lastDateDisplayed + bufferHeight); unloadSmallerDate(date - bufferHeight); unloadGreaterDate(lastDateDisplayed + bufferHeight); this.date = date; update(); }
/*function animateFlow(){ var links = flatten(bigLinks); var x = Math.floor(links.length * Math.random()); xs.push(x); var l = links[x]; svg.append("ellipse") .attr("fill", "#33CC33") .attr("rx", ( l.target.x - l.source.x)/100) .attr("ry", ( l.target.y - l.source.y)/100) .attr("cx", l.source.x) .attr("cy", l.source.y) .transition() .duration(1000000/(( l.target.x - l.source.x) + ( l.target.y - l.source.y))) .ease("linear") .attr("cx", l.target.x) .attr("cy", l.target.y) .remove();
}*/
function scrollToDate(d){ var currentDate = date; var dif = d - currentDate; console.log(dif); var smoothness = 60; //30 FPS var i = 0; var max = 1 * smoothness; //1 sec. var interval = setInterval(function(){ i=i+1; if(i > max){ clearInterval(interval); } setDate(date+ dif/max) }, max*1000/smoothness/smoothness); }
function highlightData(typeName){ var array = [].concat(typeName); console.log(array); node.attr("opacity", function(d){ var h = false; for(var g = 0; g < array.length; g=g+1) { h = h || d.groups.indexOf(array[g]) !== -1; } if(h) return 1.0; else return 0.1; }); link.attr("opacity", function(d){ var h = false; for(var g = 0; g < array.length; g=g+1) { h = h || (d.target && d.target.groups.indexOf(array[g]) !== -1 && d.source && d.source.groups.indexOf(array[g]) !== -1); }
if(h) return 1; else return 0.1; }); }
function unhighlightData(typeName){ var array = [].concat(typeName); console.log(array); node.attr("opacity", function(d){ var h = false; for(var g = 0; g < array.length; g=g+1) { h = h || d.groups.indexOf(array[g]) !== -1; } if(h) return 0.1; else return 1.0; }); link.attr("opacity", function(d){ var h = false; for(var g = 0; g < array.length; g=g+1) { h = h || ((d.target && d.target.groups.indexOf(array[g]) !== -1) || (d.source && d.source.groups.indexOf(array[g]) !== -1)); }
if(h) return 0.1; else return 1.0; }); for(i = 0; i < array.length; i=i+1){ if(unhighlightedData.indexOf(array[i]) === -1) unhighlightedData.push(array[i]); } }
//////***************************************Helper Function*************************************/
function findByID(id){ return $.grep(fnodes, function(e){return e === id || e.id === id;})[0]; }
function removeByID(array, id){ var index = -1; for(i = 0; i<array.length; i=i+1){ if(array[i].id === id){ index = i; break; } } array.splice(index, 1); }
function removeLinksByIDs(array, sourceId, targetId){ var index = -1; for(i = 0; i<array.length; i=i+1){ if(array[i].source.id === sourceId && array[i].target.id === targetId){ index = i; break; } } array.splice(index, 1); }
function getHeight(date){ return (date - firstDate)*heightOfSecond;
}
/***************************************************************************************************/
/************************************Scrolling and JSON loading stuff*******************************/
/*var loadedJSONFiles = [];
var lastLoadedJSON = -1;
var firstLoadedJSON = 0;*/
var dateJSONMatchingList; var dataUpdated = false;
var loadingData = false;
function flatten(a){ return a.reduce(extractAndMergeData, []); }
function extractAndMergeData(a, b){ return a.concat(b.data); }
function getJSONForDate(date){ if(dateJSONMatchingList === undefined){ dateJSONMatchingList = []; for(i = 0; i < jsonFiles.length; i=i+1){ var name = jsonFiles[i]; var f = parseFileNameToContainsFnc(name); dateJSONMatchingList.push(f); } } for(j = 0; j < dateJSONMatchingList.length; j=j+1){ if(dateJSONMatchingList[j](date)) return jsonFiles[j]; } return -1; }
function loadDate(date){
//Check if date is already loaded if(!isDateLoaded(date)){ //Load new date var json = getJSONForDate(date); if(json !== -1){ var file = "Team_Heidelberg_Notebook_Data_test_"+ json; console.log(md5); d3.json("/wiki/images/"+ (md5(file)+"")[0]+"/"+(md5(file)+"").substr(0,2)+"/"+file, function(error, data){ if(error) console.warn(error); var containsFnc = parseFileNameToContainsFnc(json); var smallerFnc = parseFileNameToSmallerFnc(json); var greaterFnc = parseFileNameToGreaterFnc(json); if(!isDateLoaded(date)){ //Attention this could lead due to the asynchronous nature of d3.json to a race condition and double adding of the nodes and links... bigNodes.push({ contains: containsFnc, greater: greaterFnc, smaller: smallerFnc, data: data.nodes }); bigLinks.push({ contains: containsFnc, greater: greaterFnc, smaller: smallerFnc, data: data.links }); dataUpdated = true; } update(); }); } }
}
function unloadSmallerDate(date){ if(bigNodes.reduce(function(a, b){return a || b.greater(date);}, false)){ bigNodes = bigNodes.filter(function(d){return !d.greater(date);}); bigLinks = bigLinks.filter(function(d){return !d.greater(date);}); dataUpdated = true;
} }
function unloadGreaterDate(date){ if(bigNodes.reduce(function(a, b){return a || b.smaller(date);}, false)){ bigNodes = bigNodes.filter(function(d){return !d.smaller(date);}); bigLinks = bigLinks.filter(function(d){return !d.smaller(date);}); dataUpdated = true; } }
function parseFileName(name){ var l = name.substring(0, name.length-4).split("_"); if(l === undefined || l.length !== 2) console.warn("erroneous file name", name, l); return l; }
function parseFileNameToContainsFnc(name){ var l = parseFileName(name); var f = function(l1, l2){ return function(d){ return d >= l1 && d <= l2; }; }(l[0], l[1]); return f; }
function parseFileNameToSmallerFnc(name){ var l = parseFileName(name); var f = function(l1, l2){ return function(d){ return d < l1 && d < l2; }; }(l[0], l[1]); return f; } function parseFileNameToGreaterFnc(name){ var l = parseFileName(name); var f = function(l1, l2){ return function(d){ return d > l1 && d > l2; }; }(l[0], l[1]); return f; }
function isDateLoaded(date){ for(i = 0; i < bigNodes.length; i=i+1){ if(bigNodes[i].contains(date)){ return true; } } return false; }
function handleScrolling(e) { var scrollTo = 0;
e.preventDefault();
if (e.type == 'mousewheel') { scrollTo = (e.originalEvent.wheelDelta * -1); }else if (e.type == 'DOMMouseScroll') { scrollTo = e.originalEvent.detail * scrollSpeed; } setDate(date+scrollTo); }