/** @function SpectrumParameters
* @description Get data from global variable spectrum_data and utilities to manupulate
* the data
*/
SpectrumParameters = function() {
/* Attributes to decide what to be shown on the graph */
// this contain the showCircles,showIons,isAddbgColor,showSequence
this.graphFeatures = {};
/*assign the mono m/z value when clicked on mono m/z*/
this.minMz ;
this.maxMz ;
this.centerMz ;
this.xScale = 0;
this.yScale;
this.dataMinMz ;
this.dataMaxMz ;
this.dataMaxInte ;
this.dataMinInte;
this.maxInte;
this.fixedShiftRatio = 1.000684;
this.svgWidth = 910;
this.svgHeight = 220;
/* Set padding values to the svg------------------*/
this.padding = {left:70, right:20, head:10, bottom:50};
this.specWidth = this.svgWidth - this.padding.left - this.padding.right;
this.specHeight = this.svgHeight - this.padding.head - this.padding.bottom;
this.labelAdjustVal = 15;
this.specScale = 1.0;
this.specX = 0;
/* Colors for the envelope circles */
this.spectrumColorArray = ["red","orange","blue","green"];
/* Radius factor and setting min and max radius */
this.mzRadius = 0.05;
this.minRadius = 2;
this.maxRadius = 5;
this.tickWidthList = [10000,8000,6000,5000,4000,3000,2000,1000,800,700,600,500,450,400,350,300,250,200,150,100,50,20,10,5,3,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.001,0.0005,0.0001,0.00005,0.00001,0.000005,0.000001];
this.tickHeightList = [50,40,30,25,20,15,10,5,3,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.001];
this.onClickMassAdjacentRange = 3;
this.mouseOverPadding = {head:20,middle:14};
/* number of ticks on x and y axis*/
this.xTicks = 10;
this.yTicks = 5 ;
//Height/size of the tick
this.ticklength = 7 ;
this.errorYticks = 2;
//Limiting the peaks and envelopes to 500
this.ranges=[0,0,0,0,0,0];
this.limits=[0,0,0,0,0];
this.bufferPercent = 0.01; //10 percent
/**
* @function initScale
* @description Initializing the spectrum Parameters with the data from the peak list and envilopelist.
* initializing xScale, yScale.
*/
this.initScale = function(currminMz, currmaxMz, dataMaxInte,dataMinInte,minMzData,maxMzData,currentMaxIntensity) {
this.dataMinMz = minMzData;
this.dataMaxMz = maxMzData + (0.10 * maxMzData);
this.minMz = currminMz;
this.maxMz = currmaxMz;
if(currminMz == minMzData && currmaxMz == maxMzData)
{
this.minMz = 0;
this.maxMz = this.maxMz + (0.10*this.maxMz);
}
this.centerMz = (this.minMz + this.maxMz)/2.0;
this.xScale = this.specWidth/(this.maxMz - this.minMz);
// add 1/4th of max intensity to keep the max point at 3/4 of the y axis*
this.dataMaxInte = dataMaxInte + 0.25*dataMaxInte;
this.dataMinInte = dataMinInte ;
this.maxInte = currentMaxIntensity;
// add 1/4th of max intensity to keep the max point at 3/4 of the y axisd
// dataMaxInte = dataMaxInte + 0.25*dataMaxInte ;
currentMaxIntensity = currentMaxIntensity + 0.25*currentMaxIntensity ;
this.yScale = this.specHeight/currentMaxIntensity;
this.setLimits();
}
// this.setColorToEnvelops = function(envelopes){
// envelopes.sort(function(x,y){
// return d3.ascending(x.env_peaks[0].mz, y.env_peaks[0].mz);
// })
// let colorListsize = this.spectrumColorArray.length;
// let i = envelopes.length ;
// while(i--)
// {
// envelopes[i].color = this.spectrumColorArray[i%colorListsize];
// }
// return envelopes;
// }
/**
* @function getPeakXPos
* @description Function provides the x coordinate for the mass
*/
this.getPeakXPos = function (mz) {
let peakX = (mz - this.minMz) * this.xScale + this.padding.left;
return peakX;
}
/**
* @function getPeakYPos
* @description Function provides the y coordinate for the intensity
*/
this.getPeakYPos = function (intensity) {
let peakY = this.svgHeight - intensity * this.yScale - this.padding.bottom;
return peakY;
}
/**
* @function getErrorYPos
* @description Function provides the y coordinate for the error val on the error plot
*/
this.getErrorYPos = function(erroVal){
let yErrorScale = this.graphFeatures.heightForErrorPlot/(this.graphFeatures.errorThreshHoldVal*2);// Multiply with 2 as the coordinates has to be both positive and negative
console.log("yErrorScale : ", yErrorScale);
let peakY = this.svgHeight - (erroVal * yErrorScale) - this.graphFeatures.errorplot_padding.bottom - this.graphFeatures.heightForErrorPlot/2;
return peakY;
}
/**
* @function getCircleSize
* @description Function provides the radius of the circles drawn on the graph as zoomed in and out
*/
this.getCircleSize = function() {
radius = this.mzRadius * this.xScale;
if (radius < this.minRadius) {
radius = this.minRadius;
}
if (radius > this.maxRadius) {
radius = this.maxRadius;
}
return radius;
}
/**
* @function getTickWidth
* @description Function Provides width between each tick when zoomed in and out or dragged
*/
this.getTickWidth = function(){
let tempDiff = this.maxMz - this.minMz;
let tickWidth = parseInt(this.tickWidthList[0]) ;
for(let i = 0; i < this.tickWidthList.length; i++)
{
if(tempDiff/this.xTicks <= parseFloat(this.tickWidthList[i]) && tempDiff/this.xTicks > parseFloat(this.tickWidthList[i+1]))
{
tickWidth = parseFloat(this.tickWidthList[i]);
break ;
}
}
return tickWidth ;
}
/**
* @function getTickHeight
* @description Function Provides height between each tick when zoomed in and out or dragged
*/
this.getTickHeight = function(){
let tickheight = parseInt(this.tickHeightList[0]) ;
let maxIntPercent = this.maxInte/this.dataMaxInte * 100;
for(let i = 0; i < this.tickHeightList.length; i++)
{
if(maxIntPercent/this.yTicks <= parseFloat(this.tickHeightList[i]) && maxIntPercent/this.yTicks > parseFloat(this.tickHeightList[i+1]))
{
tickheight = parseFloat(this.tickHeightList[i]);
break ;
}
}
return tickheight ;
}
/**
* @function xZoom
* @description Function provides with current xScale, current minMz and MaxMz based on the zoom on x-axis.
* Function also calls setLimita which helps in drawing limited number of peaks and circles per eachbin/range of mz values.
*/
this.xZoom = function (mouseSvgX, ratio) {
if ((ratio > 1.0) || ((this.maxMz - this.minMz) < this.dataMaxMz) ) {
let mouseSpecX = mouseSvgX - this.padding.left;
this.centerMz = mouseSpecX/this.xScale + this.minMz;
/*self is a global variable of datasource object containing all the data needed to use when zoomed*/
this.xScale = this.xScale * ratio ;
this.minMz = this.centerMz - mouseSpecX / this.xScale;
this.maxMz = this.centerMz + (this.specWidth - mouseSpecX) / this.xScale;
}
this.setLimits();
}
/**
* @function yZoom
* @description Function provides with current yScale, current max Intensity based on the zoom on y-axis
*/
this.yZoom = function (ratio) {
//Reducing zoom factor to smoothenup and remove gliches
if(ratio > 1 ) ratio = 1.4;
else if(ratio < 1) ratio = 0.9;
if ((ratio > 1.0 && this.maxInte >= this.dataMinInte ) || (ratio < 1.0 && this.maxInte <= this.dataMaxInte)) {
this.yScale = this.yScale * ratio;
this.maxInte = this.specHeight / this.yScale;
}
}
/**
* @function zoom
* @description
* Function to invoke respective zoom functionality(zoom on x or y) based on position of X, Y
* It fixes amount of zoom based on zooming in or out
*/
this.zoom = function(mouseSvgX, mouseSvgY, ratio) {
if(ratio > 1 ) ratio = 1.4; // Zooming in and fixing ration to 1.4 (fixed values based on testing the smooting of zoom)
else if(ratio < 1) ratio = 0.9; // Zooming out and fixing ration to 0.9 (fixed values based on testing the smooting of zoom)
if (mouseSvgY > this.svgHeight - this.padding.bottom) {
this.xZoom(mouseSvgX, ratio);
}
else {
this.yZoom(ratio);
}
}
/**
* @function drag
* @description
* Function provides minMz and maxMz based on the amount of drag done
*/
this.drag = function(distX) {
let mzDist = distX / this.xScale;
this.minMz = this.minMz - mzDist;
this.maxMz = this.maxMz - mzDist;
this.centerMz = this.centerMz - mzDist;
this.onDragLimits(mzDist);
}
/**
* @function setLimits
* @description
* when zoomed function provides the bin ranges to divide the complete x axis into 5 bins.
* This helps setting the number of peaks and circles to a limited number in each bin.
* This speeds up the zoom and drag functionality.
*/
this.setLimits = function(){
let avg = (this.maxMz - this.minMz)/this.limits.length ;
avg = avg + (this.bufferPercent*avg);
for(let i=0; i<this.ranges.length;i++)
{
this.ranges[i] = this.minMz + (i*avg) ;
}
}
/**
* @function onDragLimits
* @description
* When dragged function provides the bin ranges to divide the complete x axis into 5 bins.
* This helps setting the number of peaks and circles to a limited number in each bin.
* This speeds up the zoom and drag functionality.
*/
this.onDragLimits = function(mzDist){
let tempRanges = this.ranges ;
let avg = (this.maxMz - this.minMz)/this.limits.length ;
avg = avg + (avg*this.bufferPercent);
if(mzDist < 0)
{
if(tempRanges[0] < (this.minMz-avg)) tempRanges.shift();
if(tempRanges[(tempRanges.length-1)] < (this.maxMz))
{
let tempVal = tempRanges[(tempRanges.length-1)]+avg;
tempRanges.push(tempVal);
}
}
else
{
if(tempRanges[0] > this.minMz)
{
let tempVal = tempRanges[0]-avg;
tempRanges.unshift(tempVal);
}
if(tempRanges[(tempRanges.length-1)] > (this.maxMz+avg)) tempRanges.pop();
}
this.ranges = tempRanges;
}
}