Source: generateSpectrumGraphs.js

/**
 * Available functions in the file are 
 *      {generateCorrespondingGraph}, {graphOnClickActions}
 * Generating multiple graphs with different scan Id.
 * 1.   Once the data is loaded from local files from the function {promiseLoadDataJS} from multiscan.js,
 *      it sets the data into global variables ms2_ScansWithData and ms1_ScansWithData.
 * 2.   Once the data is set to the global variables, then it creates navigation elements by calling 
 *      {createMs1NavEements}, {createMs2NavEements}. 
 * 3.   Once navigation elements are generated, {graphOnClickActions} function is called to set the 
 *      on click actions on the navigation buttons of the spectrum graph
 */
// function svgIds()
// {
//     this.ms2SvgId = "ms2svg_";
//     this.ms2popUpSvgId = "ms2svg_popup_";
//     return this;
// }
/**
 * 
 * @param {Array} current_data - Contains a list with ion data if it is generating Mono Mass spectrum, 
 * contians peaklist and enveloplist if generating spectrums of MS1/MS2
 * @param {String} id - Contains the id of spectrum svg with _ followed by scan number (monoMassSvg_872/ms2svg_870)
 * @param {Float} prec_mz - Contains the mass to which the graph needs to be zoomed
 * @param {Int} specId - Contains the spectrum number
 */
function generateCorrespondingGraph(current_data,id,prec_mz,specId){
    // Gets the svg id of the spectrum
    let startOfId = id.split("_")[0];
    let graphFeatures = new GraphFeatures();
    if(startOfId == "monoMassSvg")
    {
        let calculatePrefixAndSuffixMassObj = new CalculatePrefixAndSuffixMass();
        let massShift_in = calculatePrefixAndSuffixMassObj.getIonTypeMass("B");
        let seq = calculatePrefixAndSuffixMassObj.getSequence(prsm_data);
        let massShiftList = calculatePrefixAndSuffixMassObj.getUnknownMassList();
        let prefixMassList = calculatePrefixAndSuffixMassObj.getPrefixMassList(seq,massShiftList,massShift_in);
        massShift_in = calculatePrefixAndSuffixMassObj.getIonTypeMass("Y");
        let suffixMassList = calculatePrefixAndSuffixMassObj.getSuffixMassList(seq,massShiftList,massShift_in);
        // Setting the graphFeatures object with all the features needed for the graph
        graphFeatures.showSequence = true;
        graphFeatures.addErrorPlot = true;
        graphFeatures.prefixSequenceData = prefixMassList;
        graphFeatures.suffixSequeceData = suffixMassList;
        graphFeatures.svgHeight = graphFeatures.svgHeight + graphFeatures.adjustableHeightVal + graphFeatures.heightForErrorPlot;
        graphFeatures.padding.head = graphFeatures.padding.head + graphFeatures.adjustableHeightVal;
        graphFeatures.padding.bottom = graphFeatures.padding.bottom + graphFeatures.heightForErrorPlot;
        graphFeatures.adjustableIonPosition = 10; // Random tested value for alignment
        // Gets the data list with mass error to plot in the monomass spectrum 
        graphFeatures.errorListData = json2ErrorDataList(prsm_data.prsm); 
        console.log(graphFeatures.errorListData);
        // Gets the absolute max and minimum value for upper bound and lower bound of y axis to draw the error plot
        graphFeatures.errorThreshHoldVal = getAbsoluteMaxValfromList(graphFeatures.errorListData);
        // Invoking spectrum function to draw the spectrum
        spectrumgraph = new addSpectrum(id, current_data, null, prec_mz, current_data,graphFeatures);
    }   
    else{
        let peak_data = new PeakData();
        // Get the formatted peak data list  
        let peak_list = peak_data.getPeakData(current_data);
        // Get formatted envelope data list
        let envelope_list = peak_data.getEnvelopeData(current_data);
        // Check if MS1 spectrum should be drawn
        if(id != "popupspectrum")
        {
            let ionData = peak_data.getIonData(prsm_data,specId,current_data);
            ms2_graph = new addSpectrum(id, peak_list, envelope_list, prec_mz, ionData, graphFeatures);
        }
        else{
            graphFeatures.isAddbgColor = true;
            // Get precursor mass to zoom to that point on launch of MS1 spectrum
            let precursor_mass = prsm_data.prsm.ms.ms_header.precursor_mono_mass;
            graphFeatures.bgMinMz = (graphFeatures.ratio * prec_mz) - graphFeatures.fixedWidthOfBgColorForMs1;
            graphFeatures.bgMaxMz = (graphFeatures.ratio * prec_mz) + graphFeatures.fixedWidthOfBgColorForMs1;
            spectrumgraph = new addSpectrum(id, peak_list, envelope_list, prec_mz, null,graphFeatures);
        }
    }
}

/**
 * Function to redraw the spectrum on popup window on click of download button for respected scan number
 * @param {Array} current_data - contains peak list and envelope list data of the corresponding spectrum(Scan Number) 
 * @param {String} id - Contains the Id of the SVG tag to which the spectrum need to be drawn
 * @param {Object} spectrumParameters - Contains spectrum parameters to apply same to the pop window spectrum
 * @param {Int} specId - Contains the Spec Id of the corresponding graph
 */
function reDrawWithSpecParams(current_data,id,spectrumParameters,specId)
{
    let peak_data = new PeakData();
    let peak_list = peak_data.getPeakData(current_data);
    let envelope_list = peak_data.getEnvelopeData(current_data);
    let ionData = peak_data.getIonData(prsm_data,specId,current_data);
    peak_list.sort(function(x,y){
		return d3.descending(x.intensity, y.intensity);
	})
    envelope_list = sortEnvelopes(envelope_list) ;
    let svgId = "#"+id;
    let peakData = {peak_list:peak_list, envelope_list:envelope_list};
    let graphFeatures = new GraphFeatures();
    new SpectrumGraph(svgId,spectrumParameters,peakData, ionData,graphFeatures);
}
/**
 * This generates spectrum for each spec Id
 * @param {String} divId - Contains Id of the div tag under which the monomass graphs are drawn
 * @param {String} svgId - Contains id as "monoMassSvg_" to which scan Id is added
 * @param {String} className - Contains class name to which the corresponding svg graphs are drawn 
 * @param {Array} data - contains the data of all the scans available
 */
function createMultipleSvgs(divId,svgId,className,data){
    let div = document.getElementById(divId); 
    data.forEach(function(element,i){
        let id = svgId+element.scanId;
        let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");;
        svg.setAttribute("id",id);
        svg.setAttribute("class",className);
        svg.style.backgroundColor = "#F8F8F8"; 
        if(i != 0)
        {
            svg.style.display = "none"; 
        }
        div.appendChild(svg);
        generateCorrespondingGraph(element.value,id,null,element.specId);
    });
}

/**
 * Function to hide graphs of all other spectrums other than current showing spectrum
 * @param {String} id - Contains Id of the SVG tag to be shown
 * @param {String} className - className of the spectrums to be hidden 
 */
function showCorrespondingGraph(id,className)
{
    $(className).hide();
    document.getElementById(id).style = "block";
}
/**
 * Generating Jquery Onclick actions
 */
function graphOnClickActions(){

    // On click of download button on the main page of the prsm
    $("#graph_download").click(function(){
        // Get the Scan number of the Current spectrum graph showing on the screen
        let currentGraphNode = $('.ms2_scanIds.active')[0].text;
        let scanId = currentGraphNode.split(" ")[1];
        // Get the data tot he correcponding Scan Id
		let [current_data,specId] = getCurrentData(ms2_ScansWithData,scanId);
        let id = "ms2svg_"+scanId;
        // Get SpectrumParametes and copy to a new variable. This way of copying doesn't pass reference rather creates new copy
        // correspondingSpecParams_g is a global variable contians the spec parameters of each spectrum 
        let specparams = jQuery.extend(true, {}, correspondingSpecParams_g[id]);
        let graphFeatures = new GraphFeatures();
        document.getElementsByName("show_envelops")[0].checked = graphFeatures.showCircles;
        document.getElementsByName("show_ions")[0].checked = graphFeatures.showIons;
        // Redraw the graph with correspondong specparameters
        reDrawWithSpecParams(current_data,"popup_ms2_spectrum",specparams,specId);
        // This allows pop up window to be moved
		$("#ms2spectrumpop").draggable({
			appendTo: "body"
		});
    })

    // ms2_scanIds is the Id of the nav tabs for multiple navs.
    // On Click shows corresponding graph by hiding others.
	$(".ms2_scanIds").click(function(){
        let value = this.getAttribute('value');
        let [currentData,specId] = getCurrentData(ms2_ScansWithData,value);
        id = "ms2svg_"+value;
        // Hide all the graphs except the one clicked
        showCorrespondingGraph(id,".ms2_svg_graph_class");
		$("#ms2_graph_nav .active").removeClass("active");
   		$(this).addClass("active");
	})
    
    // Hide all othe graphs of monomass spectrum other than the one clicked
    $(".monoMass_scanIds").click(function(){
		let value = this.getAttribute('value');
        let [currentData,specId] = getCurrentData(monoMassDataList,value);
        id = "monoMassSvg_"+value;
        // Hide all the graphs except the one clicked
        showCorrespondingGraph(id,".monoMass_svg_graph_class");
		$("#monoMass_nav .active").removeClass("active");
   		$(this).addClass("active");
    })
    
    // On click of mono mass mz, zoom all the graph to the corresponding point
    $(".peakRows").click(function() {
		let parent_id  = $(this).parent().parent().prop('id');
		let CurrentScanVal = document.getElementById(parent_id).firstChild.innerHTML;
		/*	get Mono M/z value till 3 decimal values	*/
		let peak_value = parseFloat(this.innerHTML).toFixed(3) ;
		let [currentData,specId] = getCurrentData(ms2_ScansWithData,CurrentScanVal);
        let id = "ms2svg_"+CurrentScanVal;
        showCorrespondingGraph(id,".ms2_svg_graph_class");
        generateCorrespondingGraph(currentData,id,peak_value,specId);
        id = "monoMassSvg_"+CurrentScanVal;
        showCorrespondingGraph(id,".monoMass_svg_graph_class");
        [currentData,specId] = getCurrentData(monoMassDataList,CurrentScanVal);
        let CurrentMonoMassVal = $("#"+parent_id+" .row_monoMass").html();
        generateCorrespondingGraph(currentData,id,parseFloat(CurrentMonoMassVal),specId);
        activateCurrentnavbar("ms2_graph_nav",CurrentScanVal);
        activateCurrentnavbar("monoMass_nav",CurrentScanVal);
        
		showSpectrun();
    });
    // By changing the graph features, on click of redraw invoke this and generate the pop spectrun repectively to be downloaded
    $("#ms2_popup_redraw").click(function(){
        let currentGraphNode = $('.ms2_scanIds.active')[0].text;
        let scanId = currentGraphNode.split(" ")[1];
		let [current_data,specId] = getCurrentData(ms2_ScansWithData,scanId);
        let id = "popup_ms2_spectrum";
        // Copying as a new variable than referencing. Referencing will change the properties of parent if child properties are changes
        // However, this is a shallow copying, we need to do this for all needed objects in side specparams
        let specparams = jQuery.extend(true, {}, correspondingSpecParams_g[id]);
        specparams.graphFeatures = jQuery.extend(true, {}, correspondingSpecParams_g[id].graphFeatures);
        specparams.graphFeatures.showCircles = document.getElementsByName("show_envelops")[0].checked ;
        specparams.graphFeatures.showIons = document.getElementsByName("show_ions")[0].checked ;
        reDrawWithSpecParams(current_data,"popup_ms2_spectrum",specparams,specId);
    })
    
}
/**
 * Function return the absolute max error value from the list
 * @param {Array} errorDataList - Contains the list of mass errors
 */
function getAbsoluteMaxValfromList(errorDataList){
    let max = 0;
    errorDataList.forEach((element,index)=>{
        let val = Math.abs(element.mass_error);
        if(max < val) max = val; 
    })
    //Getting the round off fraction value
    max = max * 100;
    max = Math.ceil(max)/100;
    console.log("max : ", max);
    return max;
}