Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Shift+Drag to select a region, then click on region to zoom
  • Loading branch information
csw11004 committed Sep 13, 2015
1 parent b175432 commit a4616f0
Showing 1 changed file with 179 additions and 42 deletions.
221 changes: 179 additions & 42 deletions VQI_GenomeBrowser.js
Expand Up @@ -13,6 +13,8 @@ function VQI_GenomeBrowser(id, serviceURL) {


var panExtent = [0, width]; var panExtent = [0, width];


var initialZoom = 1 //defines what will be considered a zoom scale of 1

var trackList = []; var trackList = [];


var genomeData = []; var genomeData = [];
Expand All @@ -24,7 +26,6 @@ function VQI_GenomeBrowser(id, serviceURL) {


var testdata; var testdata;
var isready = false; var isready = false;
var zoomOnly = false;
var waitTime; var waitTime;
var loadCount = 0; var loadCount = 0;


Expand Down Expand Up @@ -390,7 +391,7 @@ function VQI_GenomeBrowser(id, serviceURL) {
.append("svg") .append("svg")
.attr("width", width + 2 * margin) .attr("width", width + 2 * margin)
.attr("height", height + 2 * margin) .attr("height", height + 2 * margin)
.style("border", "1px solid black"); .style("border", "1px solid black")


var svg = this.svg; var svg = this.svg;


Expand All @@ -400,6 +401,8 @@ function VQI_GenomeBrowser(id, serviceURL) {


var xScale = d3.scale.linear(); var xScale = d3.scale.linear();


var fullXScale = d3.scale.linear();

var xAxis = d3.svg.axis() var xAxis = d3.svg.axis()
.scale(xScale) .scale(xScale)
.orient("bottom") .orient("bottom")
Expand All @@ -412,6 +415,67 @@ function VQI_GenomeBrowser(id, serviceURL) {


var zoom = d3.behavior.zoom(); 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") var clipPath = graphRegion.append("clipPath")
.attr("id", "clip") .attr("id", "clip")
.append("rect") .append("rect")
Expand All @@ -421,6 +485,8 @@ function VQI_GenomeBrowser(id, serviceURL) {


var zoomed = function () { var zoomed = function () {


svg.selectAll("rect.selection").remove();

zoom.translate([panLimit(), 0]); zoom.translate([panLimit(), 0]);


for(i in trackList) for(i in trackList)
Expand All @@ -440,13 +506,12 @@ function VQI_GenomeBrowser(id, serviceURL) {
"font-family": "sans-serif", "font-family": "sans-serif",
"font-size": "11px"}); "font-size": "11px"});


if (! zoomOnly){ if (waitTime != undefined)
if (waitTime != undefined) {
{ clearTimeout(waitTime);
clearTimeout(waitTime); }
} waitTime = setTimeout(updateTrack, 100);
waitTime = setTimeout(updateTrack, 100);
}
$("#" + divId + " #navigate").val(chrom_curr + ":" + Math.round(xScale.domain()[0]) + "-" + Math.round(xScale.domain()[1])); $("#" + divId + " #navigate").val(chrom_curr + ":" + Math.round(xScale.domain()[0]) + "-" + Math.round(xScale.domain()[1]));
}; };


Expand Down Expand Up @@ -521,25 +586,24 @@ function VQI_GenomeBrowser(id, serviceURL) {
}; };


var setBounds = function (min, max) { var setBounds = function (min, max) {
panExtent[0] = 0;
var xMin = Number(min) > panExtent[0] ? Number(min) : panExtent[0]; var xMin = Number(min) > panExtent[0] ? Number(min) : panExtent[0];
var xMax = Number(max) < panExtent[1] ? Number(max) : panExtent[1]; var xMax = Number(max) < panExtent[1] ? Number(max) : panExtent[1];
var initialZoom = 10000 //defines what will be considered a zoom scale of 1
var range = (panExtent[1] - panExtent[0]) / initialZoom var range = (panExtent[1] - panExtent[0]) / initialZoom

xScale.domain([panExtent[0], panExtent[0] + range]) xScale.domain([panExtent[0], panExtent[0] + range])
.range([0, width]); .range([0, width]);


zoom.scaleExtent([1 / initialZoom, (panExtent[1] - panExtent[0]) / 50 / initialZoom]); zoom.scaleExtent([1 / initialZoom, (panExtent[1] - panExtent[0]) / 50 / initialZoom]);


var prevTranslate = zoom.translate();
var prevScale = zoom.scale();

zoom.x(xScale).on("zoom", zoomed); zoom.x(xScale).on("zoom", zoomed);


svg.call(zoom).on("dblclick.zoom", null); svg.call(zoom).on("dblclick.zoom", null);


var scale = (panExtent[1] - panExtent[0]) / (xMax - xMin) / initialZoom; var scale = (panExtent[1] - panExtent[0]) / (xMax - xMin) / initialZoom;


zoom.scale(scale); zoom.scale(scale)



//translates scale with regards to the middle of xMin and xMax //translates scale with regards to the middle of xMin and xMax
var divisor = (width) / ((xScale.domain()[1] - xScale.domain()[0]) * scale); var divisor = (width) / ((xScale.domain()[1] - xScale.domain()[0]) * scale);
Expand All @@ -552,12 +616,18 @@ function VQI_GenomeBrowser(id, serviceURL) {


var zoomWidth = midScale((xMax + xMin) / 2); var zoomWidth = midScale((xMax + xMin) / 2);


zoom.translate([zoomWidth, 0]) //transitions start from the previous transition, so I make a transition that first zooms
.scale(scale); //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)
})


zoomOnly = true;
zoomed(); zoomed();
zoomOnly = false;
} }


var setPanExtent = function (min, max) { var setPanExtent = function (min, max) {
Expand Down Expand Up @@ -586,7 +656,11 @@ function VQI_GenomeBrowser(id, serviceURL) {
panExtent[0] = isNaN(min) ? 0 : min; panExtent[0] = isNaN(min) ? 0 : min;
panExtent[1] = isNaN(max) ? width : max; panExtent[1] = isNaN(max) ? width : max;


var distance = (panExtent[1] - panExtent[0]) / 10000 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 graph = function (chromosome, min, max) {
Expand Down Expand Up @@ -647,7 +721,7 @@ function VQI_GenomeBrowser(id, serviceURL) {
var reorderTracks = function () { var reorderTracks = function () {
svg.attr("height", height + 2 * margin + trackList.length * (trackHeight + bufferSpace)); svg.attr("height", height + 2 * margin + trackList.length * (trackHeight + bufferSpace));
for (var i in trackList) { for (var i in trackList) {
trackList[i].group.attr("transform", "translate(" + 0 + "," + (margin + bufferSpace + i * (trackHeight + bufferSpace)) + ")"); trackList[i].group.transition().attr("transform", "translate(" + 0 + "," + (margin + bufferSpace + i * (trackHeight + bufferSpace)) + ")");
} }
} }


Expand Down Expand Up @@ -1031,9 +1105,19 @@ function VQI_GenomeBrowser(id, serviceURL) {
var shelveFileHandle = tempHandles[1]; var shelveFileHandle = tempHandles[1];
var shoreFileHandle = tempHandles[2]; var shoreFileHandle = tempHandles[2];
var data; var data;
var redrawCutoff = 1000;

var getScale = function(){
if(zoom.scale() < redrawCutoff)
return fullXScale;
else
return xScale;
}


var drawTrack = function(data) var drawTrack = function(data)
{ {
var thisScale = getScale();

trackGroup.selectAll("rect") trackGroup.selectAll("rect")
.data(data, function (d) { .data(data, function (d) {
return d; return d;
Expand Down Expand Up @@ -1065,10 +1149,10 @@ function VQI_GenomeBrowser(id, serviceURL) {
return type == "cpg" ? 40 : type == "shore" ? 20 : 15 return type == "cpg" ? 40 : type == "shore" ? 20 : 15
}) })
.attr("width", function (d) { .attr("width", function (d) {
return xScale(d[indexArray.end]) - xScale(d[indexArray.start]) return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start])
}) })
.attr("x", function (d) { .attr("x", function (d) {
return xScale(d[indexArray.start]) return thisScale(d[indexArray.start])
}) })
.attr("y", function (d) { .attr("y", function (d) {
var type = d[indexArray.type]; var type = d[indexArray.type];
Expand Down Expand Up @@ -1179,14 +1263,35 @@ function VQI_GenomeBrowser(id, serviceURL) {
}); });
} }


var previousScale = 1;
this.zoomed = function() { this.zoomed = function() {
trackGroup.selectAll("rect") var thisScale = getScale();
.attr("width", function (d) { if(zoom.scale() < redrawCutoff)
return xScale(d[indexArray.end]) - xScale(d[indexArray.start]) {
}) if(previousScale > redrawCutoff)
.attr("x", function (d) { {
return xScale(d[indexArray.start]) 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(){ this.getData = function(){
Expand All @@ -1201,13 +1306,23 @@ function VQI_GenomeBrowser(id, serviceURL) {
this.fileHandle = fileHandle; this.fileHandle = fileHandle;
var tempHandles = fileHandle.split(","); var tempHandles = fileHandle.split(",");
var data; var data;
var redrawCutoff = 1000;

var getScale = function(){
if(zoom.scale() < redrawCutoff)
return fullXScale;
else
return xScale;
}


var drawTrack = function(data, exons) var drawTrack = function(data, exons)
{ {
if (data.length === 0) { if (data.length === 0) {
return; return;
} }


var thisScale = getScale();

var trackHeight = 10; var trackHeight = 10;


trackGroup.selectAll("rect") trackGroup.selectAll("rect")
Expand All @@ -1229,14 +1344,14 @@ function VQI_GenomeBrowser(id, serviceURL) {
return d; return d;
}) })
.attr("x", function (d) { .attr("x", function (d) {
return xScale(d[indexArray.start]); return thisScale(d[indexArray.start]);
}) })
.attr("y", function (d) { .attr("y", function (d) {
return d[indexArray.score] > 0 ? -10 : d[indexArray.score] < 0 ? 0 : -5; return d[indexArray.score] > 0 ? -10 : d[indexArray.score] < 0 ? 0 : -5;
}) })
.attr("height", 10) .attr("height", 10)
.attr("width", function (d) { .attr("width", function (d) {
return xScale(d[indexArray.end]) - xScale(d[indexArray.start]); return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start]);
}) })
.style("fill-opacity", "1") .style("fill-opacity", "1")
.style("stroke", function (d) { .style("stroke", function (d) {
Expand Down Expand Up @@ -1271,12 +1386,12 @@ function VQI_GenomeBrowser(id, serviceURL) {
return d; return d;
}) })
.attr("x", function (d) { .attr("x", function (d) {
return xScale(d[indexArray.start]); return thisScale(d[indexArray.start]);
}) })
.attr("y", -10) .attr("y", -10)
.attr("height", 20) .attr("height", 20)
.attr("width", function (d) { .attr("width", function (d) {
return xScale(d[indexArray.end]) - xScale(d[indexArray.start]); return thisScale(d[indexArray.end]) - thisScale(d[indexArray.start]);
}) })
.style("fill-opacity", ".8") .style("fill-opacity", ".8")
.style("stroke", "black") .style("stroke", "black")
Expand Down Expand Up @@ -1383,17 +1498,39 @@ function VQI_GenomeBrowser(id, serviceURL) {
} }
).error(function (req, status, error) { ).error(function (req, status, error) {
$("body").append(status + ": " + error); $("body").append(status + ": " + error);
}); });
this.zoomed();
} }


var previousScale = 1;
this.zoomed = function() { this.zoomed = function() {
trackGroup.selectAll("rect") var thisScale = getScale();
.attr("width", function (d) { if(zoom.scale() < redrawCutoff)
return xScale(d[indexArray.end]) - xScale(d[indexArray.start]) {
}) if(previousScale > redrawCutoff)
.attr("x", function (d) { {
return xScale(d[indexArray.start]) 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(){ this.getData = function(){
Expand Down Expand Up @@ -1480,7 +1617,7 @@ function VQI_GenomeBrowser(id, serviceURL) {
this.updateTrack = function(){ this.updateTrack = function(){
if(faFile) if(faFile)
{ {
if( zoom.scale() >= (panExtent[1] - panExtent[0]) / 100 / 10000) if( zoom.scale() >= (panExtent[1] - panExtent[0]) / 100/ initialZoom)
{ {
var offset; var offset;
for(var i = 0; i < faiData.length; i++) for(var i = 0; i < faiData.length; i++)
Expand Down

0 comments on commit a4616f0

Please sign in to comment.