diff --git a/VQI_GenomeBrowser.js b/VQI_GenomeBrowser.js index 2452ba7..9482af1 100755 --- a/VQI_GenomeBrowser.js +++ b/VQI_GenomeBrowser.js @@ -51,7 +51,6 @@ function VQI_GenomeBrowser(id, serviceURL) { else { graph(chrom, chrom_start, chrom_end); - } } else @@ -62,7 +61,7 @@ function VQI_GenomeBrowser(id, serviceURL) { var addRecentTrack = function(){ var track = $("#" + divId + " #RecentTracks").val(); for (i in trackList){ - if (trackList[i]['name'] == track){ + if (trackList[i].name == track){ return; } } @@ -194,8 +193,8 @@ function VQI_GenomeBrowser(id, serviceURL) { var track1Select = "Track1: "; @@ -203,8 +202,8 @@ function VQI_GenomeBrowser(id, serviceURL) { var track2Select = " Track2: "; @@ -220,46 +219,23 @@ function VQI_GenomeBrowser(id, serviceURL) { this.makeFormForColocalization(); var removeSelectedTracks = function () { - var tracknames = [] - for (var i in trackList) { - if (graphRegion.selectAll("g").data([trackList[i]['name']], function (d) { - return d; - }).select("#check").node().checked) + for (var i = trackList.length - 1; i >= 0; i--) { + if (trackList[i].isSelected()) { - tracknames.push(trackList[i]['name']); + trackList[i].group.remove(); + trackList.splice(i, 1); } } - for (var i in tracknames) { - removeTrack(tracknames[i]); - } reorderTracks(); - } - - var removeTrack = function (removedTrackName) { - if (removedTrackName != null) - { - for (var i in trackList) { - var thisTrack = trackList[i]; - if (thisTrack['name'] == removedTrackName) { - svg.selectAll("g").data([trackList[i]['name']], function (d) { - return d; - }).remove(); - trackList.splice(i, 1); - break; - } - } - } updateAllTracksSelectBoxes(); - }; + } this.getSelectedTrackNames = function(){ var tracknames = [] for (var i in trackList) { - if (graphRegion.selectAll("g").data([trackList[i]['name']], function (d) { - return d; - }).select("#check").node().checked) + if (trackList[i].isSelected()) { - tracknames.push(trackList[i]['name']); + tracknames.push(trackList[i].name); } } return tracknames; @@ -277,11 +253,9 @@ function VQI_GenomeBrowser(id, serviceURL) { var exportSelectedTracks = function () { var tracknames = [] for (var i in trackList) { - if (graphRegion.selectAll("g").data([trackList[i]['name']], function (d) { - return d; - }).select("#check").node().checked) + if (trackList[i].isSelected()) { - tracknames.push(trackList[i]['name']); + tracknames.push(trackList[i].name); } } for (var i in tracknames) { @@ -293,7 +267,7 @@ function VQI_GenomeBrowser(id, serviceURL) { var track = thisObj.getTrackByName(track_name); - exportTrackToText(track, track_name); + exportTrackToText(track.getData(), track_name); } @@ -376,8 +350,6 @@ function VQI_GenomeBrowser(id, serviceURL) { //set up scales and axis - var fullXScale = d3.scale.linear(); - var xScale = d3.scale.linear(); var xAxis = d3.svg.axis() @@ -403,16 +375,10 @@ function VQI_GenomeBrowser(id, serviceURL) { zoom.translate([panLimit(), 0]); - //svg.selectAll("g.scalable").attr("transform", "translate(" + zoom.translate()[0] + ",0)scale(" + zoom.scale() + ",1)"); - - //slow, scales elements individually, draws at large zooms - svg.selectAll("g.scalable").selectAll("rect") - .attr("width", function (d) { - return xScale(d[indexArray.end]) - xScale(d[indexArray.start]) - }) - .attr("x", function (d) { - return xScale(d[indexArray.start]) - }); + for(i in trackList) + { + trackList[i].zoomed(); + } xAxisSelection.call(xAxis); @@ -427,7 +393,6 @@ function VQI_GenomeBrowser(id, serviceURL) { "font-size": "11px"}); if (! zoomOnly){ - //updateTrack(); if (waitTime != undefined) { clearTimeout(waitTime); @@ -438,7 +403,6 @@ function VQI_GenomeBrowser(id, serviceURL) { }; var uploadFile = function(data,name,genome){ - //var rows = data.split("\n"); headerArray = ["CHROM","CHROM_START","CHROM_END","GENESYMBOL","SCORE","STRAND"]; for (i in headerArray) { @@ -480,64 +444,9 @@ function VQI_GenomeBrowser(id, serviceURL) { var updateTrack = function(){ if (isready){ - var start = (Math.round(xScale.domain()[0])).toString(); - var end = (Math.round(xScale.domain()[1])).toString(); - var chrom = chrom_curr; - var fileHandles = []; - var name = []; - for (i in trackList) { - for(j in trackInfo){ - if(trackInfo[j].name == trackList[i].name){ - fileHandles.push(trackInfo[j].fileHandle); - break; - } - } - name.push(trackList[i].name); - } - - $.ajax({ - url: serviceURL, - type: 'POST', - dataType: "json", - data: { - "getTrackData": "", - "fileHandles": fileHandles, - "name": name, - "chrom": chrom, - "start": start, - "end": end - } - - }).success(function (returnData) { - for (i in trackList){ - var name = trackList[i]['name']; - var type = trackList[i]['type']; - if(returnData[name] != undefined){ - trackList[i] = returnData[name]; - trackList[i]['name'] = name; - trackList[i]['type'] = type; - if (name == "HG19"){ - addBEDTrack(returnData[name][0], name, returnData[name][1]); - } - else if (name == "cpg"){ - addCpgTrack(returnData[name], name); - } - else{ - addBEDTrack(returnData[name], name); - } - } - } - - zoomOnly = true; - zoomed(); - zoomOnly = false; - - - }).error(function (req, status, error) { - $("body").append(status + ": " + error); - }); - + trackList[i].updateTrack(); + } } } var testRemove = function(){ @@ -629,10 +538,6 @@ function VQI_GenomeBrowser(id, serviceURL) { panExtent[1] = isNaN(max) ? width : max; var distance = (panExtent[1] - panExtent[0]) / 10000 - - fullXScale = d3.scale.linear() - .domain([panExtent[0], panExtent[0] + distance]) - .range([0, width]); } var graph = function (chromosome, min, max) { @@ -648,19 +553,13 @@ function VQI_GenomeBrowser(id, serviceURL) { setBounds(Number(min), Number(max)); } for (var i in trackList) { - addOneTrack(trackList[i], trackList[i]['name'], trackList[i]['type'], i); + trackList[i].updateTrack(); } } - var addOneTrack = function (data, name, type, i) { - //console.log("addonetrack"); - i = Number(i); - var trackIndex; - if (!isNaN(i)) { - trackIndex = i; - } else { - trackIndex = trackList.length; - } + var addOneTrack = function (data, name, type, fileHandle) { + + var trackIndex = trackList.length; //check if min and max of whole graph needs to be readjusted var min = d3.min(data, function (d) { @@ -682,18 +581,11 @@ function VQI_GenomeBrowser(id, serviceURL) { //name of track name = name || "track-" + (trackIndex + 1); - if (type == 'cpg') { - initTrack(name); - addCpgTrack(thisData, name); - data['type'] = 'cpg'; - } else { - initTrack(name); - addBEDTrack(thisData, name); - data['type'] = 'bed'; - } + if(type == "cpg") + trackList.push(new CpgTrack(name, fileHandle, graphRegion.append("g"))); + if(type == "bed") + trackList.push(new BedTrack(name, fileHandle, graphRegion.append("g"))); - data['name'] = name; - //console.log(data); clipPath.attr("height", Number(svg.attr("height"))); zoomOnly = true; zoomed(); @@ -704,390 +596,11 @@ function VQI_GenomeBrowser(id, serviceURL) { var reorderTracks = function () { svg.attr("height", height + 2 * margin + trackList.length * (trackHeight + bufferSpace)); for (var i in trackList) { - graphRegion.selectAll("g").data([trackList[i]['name']], function (d) { - return d; - }) - .attr("transform", "translate(" + 0 + "," + (margin + bufferSpace + i * (trackHeight + bufferSpace)) + ")"); + trackList[i].group.attr("transform", "translate(" + 0 + "," + (margin + bufferSpace + i * (trackHeight + bufferSpace)) + ")"); } } - - - - var initTrack = function (name) { - graphRegion.selectAll("g").data([name], function (d) { - return d; - }).enter().append("g"); - - var trackGroup = graphRegion.selectAll("g").data([name], function (d) { - return d; - }) - - //Just a line - trackGroup.selectAll("line").data([name], function (d) { - return d; - }).enter().append("line") - .attr("x1", 0) - .attr("y1", 0) - .attr("x2", width) - .attr("y2", 0) - .style("stroke", "blue") - .style("stroke-opacity" , 0.5); - - trackGroup.selectAll("text").data([name], function (d) { - return d; - }).enter().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); - - if (trackGroup.select(".checkbox").empty()) - { - trackGroup.append("foreignObject") - .attr("width", 50) - .attr("height", 20) - .attr("x", width) - .attr("y", -10) - .attr("class", "checkbox") - .append("xhtml:div") - .html("
") - .on("click", function () { - xAxisSelection.call(xAxis);//I have no idea why it won't redraw the checkbox unless I call this - }); - } - - if (trackGroup.select("path.up").empty()) - { - trackGroup.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(); - }); - } - - if (trackGroup.select("path.down").empty()) - { - trackGroup.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(); - }); - } - - if (trackGroup.select("g.scalable").empty()) - { - trackGroup.append("g") - .attr("clip-path", "url(#clip)") - .append("g") - .attr("class", "scalable"); - } - } - - var addCpgTrack = function (data, name) { - - var trackScalableGroup = graphRegion.selectAll("g").data([name], function (d) { - return d; - }).select("g.scalable"); - - trackScalableGroup.selectAll("rect") - .data(data, function (d) { - return d; - }) - .exit() - .remove(); - - trackScalableGroup.selectAll("rect") - .data(data, function (d) { - return d; - }) - .enter() - .append("rect"); - - trackScalableGroup.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 xScale(d[indexArray.end]) - xScale(d[indexArray.start]) - }) - .attr("x", function (d) { - return xScale(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 - }) - .on("mouseenter", function(){console.log("mouseenter")}) - .on("mouseleave", function(){console.log("mouseleave")}) - - - addTooltip(trackScalableGroup.selectAll("rect") - .filter(function (d) { - return d[indexArray.type] == "cpg";}), name, "cpg"); - - addTooltip(trackScalableGroup.selectAll("rect") - .filter(function (d) { - return d[indexArray.type] == "shore";}), name, "shore"); - - addTooltip(trackScalableGroup.selectAll("rect") - .filter(function (d) { - return d[indexArray.type] == "shelve";}), name, "shelve"); - - /*$(trackScalableGroup.selectAll("rect")[0]).mousemove(function(event){ - $(this).mouseenter(); - });*/ - - } - - var addBEDTrack = function (data, name, exons) { - testdata = data; - /** - * @author Pujan Joshi - * @since April 16, 2015 - * - * if data is empty, we do not need to proceed. Trying to check for - * some records in empty array was causing error in this method. - * - */ - if (data.length === 0) { - return; - } - - var trackHeight = 10; - - var trackScalableGroup = graphRegion.selectAll("g").data([name], function (d) { - return d; - }).select("g.scalable"); - - trackScalableGroup.selectAll("rect") - .data(data, function (d) { - return d; - }) - .exit() - .remove(); - - trackScalableGroup.selectAll("rect") - .data(data, function (d) { - return d; - }) - .enter() - .append("rect"); - - var tracks = trackScalableGroup.selectAll("rect") - .data(data, function (d) { - return d; - }) - .attr("x", function (d) { - return fullXScale(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 fullXScale(d[indexArray.end]) - fullXScale(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") - .attr("class", "scalable") - - addTooltip(trackScalableGroup.selectAll("rect") - .data(data, function (d) { - return d;}), name, "gene") - - if (exons) - { - trackScalableGroup.selectAll("rect") - .data(data, function (d) { - return d; - }) - .exit() - .remove(); - - trackScalableGroup.selectAll("rect") - .data(exons, function (d) { - return d; - }) - .enter() - .append("rect"); - trackScalableGroup.selectAll("rect") - .data(exons, function (d) { - return d; - }) - .attr("x", function (d) { - return fullXScale(d[indexArray.start]); - }) - .attr("y", -10) - .attr("height", 20) - .attr("width", function (d) { - return fullXScale(d[indexArray.end]) - fullXScale(d[indexArray.start]); - }) - .style("fill-opacity", ".8") - .style("stroke", "black") - .style("fill", "black") - .style("vector-effect", "non-scaling-stroke") - .attr("class", "scalable") - - addTooltip(trackScalableGroup.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; - - var fileHandle = ''; - if(type == "cpg"){ - fileHandle = 'upload1437097194'; - } - else if(type == "shelve"){ - fileHandle = 'upload1437098473'; - } - else if (type == "shore"){ - fileHandle = 'upload1437098556'; - } - else if (name == "HG19"){ - fileHandle = 'upload1436481988'; - } - else { - for(i in trackInfo){ - if(name == trackInfo[i].name){ - fileHandle = trackInfo[i].fileHandle; - break; - } - } - } - selection.each( - function(d){ - $(this).qtip({ - content: { - text: function(event, api) { - var min,max; - - min = d[indexArray.start]; - max = d[indexArray.end]; - - $.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 - api.set('content.text', content); - }, function(xhr, status, error) { - // Upon failure... set the tooltip content to the status and error value - api.set('content.text', status + ': ' + error); - }); - - } - }, - 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 - 59) * 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); - }, 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.addTrackFromDatabase = function(){ + this.addTrackFromDatabase = function() { var chrom = "chr1"; var fileHandles = []; var name = []; @@ -1116,12 +629,10 @@ function VQI_GenomeBrowser(id, serviceURL) { updateTrack(); }).error(function (req, status, error) { $("body").append(status + ": " + error); - }); - - + }); } - this.addOneTrackFromDatabase = function(fileHandle,name,type){ + this.addOneTrackFromDatabase = function(fileHandle,name,type) { var chrom = "chr1"; $.ajax({ @@ -1136,7 +647,7 @@ function VQI_GenomeBrowser(id, serviceURL) { } }).success(function (returnData) { - thisObj.addTrack(returnData[0], name, type); + thisObj.addTrack(returnData[0], name, type, fileHandle); isready = true; updateTrack(); }).error(function (req, status, error) { @@ -1144,16 +655,14 @@ function VQI_GenomeBrowser(id, serviceURL) { }); } - this.addTrack = function (data, name, type) { + this.addTrack = function (data, name, type, fileHandle) { if(data[0][0] != "chrom") { data.unshift(["chrom", "chrom_start", "chrom_end", "name", "score", "strand"]) } - data = addOneTrack(data, name, type); + data = addOneTrack(data, name, type, fileHandle); //console.log("addtrack"); - trackList.push(data); - reorderTracks(); updateAllTracksSelectBoxes(); @@ -1265,7 +774,7 @@ function VQI_GenomeBrowser(id, serviceURL) { this.getTrackByName = function (name) { for (var i in trackList) { var thisTrack = trackList[i]; - if (thisTrack['name'] === name) { + if (thisTrack.name === name) { return thisTrack; } } @@ -1274,7 +783,7 @@ function VQI_GenomeBrowser(id, serviceURL) { var getTrackIndexByName = function (name) { for (var i in trackList) { var thisTrack = trackList[i]; - if (thisTrack['name'] === name) { + if (thisTrack.name === name) { return i; } } @@ -1291,7 +800,7 @@ function VQI_GenomeBrowser(id, serviceURL) { selectBox.options.length = 0; var optionIndex = 0; for (var i in trackList) { - var text = trackList[i]['name']; + var text = trackList[i].name; var value = text; selectBox.options[optionIndex++] = new Option(text, value); } @@ -1375,4 +884,471 @@ function VQI_GenomeBrowser(id, serviceURL) { $("body").append(status + ": " + error); }); } -} \ No newline at end of file + + 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) + .attr("y", -10) + .attr("class", "checkbox") + .append("xhtml:div") + .html("
") + .on("click", function () { + xAxisSelection.call(xAxis);//I have no idea why it won't redraw the checkbox unless I call this + }); + + + 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(){}; + } + + function CpgTrack(name, fileHandle, group) { + Track.call(this, name, group); + var trackGroup = this.trackGroup; + + this.fileHandle = fileHandle; + var tempHandles = fileHandle.split(","); + var cpgFileHandle = tempHandles[0]; + var shelveFileHandle = tempHandles[1]; + var shoreFileHandle = tempHandles[2]; + var data; + + var drawTrack = function(data) + { + 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 xScale(d[indexArray.end]) - xScale(d[indexArray.start]) + }) + .attr("x", function (d) { + return xScale(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); + }, 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]; + + $.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; + } + ).error(function (req, status, error) { + $("body").append(status + ": " + error); + }); + } + + this.zoomed = function() { + trackGroup.selectAll("rect") + .attr("width", function (d) { + return xScale(d[indexArray.end]) - xScale(d[indexArray.start]) + }) + .attr("x", function (d) { + return xScale(d[indexArray.start]) + }); + } + + this.getData = function(){ + return data; + } + } + + function BedTrack(name, fileHandle, group) { + Track.call(this, name, group) + var trackGroup = this.trackGroup; + + this.fileHandle = fileHandle; + var tempHandles = fileHandle.split(","); + var data; + + var drawTrack = function(data, exons) + { + if (data.length === 0) { + return; + } + + var trackHeight = 10; + + var trackScalableGroup = graphRegion.selectAll("g").data([name], function (d) { + return d; + }).select("g.scalable"); + + 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 xScale(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 xScale(d[indexArray.end]) - xScale(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 xScale(d[indexArray.start]); + }) + .attr("y", -10) + .attr("height", 20) + .attr("width", function (d) { + return xScale(d[indexArray.end]) - xScale(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); + }, 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]; + + $.ajax({ + url: serviceURL, + type: 'POST', + dataType: "json", + data: { + "getTrackData": "", + "fileHandles": fileHandles, + "name": name, + "chrom": chrom, + "start": start, + "end": end + } + + }).success(function (returnData) { + if(returnData[name][0][0].length === 4) //if no exons exist + drawTrack(returnData[name]); + else + drawTrack(returnData[name][0], returnData[name][1]); + + data = returnData; + } + ).error(function (req, status, error) { + $("body").append(status + ": " + error); + }); + } + + this.zoomed = function() { + trackGroup.selectAll("rect") + .attr("width", function (d) { + return xScale(d[indexArray.end]) - xScale(d[indexArray.start]) + }) + .attr("x", function (d) { + return xScale(d[indexArray.start]) + }); + } + + this.getData = function(){ + return data; + } + } + + +} + diff --git a/VQI_GenomeBrowserDemo.html b/VQI_GenomeBrowserDemo.html index f8d40ff..69a056f 100644 --- a/VQI_GenomeBrowserDemo.html +++ b/VQI_GenomeBrowserDemo.html @@ -22,29 +22,16 @@