Skip to content
Permalink
874ec6518f
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
executable file 1715 lines (1456 sloc) 59.5 KB
function VQI_GenomeBrowser(id, serviceURL) {
var divId = id;
var width = 1000;
var height = 20;
var margin = 50;
var bufferSpace = 20;
var trackHeight = 50;
var panExtent = [0, width];
var initialZoom = 1 //defines what will be considered a zoom scale of 1
var trackList = [];
var genomeData = [];
var chromosomes = [];
var thisObj = this;
var chrom_curr = "chr1";
var indexArray = {chr: 0, start: 1, end: 2, name: 3, type: 3, score: 4, strand: 5, options: 6, exonStarts: 9, exonEnds: 10};
var testdata;
var isready = false;
var waitTime;
var loadCount = 0;
var trackInfo = [];
trackInfo[0] = {name: "HG19", type: "bed", fileHandle: "upload1436481988"};
trackInfo[1] = {name: "Tile2 Content Snp", type: "bed", fileHandle: "upload1436411775"};
trackInfo[2] = {name: "cpg", type: "cpg", fileHandle: "upload1437097194,upload1437098473,upload1437098556"};
var serviceURL = serviceURL;
// var trackDiv;
// var trackNavContainer;
// var recentTrackContainer;
// var dataDiv;
// var otherDiv;
var navigateToRegion = function () {
var navigate = $("#" + divId + " #navigate").val();
navigate = navigate.split(/[:-]/);
if (navigate.length == 3){
var chrom = navigate[0].trim();
var chrom_start = Number(navigate[1].trim());
var chrom_end = Number(navigate[2].trim());
//Only need to set bounds if current chromosome is already graphed
if (chrom == chrom_curr)
{
setBounds(chrom_start, chrom_end);
}
else
{
setPanExtent();
graph(chrom, chrom_start, chrom_end);
}
}
else
{
browseToGene();
}
};
var addRecentTrack = function(){
var track = $("#" + divId + " #RecentTracks").val();
for (i in trackList){
if (trackList[i].name == track){
return;
}
}
for (i in trackInfo){
if (trackInfo[i].name == track){
self.addOneTrackFromDatabase(trackInfo[i].fileHandle,track,trackInfo[i].type);
break;
}
}
}
var browseToGene = function () {
var geneName = $("#" + divId + " #navigate").val();
var genes = [geneName];
dataToPost = JSON.stringify(genes);
$.ajax({
url: vqi_url + 'serverside/web/VQService.php?service=gene-info-for-gene-symbol',
type: 'POST',
dataType: "json",
data: {
"genes": dataToPost
},
async: false
}).success(function (data) {
var thisGene = data.slice(1)[0];
var gene_chrom = thisGene[2];
var gene_start = thisGene[3];
var gene_end = thisGene[4];
thisObj.navigate(gene_chrom, gene_start, gene_end);
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
};
this.makeNavMenu = function () {
var menu = "<ul class='nav nav-tabs' style='font-size: 16'>"+
"<li class='active'><a data-toggle='tab' href='#home'>Home</a></li>"+
"<li><a data-toggle='tab' href='#traks'>Track</a></li>"+
"<li><a data-toggle='tab' href='#analysis'>Analysis</a></li>"+
"<li><a data-toggle='tab' href='#other'>Other</a></li>"+
"</ul>"
var homeTable = "<table cellpadding='5'; style='margin: 0px 20px;font-size: 14'>"+
"<tr> <td id='trackNavContainer'> </td></tr>"+
"<tr> <td id=''> </td></tr>"+
"<tr> <td id=''> </td></tr>"+
"</table>"
var tackMenuTable = "<table cellpadding='5'; style='margin: 0px 20px;font-size: 14'>"+
"<tr> <td id='uploadDataContainer'> </td></tr>"+
"<tr> <td id='recentTrackContainer'> </td></tr>"+
"<tr> <td id='exportRemoveContainer'> </td></tr>"+
"</table>"
var analysisMenuTable = "<table cellpadding='5'; style='margin: 0px 20px;font-size: 14'>"+
"<tr> <td id='colocalizeContainer'> </td></tr>"+
"<tr> <td id='mcEntContainer'> </td></tr>"+
"</table>"
var menuContent = "<div class='tab-content'>"+
"<div id='home' class='tab-pane fade in active' style='height: 130px; width: 800px; background-color:#F0F0F0'>"+homeTable+"</div>"+
"<div id='traks' class='tab-pane fade ' style='height: 130px; width: 800px; background-color:#F0F0F0'>"+tackMenuTable+"</div>"+
"<div id='analysis' class='tab-pane fade' style='height: 130px; width: 800px; background-color:#F0F0F0'>"+analysisMenuTable+"</div>"+
"<div id='other' class='tab-pane fade'></div>"+
"</div>"
var menuContainer = "<div class='container-fluid' >"+menu+menuContent+"</div>";
$("#" + divId).append(menuContainer);
};
this.makeNavMenu();
this.makeNavigationForm = function () {
var navigateBox = "<input type='text' name='navigate' id='navigate' size='30'>";
var navigateButton = "<input type='button' id='navigatebutton' value='Go To'>";
var form = "<form id='navigation_form'>" + navigateBox + navigateButton + "</form>";
$("#" + divId).append(form);
$("#" + divId + " #navigatebutton").on("click", navigateToRegion.bind(this));
};
this.makeNavigationForm();
var colocalize = function () {
var track1Name = $("#" + divId + " #track1").val();
var track2Name = $("#" + divId + " #track2").val();
var coloc_dist = $("#" + divId + " #coloc_dist").val();
if(track1Name === track2Name){
alert("Track1 and Track2 cannot be same for colocalization.");
return;
}
var data1 = this.getTrackByName(track1Name);
var data2 = this.getTrackByName(track2Name);
var dataToPost1 = [], dataToPost2 = [];
dataToPost1 = JSON.stringify(data1);
dataToPost2 = JSON.stringify(data2);
var data1Length = data1.length;
var data2Length = data2.length;
$.ajax({
url: vqi_url + 'serverside/web/VQService.php?service=coloc-bed-and-bed',
type: 'POST',
dataType: "json",
data: {
"bed1": dataToPost1,
"bed2": dataToPost2,
"coloc_dist": coloc_dist
},
async: false
}).success(function (data) {
var data1 = [];
var data2 = []
data = data.slice(1);
for (var i in data) {
data1.push(data[i].slice(0, 6));
data2.push(data[i].slice(6));
}
thisObj.addTrack(data1);
thisObj.addTrack(data2);
thisObj.getPValue(data1Length, data2Length, data1.length);
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
};
/**
*
* @author Pujan Joshi
* @since April 16, 2015
* @param {type} k1
* @param {type} k2
* @param {type} ob
* @returns {p-value}
*
* This method calls Yue's pvalue program and returns p-value result.
*/
this.getPValue = function (k1, k2, ob) {
$.ajax({
url: vqi_url + 'serverside/web/VQService.php?service=coloc-pvalue',
type: 'GET',
dataType: "text",
data: {
"K1": k1,
"K2": k2,
"OB": ob
},
async: true
}).success(function (data) {
console.log(data);
$("#pvalue_div").empty().append("p-value = " + data);
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
}
this.makeFormForColocalization = function () {
var track1Select = "Track1: <select name='track1' id='track1'>";
for (var i in trackList) {
var thisTrack = trackList[i];
var text = thisTrack.name;
var value = thisTrack.name;
track1Select += "<option value='" + value + "'>" + text + "</option>";
}
track1Select += "</select>";
var track2Select = " Track2: <select name='track2' id='track2'>";
for (var i in trackList) {
var thisTrack = trackList[i];
var text = thisTrack.name;
var value = thisTrack.name;
track2Select += "<option value='" + value + "'>" + text + "</option>";
}
track2Select += "</select>";
var distanceTextBox = "<input type=text name='coloc_dist' id='coloc_dist' value='100'>";
var colocalizeButton = "<input type='button' id='colocalize' value='colocalize'>";
var pValueDiv = "<div id='pvalue_div'></div>"
var form = "<form id='colocalization_form'>" + track1Select + track2Select + distanceTextBox + colocalizeButton + pValueDiv + "</form>";
$("#" + divId + " #colocalizeContainer").append(form);
$("#" + divId + " #colocalize").on("click", colocalize.bind(this));
};
this.makeFormForColocalization();
/*var removeSelectedTracks = function () {
for (var i = trackList.length - 1; i >= 0; i--) {
if (trackList[i].isSelected())
{
trackList[i].group.remove();
trackList.splice(i, 1);
}
}
reorderTracks();
updateAllTracksSelectBoxes();
}*/
var removeTrack = function (track_name) {
for (var i = trackList.length - 1; i >= 0; i--) {
if (trackList[i].name == track_name)
{
trackList[i].group.remove();
trackList.splice(i, 1);
}
}
setPanExtent();
graph(chrom_curr, xScale.domain()[0], xScale.domain()[1]);
reorderTracks();
updateAllTracksSelectBoxes();
}
/* this.getSelectedTrackNames = function(){
var tracknames = []
for (var i in trackList) {
if (trackList[i].isSelected())
{
tracknames.push(trackList[i].name);
}
}
return tracknames;
}
this.getSelectedTracks = function(){
tracknames = thisObj.getSelectedTrackNames();
tracks = [];
for (var i in tracknames) {
tracks.push(thisObj.getTrackByName(tracknames[i]));
}
return tracks;
}
var exportSelectedTracks = function () {
var tracknames = []
for (var i in trackList) {
if (trackList[i].isSelected())
{
tracknames.push(trackList[i].name);
}
}
for (var i in tracknames) {
exportTrack(tracknames[i]);
}
}*/
var exportTrack = function (track_name) {
var track = thisObj.getTrackByName(track_name);
exportTrackToText(track.getData(), track_name);
}
this.makeUploadForm = function() {
var fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.addEventListener('change', function (e) {
var file = fileInput.files[0];
var textType = /text.*/;
if (file.type.match(textType)) {
var reader = new FileReader();
reader.onload = function (e) {
var Data = reader.result;
uploadFile(Data);
}
reader.readAsText(file);
} else {
alert("File not supported!");
}
});
var f = document.createElement("form");
fileInput.style.display="inline";
f.innerHTML = "Add track by uploading file: ";
f.appendChild(fileInput);
$("#" + divId + " #uploadDataContainer").append(f);
}
this.makeUploadForm();
this.makeRecentTrackForm = function (){
var trackSelect = "Recent tracks: <select name='RecentTracks' id='RecentTracks'>";
for (var i in trackInfo) {
var thisTrack = trackInfo[i];
var text = thisTrack.name;
var value = thisTrack.name;
trackSelect += "<option value='" + value + "'>" + text + "</option>";
}
trackSelect += "</select>";
var addTrackButton = "<input type='button' id='addTrackButton' value='Add Track'>";
var form = "<form id='colocalization_form'>" + trackSelect + addTrackButton + "</form>";
$("#" + divId + " #recentTrackContainer").append(form);
$("#" + divId + " #addTrackButton").on("click", addRecentTrack.bind(this));
}
this.makeRecentTrackForm();
this.makeSelectionForm = function () {
var removeButton = "<input type='button' id='removetrackbutton' value='Remove Selected Track'>";
var exportButton = "<input type='button' id='exporttrackbutton' value='Export Selected Track'>";
var mcScoreButton = "<input type='button' id='mcscoreTracks' value='MC System' onclick='VQI_ControlPanel.scoreButtonClicked()'>";
var entScoreButton = "<input type='button' id='entscoreTracks' value='EMT Score' onclick='VQI_ControlPanel.EMTScoreButtonClicked()'>";
//var removeExportform = "<form id='removeExportForm'>" + removeButton + "&nbsp&nbsp&nbsp"+exportButton +"</form>";
var mcEntForm = "<form id='mcEntForm'>" + mcScoreButton + "&nbsp&nbsp&nbsp"+entScoreButton +"</form>";
//$("#" + divId +" #exportRemoveContainer").append(removeExportform);
$("#" + divId +" #mcEntContainer").append(mcEntForm);
//$("#" + divId + " #removetrackbutton").on("click", removeSelectedTracks.bind(this));
//$("#" + divId + " #exporttrackbutton").on("click", exportSelectedTracks.bind(this));
};
this.makeSelectionForm();
var self = this;
this.svg = d3.select("#" + id)
.append("svg")
.attr("width", width + 2 * margin)
.attr("height", height + 2 * margin)
.style("border", "1px solid black")
var svg = this.svg;
var graphRegion = svg.append("g").attr("transform", "translate(" + margin + "," + margin + ")");
//set up scales and axis
var xScale = d3.scale.linear();
var fullXScale = d3.scale.linear();
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10);
//x-axis
var xAxisSelection = graphRegion.append("g")
.call(xAxis)
.attr("class", "axis")
var zoom = d3.behavior.zoom();
var rubberbanding = false;
var rubberbandingX;
svg.on("mousedown", function() {
svg.selectAll("rect.selection").remove();
if(d3.event.shiftKey){
d3.event.preventDefault();
zoom.on("zoom",null);
svg.call(zoom);
rubberbanding = true;
var p = d3.mouse(this);
// create rubber band selector
if(p[0] > margin && p[0] < margin + width)
{
svg.append( "rect")
.attr({
class : "selection",
x : p[0],
y : 0,
width : 0,
height : height + 2 * margin + trackList.length * (trackHeight + bufferSpace)
})
.style("fill-opacity", ".2")
.on("mousedown", navigateToRegion);
}
rubberbandingX = p[0];
}
})
.on("mousemove", function() {
// rubber band selector
var s = svg.select("rect.selection");
if(!s.empty() && rubberbanding) {
d3.event.preventDefault();
// get cursor coordinate
var p = d3.mouse(this);
// get rubber band selector coordinate and size
newX = Math.min(Math.max(p[0] , margin), width + margin);
var c = {
x : Math.min(newX, rubberbandingX),
width : Math.abs(newX - rubberbandingX)
};
s.attr(c);
}
})
.on("mouseup", function() {
// remove rubber band selector
zoom.on("zoom",zoomed);
svg.call(zoom).on("dblclick.zoom", null);
rubberbanding = false;
var s = svg.select("rect.selection");
if(!s.empty()){
$("#" + divId + " #navigate").val(chrom_curr + ":"
+ Math.round(xScale.invert(parseInt(s.attr("x"))-margin)) + "-"
+ Math.round(xScale.invert(parseInt(s.attr("x")) + parseInt(s.attr("width")) - margin)));
}
});
var clipPath = graphRegion.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("y", -margin); //to make this work with all the transformations.
var zoomed = function () {
svg.selectAll("rect.selection").remove();
zoom.translate([panLimit(), 0]);
for(i in trackList)
{
trackList[i].zoomed();
}
xAxisSelection.call(xAxis);
d3.selectAll(".axis path, .axis line").style({
"fill": "none",
"stroke": "black",
"shape-rendering": "crispEdges"});
d3.selectAll(".axis text").style({
"font-family": "sans-serif",
"font-size": "11px"});
if (waitTime != undefined)
{
clearTimeout(waitTime);
}
waitTime = setTimeout(updateTrack, 100);
$("#" + divId + " #navigate").val(chrom_curr + ":" + Math.round(xScale.domain()[0]) + "-" + Math.round(xScale.domain()[1]));
};
var uploadFile = function(data,name,genome){
headerArray = ["CHROM","CHROM_START","CHROM_END","GENESYMBOL","SCORE","STRAND"];
for (i in headerArray) {
indexArray[headerArray[i]] = i;
}
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
data: {
"header": headerArray,
"indexArray": indexArray,
"upload": data
}
}).success(function (data) {
var CurrentFileHandle = data;
var trackName = CurrentFileHandle;
if(name !== undefined){
var trackName = name+" "+genome;
}
trackInfo.push({name: trackName, type: "bed", fileHandle: CurrentFileHandle});
updateRecentTrackDropDown();
self.addOneTrackFromDatabase(CurrentFileHandle,trackName,"bed");
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
}
this.uploadFileFromServer = function(data,name,genome){
var temp = [];
for (i in data) {
temp.push(data[i].join('\t'));
}
trackData = temp.join('\n');
uploadFile(trackData,name,genome);
}
var updateTrack = function(){
for (i in trackList) {
trackList[i].updateTrack();
}
}
var testRemove = function(){
removeTrack("HG191");
reorderTracks();
}
var panLimit = function () {
var divisor = (width) / ((xScale.domain()[1] - xScale.domain()[0]) * zoom.scale());
minX = -(((xScale.domain()[0] - xScale.domain()[1]) * zoom.scale()) + (panExtent[1] - (panExtent[1] - (width / divisor)))),
maxX = -(((xScale.domain()[0] - xScale.domain()[1])) + (panExtent[1] - panExtent[0])) * divisor * zoom.scale();
tx = xScale.domain()[0] < panExtent[0] ?
minX :
xScale.domain()[1] > panExtent[1] ?
maxX :
zoom.translate()[0];
return tx;
}
this.navigate = function (chrom, chrom_start, chrom_end) {
graph(chrom, chrom_start, chrom_end);
};
var setBounds = function (min, max) {
var xMin = Number(min) > panExtent[0] ? Number(min) : panExtent[0];
var xMax = Number(max) < panExtent[1] ? Number(max) : panExtent[1];
var range = (panExtent[1] - panExtent[0]) / initialZoom
xScale.domain([panExtent[0], panExtent[0] + range])
.range([0, width]);
zoom.scaleExtent([1 / initialZoom, (panExtent[1] - panExtent[0]) / 50 / initialZoom]);
var prevTranslate = zoom.translate();
var prevScale = zoom.scale();
zoom.x(xScale).on("zoom", zoomed);
svg.call(zoom).on("dblclick.zoom", null);
var scale = (panExtent[1] - panExtent[0]) / (xMax - xMin) / initialZoom;
if(scale > (panExtent[1] - panExtent[0]) / 50 / initialZoom)
scale = (panExtent[1] - panExtent[0]) / 50 / initialZoom;
if(scale < 1 / initialZoom)
scale = 1 / initialZoom;
zoom.scale(scale)
//translates scale with regards to the middle of xMin and xMax
var divisor = (width) / ((xScale.domain()[1] - xScale.domain()[0]) * scale);
var minX = -(((xScale.domain()[0] - xScale.domain()[1]) * scale) + (panExtent[1] - (panExtent[1] - (width / divisor))));
var maxX = -(((xScale.domain()[0] - xScale.domain()[1])) + (panExtent[1] - panExtent[0])) * divisor * scale;
var midScale = d3.scale.linear()
.domain([panExtent[0] + (xMax - xMin) / 2, panExtent[1] - (xMax - xMin) / 2])
.range([minX, maxX]);
var zoomWidth = midScale((xMax + xMin) / 2);
//transitions start from the previous transition, so I make a transition that first zooms
//to the current view in no time, then another transition that zooms to the desired view
svg.transition()
.duration(0)
.call(zoom.translate(prevTranslate).scale(prevScale).event)
.each("end", function(){
svg.transition()
.duration(1000)
.call(zoom.scale(scale).translate([zoomWidth, 0]).event)
})
zoomed();
}
var setPanExtent = function () {
var mins = [];
var maxs = [];
for (var i in trackList) {
range = trackList[i].getRange();
mins.push(Number(range[0]));
maxs.push(Number(range[1]));
}
min = d3.min(mins);
max = d3.max(maxs);
panExtent[0] = isNaN(min) ? 0 : min;
panExtent[1] = isNaN(max) ? width : max;
var distance = (panExtent[1] - panExtent[0]) / initialZoom;
fullXScale = d3.scale.linear()
.domain([panExtent[0], panExtent[0] + distance])
.range([0, width]);
}
var graph = function (chromosome, min, max) {
var self = this;
chrom_curr = chromosome;
if (min == null || max == null) {
setBounds(panExtent[0], panExtent[1]);
}
else {
setBounds(Number(min), Number(max));
}
for (var i in trackList) {
trackList[i].updateTrack();
}
}
var addOneTrack = function (data, name, type, args) {
var trackIndex = trackList.length;
var trackCount = trackIndex + 1;
//name of track
name = name || "track-" + (trackIndex + 1);
if(type == "cpg")
trackList.push(new CpgTrack(name, graphRegion.append("g"), args));
if(type == "bed")
trackList.push(new BedTrack(name, graphRegion.append("g"), args));
if(type == "fasta")
trackList.push(new FastaTrack(name, graphRegion.append("g"), args));
setPanExtent();
graph(chrom_curr);
clipPath.attr("height", Number(svg.attr("height")));
zoomOnly = true;
zoomed();
zoomOnly = false;
return data;
}
var reorderTracks = function () {
svg.transition().attr("height", height + 2 * margin + trackList.length * (trackHeight + bufferSpace));
for (var i in trackList) {
trackList[i].group.transition().attr("transform", "translate(" + 0 + "," + (margin + bufferSpace + i * (trackHeight + bufferSpace)) + ")");
}
}
this.addOneTrackFromDatabase = function(fileHandle,name,type) {
thisObj.addTrack([], name, type, {"fileHandle" : fileHandle});
}
this.addTrack = function (data, name, type, args) {
addOneTrack(data, name, type, args);
reorderTracks();
updateAllTracksSelectBoxes();
}
this.addTrackFile = function (dataFile, name, type, header) {
$.get(dataFile, function (data) {
var dataRows = thisObj.parseTrackFile(data, header);
thisObj.addTrack(dataRows, name, type);
});
}
/* this.setData = function (data) {
genomeData = data;
graph(chromosomes[0]);
}
this.getData = function () {
return genomeData;
}
this.loadCPGFiles = function (cpg, shoer, shelf) {
genomeData = [];
chromosomes = [];
//Will read the 3 files and place all data into genomeData
//as objects with attributes 'chromosome', 'start', 'end', 'type'
$.get(cpg, function (data) {
var cpgData = data.trim().split("\n");
$.each(cpgData, function (index, value) {
cpgData[index] = cpgData[index].trim().split("\t").map(function (item) {
return isNaN(Number(item)) ? item : Number(item);
});
});
//get all unique chromosomes
var currentChromosome = "";
$.each(cpgData, function (index, value) {
if (value[0] != currentChromosome)
{
chromosomes.push(value[0]);
currentChromosome = value[0];
}
});
cpgData = cpgData.map(function (data) {
return [data[0], data[1], data[2], "cpg"];
});
genomeData = genomeData.concat(cpgData);
});
$.get(shoer, function (data) {
var tempShoreData = data.trim().split("\n");
$.each(tempShoreData, function (index, value) {
tempShoreData[index] = tempShoreData[index].trim().split("\t").map(function (item) {
return isNaN(Number(item)) ? item : Number(item);
});
});
var shoreData = [];
$.each(tempShoreData, function (index, value) {
shoreData.push([value[0], value[1], value[2], "shore"]);
shoreData.push([value[0], value[3], value[4], "shore"]);
});
genomeData = genomeData.concat(shoreData);
});
$.get(shelf, function (data) {
var tempShelveData = data.trim().split("\n");
$.each(tempShelveData, function (index, value) {
tempShelveData[index] = tempShelveData[index].trim().split("\t").map(function (item) {
return isNaN(Number(item)) ? item : Number(item);
});
});
var shelveData = [];
$.each(tempShelveData, function (index, value) {
shelveData.push([value[0], value[1], value[2], "shelve"]);
shelveData.push([value[0], value[3], value[4], "shelve"]);
});
genomeData = genomeData.concat(shelveData);
thisObj.addTrack(genomeData, "cpg", 'cpg');
});
}*/
this.parseTrackFile = function (data, header) {
var delimeter = "\t";
var thisData = new Array();
var txtContent = data.split(/\r\n|\r|\n/g);
var startRow = 0;
if (header) {
startRow = 1;
}
for (var i = startRow; i < txtContent.length; i++) {
var thisRow = txtContent[i].split(delimeter);
var thisObject = {};
thisObject = thisRow;
if (thisRow[0].indexOf("##") === 0) {
continue;
}
thisData.push(thisObject);
}
return thisData;
};
this.getTrackByName = function (name) {
for (var i in trackList) {
var thisTrack = trackList[i];
if (thisTrack.name === name) {
return thisTrack;
}
}
};
var getTrackIndexByName = function (name) {
for (var i in trackList) {
var thisTrack = trackList[i];
if (thisTrack.name === name) {
return i;
}
}
};
var updateAllTracksSelectBoxes = function () {
var track1Select = $("#" + divId + " #track1");
updateSelectBoxWithTracks(track1Select.get(0));
var track2Select = $("#" + divId + " #track2");
updateSelectBoxWithTracks(track2Select.get(0));
}
var updateSelectBoxWithTracks = function (selectBox) {
selectBox = selectBox;
selectBox.options.length = 0;
var optionIndex = 0;
for (var i in trackList) {
var text = trackList[i].name;
var value = text;
selectBox.options[optionIndex++] = new Option(text, value);
}
};
var updateRecentTrackDropDown = function () {
var trackSelect = $("#" + divId + " #RecentTracks");
selectBox = trackSelect.get(0);
selectBox.options.length = 0;
var optionIndex = 0;
for (var i in trackInfo) {
var text = trackInfo[i].name;
var value = text;
selectBox.options[optionIndex++] = new Option(text, value);
}
};
var exportTrackToText = function (data, filename) {
temp = [];
for (i in data)
{
if (data[i].constructor === Array)
{
var row = data[i].join("\t");
temp.push(row);
}
}
var txt = temp.join("\r\n");
var blob = new Blob([txt], {type: "text/csv;charset=utf-8"});
saveAs(blob, filename + ".txt");
}
function optmizedTrack(){
var myData;
var start = (Math.round(xScale.domain()[0])).toString();
var end = (Math.round(xScale.domain()[1])).toString();
$.ajax({
url: 'zoomAssist.php',
type: 'POST',
dataType: "json",
data: {
"start": start,
"end": end
}
}).success(function (data) {
myData = data;
d3.select(test2).select("svg")
.remove();
var svg2 = d3.select(test2)
.append("svg")
.attr("width", width + 2 * margin)
.attr("height", height + 2 * margin);
var graphR = svg2.append("g").attr("transform", "translate(" + margin + "," + margin + ")");
var tracks = graphR.selectAll("rect")
.data(myData)
.enter()
.append("rect")
.attr("fill", "gray")
.attr("x", function (d) {
return xScale(d.start);
})
.attr("y", 5)
.attr("height", 10)
.attr("width", function (d) {
return Math.ceil(xScale(d.end) - xScale(d.start));
});
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
}
function Track(name, group) {
this.group = group;
this.name = name;
group.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.style("stroke", "blue")
.style("stroke-opacity" , 0.5);
group.append("text")
.attr("x", 0)
.attr("y", -trackHeight / 2 - bufferSpace / 2)
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "red")
.text(name);
group.append("foreignObject")
.attr("width", 50)
.attr("height", 20)
.attr("x", width+5)
.attr("y", -7.5)
.append("xhtml:div")
.html("<form><input type=image src=DeleteTrack.png width=15 height=15 onclick='return false;'></form>")
.on("click", function () {
removeTrack(name);
});
group.append("foreignObject")
.attr("width", 50)
.attr("height", 20)
.attr("x", width+25)
.attr("y", -7.5)
.append("xhtml:div")
.html("<form><input type=image src=ExportTrack.png width=15 height=15 onclick='return false;'></form>")
.on("click", function () {
exportTrack(name);
});
group.append("path")
.attr("transform", function (d) {
return "translate(" + -20 + "," + -10 + ")"
})
.attr("d", d3.svg.symbol().type(["triangle-up"]))
.attr("class", "up")
.on('click', function () {
var i = Number(getTrackIndexByName(name));
if (i > 0)
{
var temp = trackList[i];
trackList[i] = trackList[i - 1];
trackList[i - 1] = temp;
}
reorderTracks();
});
group.append("path")
.attr("transform", function (d) {
return "translate(" + -20 + "," + 10 + ")"
})
.attr("d", d3.svg.symbol().type(["triangle-down"]))
.attr("class", "down")
.on('click', function () {
var i = Number(getTrackIndexByName(name));
if (i < trackList.length - 1)
{
var temp = trackList[i];
trackList[i] = trackList[i + 1];
trackList[i + 1] = temp;
}
reorderTracks();
});
this.trackGroup = group.append("g")
.attr("clip-path", "url(#clip)")
.append("g");
this.isSelected = function() {
return group.select("#check").node().checked;
}
//Updates currently loaded objects whenever zooming or scrolling
this.zoomed = function(){};
//Pull in new data from database if neccessary when zooming/scrolling stops
this.updateTrack = function(){};
this.getData = function(){};
this.getRange = function(){};
}
function CpgTrack(name, group, args) {
Track.call(this, name, group);
var trackGroup = this.trackGroup;
var fileHandle = args.fileHandle;
var tempHandles = fileHandle.split(",");
var cpgFileHandle = tempHandles[0];
var shelveFileHandle = tempHandles[1];
var shoreFileHandle = tempHandles[2];
var data;
var redrawCutoff = 1000; //Scale at which rectangles will be drawn individually
var getScale = function(){
if(zoom.scale() < redrawCutoff)
return fullXScale;
else
return xScale;
}
var drawTrack = function(data)
{
var thisScale = getScale();
trackGroup.selectAll("rect")
.data(data, function (d) {
return d;
})
.exit()
.remove();
trackGroup.selectAll("rect")
.data(data, function (d) {
return d;
})
.enter()
.append("rect");
trackGroup.selectAll("rect")
.style("fill-opacity", ".4")
.style("stroke", function (d) {
var type = d[indexArray.type];
return type == "cpg" ? "red" : type == "shore" ? "green" : "yellow"
})
.style("fill", function (d) {
var type = d[indexArray.type];
return type == "cpg" ? "red" : type == "shore" ? "green" : "yellow"
})
.style("vector-effect", "non-scaling-stroke")
//.attr("class", "scalable")
.attr("height", function (d) {
var type = d[indexArray.type];
return type == "cpg" ? 40 : type == "shore" ? 20 : 15
})
.attr("width", function (d) {
return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start])
})
.attr("x", function (d) {
return thisScale(d[indexArray.start])
})
.attr("y", function (d) {
var type = d[indexArray.type];
var offset = type == "cpg" ? -20 : type == "shore" ? -10 : -7.5;
return offset;//height / 2 + margin + offset
})
addTooltip(trackGroup.selectAll("rect")
.filter(function (d) {
return d[indexArray.type] == "cpg";}), name, "cpg", cpgFileHandle);
addTooltip(trackGroup.selectAll("rect")
.filter(function (d) {
return d[indexArray.type] == "shore";}), name, "shore", shoreFileHandle);
addTooltip(trackGroup.selectAll("rect")
.filter(function (d) {
return d[indexArray.type] == "shelve";}), name, "shelve", shelveFileHandle);
}
var addTooltip = function(selection, name, type, fileHandle)
{
var start = (Math.round(xScale.domain()[0])).toString();
var end = (Math.round(xScale.domain()[1])).toString();
var scale = (end - start)/1000;
selection.each(
function(d){
$(this).qtip({
content: {
text: "Loading..."
},
position: {
my: 'top center',
at: 'top center',
target: 'mouse',
adjust: {
mouse: true, // Can be omitted (e.g. default behaviour)
y: 10
}
}
})
});
selection.each(function(){
var selected = $(this);
var hoverTimeout = 0;
$(this).mousemove(function(event) {
clearTimeout(hoverTimeout);
hoverTimeout = setTimeout(function(){
var pixelWidth = (xScale.domain()[1] - xScale.domain()[0])/1000
var min = (event.pageX - 60) * pixelWidth + xScale.domain()[0];
var max = (event.pageX - 58) * pixelWidth + xScale.domain()[0];
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
data: {
"loadTooltip": "",
"chrom": chrom_curr,
"trackName" : name,
"type" : type,
"min" : min,
"max": max,
'fileHandle': fileHandle
}
})
.then(function(content) {
// Set the tooltip content upon successful retrieval
selected.qtip('option', 'content.text', content);
selected.qtip('reposition', event);
}, function(xhr, status, error) {
// Upon failure... set the tooltip content to the status and error value
selected.qtip('option', 'content.text', status + ': ' + error);
});
} , 200);
});
});
}
this.updateTrack = function(){
var start = (Math.round(xScale.domain()[0])).toString();
var end = (Math.round(xScale.domain()[1])).toString();
var chrom = chrom_curr;
var fileHandles = [fileHandle];
var name = [this.name];
var LoadingText = group.append("g")
LoadingText.append("rect")
.attr("x", 450)
.attr("width", 100)
.attr("y", -10)
.attr("height", 20)
.attr("rx", 6)
.attr("ry", 6)
.style("fill-opacity", .6)
.style("fill", "white")
LoadingText.append("text")
.text("Loading...")
.attr("x", 475)
.attr("y", 5);
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
data: {
"getTrackData": "",
"fileHandles": fileHandles,
"name": name,
"chrom": chrom,
"start": start,
"end": end
}
}).success(function (returnData) {
drawTrack(returnData[name]);
data = returnData;
LoadingText.remove();
}
).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
}
var previousScale = 1;
this.zoomed = function() {
var thisScale = getScale();
if(zoom.scale() < redrawCutoff)
{
if(previousScale > redrawCutoff)
{
trackGroup.selectAll("rect")
.attr("width", function (d) {
return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start])
})
.attr("x", function (d) {
return thisScale(d[indexArray.start])
});
}
trackGroup.attr("transform", "translate(" + zoom.translate()[0] + ",0)scale(" + zoom.scale() + ",1)");
}
else
{
trackGroup.attr("transform", null);
trackGroup.selectAll("rect")
.attr("width", function (d) {
return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start])
})
.attr("x", function (d) {
return thisScale(d[indexArray.start])
});
}
previousScale = zoom.scale();
}
this.getData = function(){
return data;
}
this.getRange = function(){
var range;
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
async : false,
data: {
"getRange": "",
"fileHandles": [fileHandle],
"name": [name],
"chrom": chrom_curr
}
}).success(function (returnData) {
range = returnData;
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
return range;
}
}
function BedTrack(name, group, args) {
Track.call(this, name, group)
var trackGroup = this.trackGroup;
var fileHandle = args.fileHandle;
var data;
var redrawCutoff = 1000; //Scale at which rectangles will be drawn individually
var getScale = function(){
if(zoom.scale() < redrawCutoff)
return fullXScale;
else
return xScale;
}
var drawTrack = function(data, exons)
{
if (data.length === 0) {
return;
}
var thisScale = getScale();
var trackHeight = 10;
trackGroup.selectAll("rect")
.data(data, function (d) {
return d;
})
.exit()
.remove();
trackGroup.selectAll("rect")
.data(data, function (d) {
return d;
})
.enter()
.append("rect");
trackGroup.selectAll("rect")
.data(data, function (d) {
return d;
})
.attr("x", function (d) {
return thisScale(d[indexArray.start]);
})
.attr("y", function (d) {
return d[indexArray.score] > 0 ? -10 : d[indexArray.score] < 0 ? 0 : -5;
})
.attr("height", 10)
.attr("width", function (d) {
return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start]);
})
.style("fill-opacity", "1")
.style("stroke", function (d) {
return d[indexArray.score] > 0 ? "red" : d[indexArray.score] < 0 ? "green" : "grey";
})
.style("fill", function (d) {
return d[indexArray.score] > 0 ? "red" : d[indexArray.score] < 0 ? "green" : "grey";
})
.style("vector-effect", "non-scaling-stroke")
addTooltip(trackGroup.selectAll("rect")
.data(data, function (d) {
return d;}), name, "gene")
if (exons)
{
trackGroup.selectAll("rect")
.data(data, function (d) {
return d;
})
.exit()
.remove();
trackGroup.selectAll("rect")
.data(exons, function (d) {
return d;
})
.enter()
.append("rect");
trackGroup.selectAll("rect")
.data(exons, function (d) {
return d;
})
.attr("x", function (d) {
return thisScale(d[indexArray.start]);
})
.attr("y", -10)
.attr("height", 20)
.attr("width", function (d) {
return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start]);
})
.style("fill-opacity", ".8")
.style("stroke", "black")
.style("fill", "black")
.style("vector-effect", "non-scaling-stroke")
addTooltip(trackGroup.selectAll("rect")
.data(exons, function (d) {
return d;}), name, "exon")
}
}
var addTooltip = function(selection, name, type)
{
var start = (Math.round(xScale.domain()[0])).toString();
var end = (Math.round(xScale.domain()[1])).toString();
var scale = (end - start)/1000;
selection.each(
function(d){
$(this).qtip({
content: {
text: "Loading..."
},
position: {
my: 'top center',
at: 'top center',
target: 'mouse',
adjust: {
mouse: true, // Can be omitted (e.g. default behaviour)
y: 10
}
}
})
});
selection.each(function(){
var selected = $(this);
var hoverTimeout = 0;
$(this).mousemove(function(event) {
clearTimeout(hoverTimeout);
hoverTimeout = setTimeout(function(){
var pixelWidth = (xScale.domain()[1] - xScale.domain()[0])/1000
var min = (event.pageX - 60) * pixelWidth + xScale.domain()[0];
var max = (event.pageX - 58) * pixelWidth + xScale.domain()[0];
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
data: {
"loadTooltip": "",
"chrom": chrom_curr,
"trackName" : name,
"type" : type,
"min" : min,
"max": max,
'fileHandle': fileHandle
}
})
.then(function(content) {
// Set the tooltip content upon successful retrieval
selected.qtip('option', 'content.text', content);
selected.qtip('reposition', event);
}, function(xhr, status, error) {
// Upon failure... set the tooltip content to the status and error value
selected.qtip('option', 'content.text', status + ': ' + error);
});
} , 200);
});
});
}
this.updateTrack = function(){
var start = (Math.round(xScale.domain()[0])).toString();
var end = (Math.round(xScale.domain()[1])).toString();
var chrom = chrom_curr;
var fileHandles = [fileHandle];
var name = [this.name];
var LoadingText = group.append("g")
LoadingText.append("rect")
.attr("x", 450)
.attr("width", 100)
.attr("y", -10)
.attr("height", 20)
.attr("rx", 6)
.attr("ry", 6)
.style("fill-opacity", .6)
.style("fill", "white")
LoadingText.append("text")
.text("Loading...")
.attr("x", 475)
.attr("y", 5);
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
data: {
"getTrackData": "",
"fileHandles": fileHandles,
"name": name,
"chrom": chrom,
"start": start,
"end": end
}
}).success(function (returnData) {
if(returnData.length === 1) //if no exons exist
drawTrack(returnData[name]);
else
drawTrack(returnData[name][0], returnData[name][1]);
data = returnData;
LoadingText.remove();
}
).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
this.zoomed();
}
var previousScale = 1;
this.zoomed = function() {
var thisScale = getScale();
if(zoom.scale() < redrawCutoff)
{
if(previousScale > redrawCutoff)
{
trackGroup.selectAll("rect")
.attr("width", function (d) {
return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start])
})
.attr("x", function (d) {
return thisScale(d[indexArray.start])
});
}
trackGroup.attr("transform", "translate(" + zoom.translate()[0] + ",0)scale(" + zoom.scale() + ",1)");
}
else
{
trackGroup.attr("transform", null);
trackGroup.selectAll("rect")
.attr("width", function (d) {
return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start])
})
.attr("x", function (d) {
return thisScale(d[indexArray.start])
});
}
previousScale = zoom.scale();
}
this.getData = function(){
return data;
}
this.getRange = function(){
var range;
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
async : false,
data: {
"getRange": "",
"fileHandles": [fileHandle],
"name": [name],
"chrom": chrom_curr
}
}).success(function (returnData) {
range = returnData;
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
return range;
}
}
function FastaTrack(name, group, args) {
Track.call(this, name, group);
var trackGroup = this.trackGroup;
var file = args.file;
var indexFile = args.indexFile
var drawTrack = function(data)
{
trackGroup.selectAll("text")
.data(data, function (d) {
return d;
})
.exit()
.remove();
trackGroup.selectAll("text")
.data(data, function (d) {
return d;
})
.enter()
.append("text")
trackGroup.selectAll("text")
.data(data, function (d) {
return d;
})
.text(function (d) {return d[0]})
.attr("x", function (d) {
return xScale(d[1]) - 2; //-2 to center text
})
addTooltip(trackGroup.selectAll("text"))
}
var clearTrack = function()
{
trackGroup.selectAll("text").remove();
}
var addTooltip = function(selection)
{
var start = (Math.round(xScale.domain()[0])).toString();
var end = (Math.round(xScale.domain()[1])).toString();
var scale = (end - start)/1000;
selection.each(
function(d){
$(this).qtip({
content: {
text: d[1]
},
position: {
my: 'top center',
at: 'top center',
target: 'mouse',
adjust: {
mouse: true, // Can be omitted (e.g. default behaviour)
y: 10
}
}
})
});
}
this.zoomed = function(){
trackGroup.selectAll("text")
.attr("x", function (d) {
return xScale(d[1]) - 2;
})
}
this.updateTrack = function(){
if( zoom.scale() >= (panExtent[1] - panExtent[0]) / 100/ initialZoom)
{
var LoadingText = group.append("g")
LoadingText.append("rect")
.attr("x", 450)
.attr("width", 100)
.attr("y", -10)
.attr("height", 20)
.attr("rx", 6)
.attr("ry", 6)
.style("fill-opacity", .6)
.style("fill", "white")
LoadingText.append("text")
.text("Loading...")
.attr("x", 475)
.attr("y", 5);
var xStart = Math.floor(xScale.domain()[0]);
var length = Math.ceil(xScale.domain()[1]) - xStart;
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
data: {
"loadFastaData": "",
"chrom" : chrom_curr,
"start": xStart,
"length": length,
"file": file,
"indexFile": indexFile
}
}).success(function (returnData) {
var data = returnData.split("");
for(var i = 0; i < returnData.length; i++)
{
data[i] = [data[i], xStart + i]
}
drawTrack(data);
data = returnData;
LoadingText.remove();
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
}
else
{
clearTrack();
}
}
this.getRange = function(){
var range;
$.ajax({
url: serviceURL,
type: 'POST',
dataType: "json",
async : false,
data: {
"getFastaRange": "",
"chrom": chrom_curr,
"indexFile": indexFile
}
}).success(function (returnData) {
range = returnData;
}).error(function (req, status, error) {
$("body").append(status + ": " + error);
});
return range;
}
}
}