/**
* Get the size of the svg based on the no. of rows and row length and other parameter.,.
* @param {Object} parameters - Contains parameters of width, letter space etc., to draw SVG
* @param {String} seq - Contains protein Sequence
*/
function getSvgSize(parameters,seq)
{
let seqLen = seq.length;
let num_of_rows = parseInt(seqLen/parameters.row_length) ;
let no_of_blocks = parameters.row_length/parameters.block_length - 1 ;
let width = parameters.letter_width * (parameters.row_length - 1)+ (no_of_blocks)*parameters.gap_width + parameters.right_margin + parameters.left_margin + 2*parameters.numerical_width;
let height = parameters.row_height * num_of_rows + parameters.bottom_margin + parameters.top_margin ;
return [width,height];
}
/**
* Draw the sequence on to svg
* @param {Object} parameters - Contains parameters of width, letter space etc., to draw SVG
* @param {String} seq - Contains the protein sequence
* @param {String} id -Contians id of the SVG tag from html.
* @param {Array} massShiftList - Contains list of all the mass shifts
* @param {Array} monoMassList - Contains Mono Mass list data
*/
function buildSvg(parameters,seq,id,massShiftList,monoMassList)
{
let massShiftListLen = massShiftList.length ;
d3.selectAll(".residue").remove();
let width,height ;
[width,height] = getSvgSize(parameters,seq) ;
/*create a group under svg with svgId_g*/
let id_temp = id + "_g" ;
let svgContainer = d3.select("#"+id)
.attr("width", width)
.attr("height", height)
.attr("font-family","'FreeMono',Miltonian,monospace")
.attr("font-size","16px")
.style("fill", parameters.svgBackground_color)
svgContainer = svgContainer.append("g")
.attr("id",id_temp)
.attr("class",id_temp);
text = svgContainer.selectAll("text");
let x,y ;
/* Get the x and y coordinates of the acid position */
text.data(seq)
.enter()
.append("text")
.attr("class","residue")
.attr("x", function(d,i){
x = getX(parameters,i) ;
return x ;
})
.attr("y", function(d,i){
y = getY(parameters,i) ;
return y ;
})
.text(function(d,i){
for(let k=0;k<massShiftListLen;k++)
{
if( i == massShiftList[k].position && massShiftList[k].mass != 0)
{
MassShift(this,massShiftList[k].mass,i);
break;
}
else if(i == massShiftList[k].position && massShiftList[k].mass == 0)
{
MassShift(this,massShiftList[k].mass,i);
}
}
return d ;
})
.on("mouseover",function(d,i){
d3.select(this).style("cursor","pointer")
let id = "massshift_" + i;
d3.select("#"+id).attr("font-size","18px");
})
.on("mouseout",function(d,i){
d3.select(this).style("cursor","default")
let id = "massshift_" + i;
d3.select("#"+id).attr("font-size","11px");
})
.on("click",function(d,i){
handleOnClick(d,i,id,seq,massShiftList,monoMassList)
})
.style("fill",function(d,i){
for(let k=0;k<massShiftListLen;k++)
{
if( i == massShiftList[k].position )
{
MassShift(this,massShiftList[k].mass,i);
//return "red" ;
break;
}
else if(i == massShiftList[k].position)
{
MassShift(this,massShiftList[k].mass,i);
}
}
return "black" ;
})
return parameters;
}
/**
* Handles on click actions.
* on click of any amino acid, provides a box to enter mass shift.
* On click of ok, will re calculate and redraws entire page.
* @param {Char} d Current Amino Acid
* @param {Integer} i Index or position of the amino acid
* @param {String} id Contains Id of the SVG on which the sequence is drawn
* @param {String} seq Sequence of the amino acid
* @param {Array} massShiftList List of all the amino acids
* @param {Array} monoMassList List of Mono Mass data
*/
function handleOnClick(d,i,id,seq,massShiftList,monoMassList){
d3.selectAll("#tooltip_pop").remove() ;
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.attr("id","tooltip_pop")
.style("opacity", 1);
let colorsDropdown = addColorsToDropdown();
div.transition()
.duration(200)
.style("opacity", .9);
div.html(
'<input list="browsers" name="myBrowser" type="text" id= "mass_shift" />'+
colorsDropdown +
'<button id="ok" style = "none" type="button">ok</button>'
)
.style("left", (d3.event.pageX - 30) + "px")
.style("top", (d3.event.pageY - 45) + "px");
let shiftPosition = i;
d3.select("#ok").on("click",function(){
let massShiftVal = document.getElementById("mass_shift").value ;
let tooltipcolor = document.getElementById("tooltip_color").value ;
d3.select("#tooltip_pop").remove() ;
massShiftVal = parseFloat(massShiftVal);
if(!isNaN(massShiftVal)){
let errorType = $(".error_dropdown").val();
let errorVal = parseFloat($("#errorval").val().trim());
let executionObj = new SeqOfExecution();
executionObj.onClickMassShift = {mass:massShiftVal,position:shiftPosition,color:tooltipcolor}
executionObj.onClickSequenceOfExecution(errorType,errorVal);
}
});
}
/**
* Put the numerical positions at the start and end of each row of the sequence
* @param {Object} para Contains parameters of width, letter space etc., to draw SVG
* @param {Object} seq Amino Acid Sequence
* @param {String} id Id of the SVG from html
*/
function getNumValues(para,seq,id)
{
//remove all the numbers if exist
d3.selectAll(".numbers").remove();
let svgContainer = d3.select("#"+id+"_g") ;
let len = seq.length;
for(let i = 0;i < len ;i++ )
{
let x,y ;
let l_position_temp = i ;
/* write the numerical values only at the start position and end position(this is in the
* form of 29,59 etc.,. as the data starts with 0 as 1st element) */
if(l_position_temp%(para.row_length) == 0 || l_position_temp%(para.row_length) == (para.row_length-1)
|| l_position_temp == len-1)
{
let id_temp ;
let position = i+1 ;
if(i%para.row_length == 0)
{
/* Get the coordinates of left numerical */
[x,y] = calibrateLeftNum(para,l_position_temp) ;
x = x ;
id_temp = "left_align" ;
}
else
{
/* Get the coordinates of right numerical */
[x,y] = calibrateRightNum(para,l_position_temp) ;
id_temp = "right_align" ;
}
svgContainer.append("text")
.attr("class","numbers")
.attr("id", id_temp)
.attr("x",x)
.attr("y",y)
.text(function(d,i){
return position ;
})
.style("text-anchor",function(d,i){
/* Align the left numerical towards left side */
if(id_temp == "left_align") return "end" ;
return null ;
})
.style("fill", "black");
// When there exist only one number in the last row
if(l_position_temp == len-1 && len%(para.row_length) == 1)
{
[x,y] = calibrateRightNum(para,l_position_temp) ;
id_temp = "right_align" ;
svgContainer.append("text")
.attr("id", id_temp)
.attr("x",x)
.attr("y",y)
.text(function(d,i){
return position ;
})
.style("fill", "black");
}
}
}
}
/**
* Draw annotations
* @param {Object} para Contains parameters of width, letter space etc., to draw SVG
* @param {Array} matchedPeaks Contains Matched List
* @param {String} id Contains id of the SVG tag from html to draw sequence
*/
function annotations(para,matchedPeaks,id)
{
// remove all existing polylines with polyline id
d3.selectAll("#annoTooltip").remove();
d3.selectAll("#polyline").remove();
matchedPeaks.forEach(function(matchedPeak,index){
let position = matchedPeak.position ;
let charge = getIonCharge(matchedPeaks,position);
let utilFunctionsObj = new utilFunctions();
let tempIon = matchedPeak.ion[0].toLowerCase();
let ionType = utilFunctionsObj.getTerminus(tempIon);
if("NTERMINUS" == ionType)
{
drawAnnotation_B(para,position,charge,id) ;
}
else
{
drawAnnotation_Y(para,position,charge,id) ;
}
})
}
/**
* Draw the annotation when the ion type is B
* @param {Object} para Contains parameters of width, letter space etc., to draw SVG
* @param {Integer} position Position of the amino acid
* @param {String} charge Contains the charge at the current position to display on hover of the annotation
* @param {String} id Contains id of the SVG tag from html to draw sequence
*/
function drawAnnotation_B(para,position,charge,id)
{
x = getX(para,position-1);
y = getY(para,position-1);
x = x + (para.letter_width/2) ;
let coordinates = (x-2)+","+(y-13)+ " " +(x+4)+","+ (y-11)+" "+(x+4)+","+(y+2);
drawAnnotation(position,charge,id,coordinates,x,y);
}
/**
* Draw the annotation when the ion type is Y
* @param {Object} para Contains parameters of width, letter space etc., to draw SVG
* @param {Integer} position Position of the amino acid
* @param {String} charge Contains the charge at the current position to display on hover of the annotation
* @param {String} id Contains id of the SVG tag from html to draw sequence
*/
function drawAnnotation_Y(para,position,charge,id)
{
x = getX(para,position-1);
y = getY(para,position-1);
x = x + (para.letter_width/2);
let coordinates = (x+4)+","+ (y-11)+" "+(x+4)+","+(y+2)+ " "+(x+10) + ","+(y+5);
drawAnnotation(position,charge,id,coordinates,x,y);
}
/**
* generate cooordinates to dray Y or B annotation
* @param {Object} para Contains parameters of width, letter space etc., to draw SVG
* @param {Integer} position Position of the amino acid
* @param {String} charge Contains the charge at the current position to display on hover of the annotation
* @param {String} id Contains id of the SVG tag from html to draw sequence
*/
function drawAnnotation_YB(para,position,charge,id)
{
x = getX(para,position-1);
y = getY(para,position-1);
x = x + (para.letter_width/2) ;
let coordinates = (x-2)+","+(y-13)+ " " + (x+4)+","+ (y-11)+" "+(x+4)+","+(y+2)+ " "+(x+10) + ","+(y+5);
drawAnnotation(position,charge,id,coordinates,x,y);
}
/**
* Draw Annotations
* @param {Integer} position Position of the amino acid
* @param {String} charge Contains the charge at the current position to display on hover of the annotation
* @param {String} id Contains id of the SVG tag from html to draw sequence
* @param {String} coordinates Contains coordinates to draw the annotaion
* @param {Integer} x Contains x coordinate of start point to draw the annotation
* @param {Integer} y Contains y coordinate of start point to draw the annotation
*/
function drawAnnotation(position,charge,id,coordinates,x,y)
{
let svgContainer = d3.select("#"+id+"_g");
let l_polyline = svgContainer.append("polyline")
.attr("id","polyline")
.attr("points", coordinates)
.style("fill", "none")
.style("stroke", "1e90ff")
.style("stroke-width", 1 );
// Rectangle to have flexible on click and on mouse actions
svgContainer.append("rect")
.attr("id","annoTooltip")
.attr("x", x)
.attr("y", y-14)
.attr("width", 13)
.attr("height", 23)
.style("opacity", 0)
.attr("cursor", "pointer")
.on("click",function(){
showIonPeaks(position);
})
.on("mouseover", function(){
appendTooltip(charge);
})
.on("mouseout", function(d){
removeToolTip();
});
}
/**
* Append Charge to the tool tip
* @param {String} charge Contains the charge at the current position to display on hover of the annotation
*/
function appendTooltip(charge)
{
var div = d3.select("body").append("div")
.attr("class", "tooltip annotation_tooltip")
.style("opacity", 0);
div.transition()
.duration(10)
.style("opacity", .9);
div.html(charge)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28)+ "px") ;
}
/**
* Remove tootltip on remove of the mouse from annotation
*/
function removeToolTip()
{
d3.selectAll(".annotation_tooltip").remove();
}
/**
* Get the charge of the Ion
* @param {Array} matchedPeaks Array with charge data at all the matched positions
* @param {Integer} position Position at which the charge data has to be consolidated to show on hover of an annotation
*/
function getIonCharge(matchedPeaks,position){
let l_charge = "";
for(let j=0;j<matchedPeaks.length;j++){
if(position == matchedPeaks[j].position )
{
l_charge = l_charge + matchedPeaks[j].ion
+" "+matchedPeaks[j].charge+"+ " ;
}
}
return l_charge ;
}
/**
* MassShift value at the top of the acids
* @param {Object} thisElem Current element of the amino acid
* @param {Float} MassShift Value of the mass shift
* @param {Integer} position Position of the amino acid
*/
function MassShift(thisElem,MassShift,position)
{
let id = "massshift_" + position;
d3.select("#"+id).remove();
let dy = -1.2 ;
let x = $(thisElem).attr("x");
let y = $(thisElem).attr("y");
dy = dy+"em" ;
let svgContainer = d3.select("#seqsvg");
svgContainer.append("text")
.attr("class","massshift_class")
.attr("id",id)
.attr("x", x)
.attr("y", y)
.attr("dy", dy)
.text(function(){
if(MassShift != 0)
{
return MassShift ;
}
return "";
})
//.attr("text-anchor","middle")
.attr("fill","black")
.attr("font-size","11px");
}
/**
* Provide a drop down to add different background colors to the mass shifted elements
*/
function addColorsToDropdown(){
let colors = ["white","green","yellow","blue","red"]
let startStatement = "<select id=\"tooltip_color\" style=\"background-color:"+colors[0]+"\">";
let endStatement = "</select>";
let stringyfyingHTML = startStatement;
let len = colors.length;
for(let i=0;i<len;i++)
{
stringyfyingHTML += drawRectagleWithColors(colors[i],i);
}
stringyfyingHTML = stringyfyingHTML + endStatement;
console.log("stringyfyingHTML : ", stringyfyingHTML);
return stringyfyingHTML;
}
/**
* Add rectagular block with selected color
* @param {String} color Backgroung color added tot he amino acid
* @param {Integer} index Position at which the color needed to be added
*/
function drawRectagleWithColors(color,index){
let option = "<option value=\""+color +"\"style=\"width:80px;height:5px;border:1px solid #000;background-color:"+color+"\">";
if(index == 0)
{
option = "<option value=\""+color +"\"style=\"width:80px;height:5px;border:1px solid #000;background-color:"+color+"\""+"selected"+">";
}
//let div = "<div style=\"width:80px;height:5px;border:1px solid #000;background-color:"+color+"\"></div>";
let finalOption = option+color+"</option>";
return finalOption;
}