Skip to content
Snippets Groups Projects
LoadFile.ts 43.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Laura Cappelli's avatar
    Laura Cappelli committed
    interface coordinates{ //tipo delle variabili "pixel"
        xp: number;
        yp: number;
    }
    var DataMatrix: number[][][]; //matrice 3D con tutti i dati letti dal file
    var nOfCounts: number[][]; //numero di conteggi per ogni pixel
    var pixelDim: number; //dimensione di un pixel in pt
    var maxAbsolute: number; //massimo conteggio della matrice nOfCounts
    var dataCompleteChart: string; //dati del grafico completo
    var dataCompleteChartCalibrated: string; //dati del grafico calibrato completo
    var a: number = 3.36275; //costante moltiplicativa per la calibrazione
    var b: number = 58.2353; //costante additiva per la calibrazione
    var rePrint: boolean = false; //variabile per ricolorare con il max relativo
    var calibrated: boolean = false; //variabile per il controllo sulla calibrazione
    var newOrigin: coordinates; //nuovo origine nel caso di zoom
    var zPixel1: coordinates = {xp: 0, yp: 0}; //pixel1 dello zoom
    var zPixel2: coordinates = {xp: 0, yp: 0}; //pixel2 dello zoom
    //var canvasMaxWidth: number = 450; //dim massima della canvas in pt - asse x
    //var canvasMaxHeight: number = 500; //dim massima della canvas in pt - asse y
    var xDim: number = 0; //numero di pixel dell'immagine sull'asse x
    var yDim: number = 0; //numero di pixel dell'immagine sull'asse y
    var passo: number = 0; //dimensione di un pixel in micorn
    var globalxMinRange: number = 0; //estremo sinistro del range dell'asse x
    var globalxMaxRange: number = 55; //estremo destra del range dell'asse x
    var realPixelDim: number; //dimensione dei pixel responsive
    
    //imposto le dimensioni del canvas
    var bb: any = document.querySelector ('#mappa-pannel').getBoundingClientRect();
    var maxMappaWidth: number = bb.right - bb.left - 50;
    var maxMappaHeight: number = bb.bottom - bb.top - 50;
    
    //avvio la possibilità di fare il drag&drop
    var element = document.querySelector('.droppable');
    makeDroppable(element, callback);
    
    //costruzione dell'albero
    //prima parte: leggo il file con la descrizione della directory
    var MapTreeFile = new  XMLHttpRequest();
    
    MapTreeFile.open("GET", "https://oc-chnet.cr.cnaf.infn.it:8443/Laura/XRF-App-Bootstrap/filesystemtree.json", true);
    
    Laura Cappelli's avatar
    Laura Cappelli committed
    MapTreeFile.onreadystatechange = function(){
        if(MapTreeFile.readyState === 4){
            if(MapTreeFile.status === 200){
                var MapTreeText: any = JSON.parse(MapTreeFile.responseText);
                //alert(MapTreeText[0].name);
                //creaAlbero(MapTreeText);
            }
        }
    }
    MapTreeFile.send(null);
    
    //creo l'albero con treeview
    function getTree() {
        var tree = [
        {
            text: "PERGAMENA MEDIOEVALE",
            nodes: [
            {
                text: "Mappa integrale",
                icon: "glyphicon glyphicon-file",
                selectedIcon: "glyphicon glyphicon-file",
    
                url: "https://oc-chnet.cr.cnaf.infn.it:8443/Laura/XRF-App-Bootstrap/RemoteFileSystem/Pergamena-Medioevale/map3_turkey.txt"
    
    Laura Cappelli's avatar
    Laura Cappelli committed
            },
            {
                text: "Coda Pavone",
                nodes: [
                {
                    text: "Risoluzione 500",
                    icon: "glyphicon glyphicon-file",
                    selectedIcon: "glyphicon glyphicon-file",
    
                    url: "https://oc-chnet.cr.cnaf.infn.it:8443/Laura/XRF-App-Bootstrap/RemoteFileSystem/Pergamena-Medioevale/mappa4_codapavone_500_v05.txt"
    
    Laura Cappelli's avatar
    Laura Cappelli committed
                },
                {
                    text: "Risoluzione 250",
                    icon: "glyphicon glyphicon-file",
                    selectedIcon: "glyphicon glyphicon-file",
    
                    url: "https://oc-chnet.cr.cnaf.infn.it:8443/Laura/XRF-App-Bootstrap/RemoteFileSystem/Pergamena-Medioevale/mappa4_codapavone_250_v05.txt"
    
    Laura Cappelli's avatar
    Laura Cappelli committed
                }]
            }]
        },
        {
            text: "RAFFAELLO",
            nodes: [
            {
                text: "La muta",
                nodes: [
                {
                    text: "Risoluzione 500",
                    icon: "glyphicon glyphicon-file",
                    selectedIcon: "glyphicon glyphicon-file"
                },
                {
                    text: "Risoluzione 250",
                    icon: "glyphicon glyphicon-file",
                    selectedIcon: "glyphicon glyphicon-file"
                }]
            }]
        }];
        return tree;
    }
    
    $(document).ready( function() {
    
    
        //bottone per l'importazione locale
        var fileInputButton: any = document.getElementById('myImport'); 
        fileInputButton.onchange = function(){
          //qua si salva il nome del file
          var fileName: string = fileInputButton.files[0];
          //creo l'oggetto filereader 
          var readerObject: any = new FileReader(); 
          //dico come andrà letto il file
          readerObject.readAsBinaryString(fileName);  
          readerObject.onload = function() {
            //riempio filestring con il contenuto del file solo dopo che il file
            //è stato caricato
            var fileString: string = readerObject.result; 
            readData(fileString);
          }
        }
        
        //costruzione dell'albero
    
    Laura Cappelli's avatar
    Laura Cappelli committed
        $('#FileTreeview').treeview({data: getTree()});
    
        $('#FileTreeview').on('nodeSelected', function(e, node){
    
    Laura Cappelli's avatar
    Laura Cappelli committed
            if(node['url'] != undefined){
                openFileFromServer(node['url']);
            }
        });
    
    
      //compressione sidenav settings
      var setLabel: any = $('.btn-settings');
      var isClosedSettings: boolean = false;
      setLabel.click(function () { setLabel_cross(); });
    
      function setLabel_cross() {
        if (isClosedSettings == true) {
          isClosedSettings = false;
          document.getElementById("mySidenavSet").style.width = "0";
          document.getElementById("wrapper").style.marginRight= "0";
          document.getElementById("setbtn").style.marginRight="-2px";
        } else {
          isClosedSettings = true;
          document.getElementById("mySidenavSet").style.width = "250px";
          document.getElementById("wrapper").style.marginRight = "250px";
          document.getElementById("setbtn").style.marginRight="248px";
        }
      }
    
      //compressione sidenav file system
      var fsLabel: any = $('.fs-label');
      var isClosedfs: boolean = false;
      fsLabel.click(function () { fsLabel_cross(); });
    
      function fsLabel_cross() {
        if (isClosedfs == true) {
          isClosedfs = false;
          fsLabel.removeClass('is-open');
          fsLabel.addClass('is-closed');
          document.getElementById("mySidenavfs").style.width = "0";
          document.getElementById("wrapper").style.marginLeft= "0";
          document.getElementById("fsbtn").style.marginLeft="-2px";
        } else {
          isClosedfs = true;
          fsLabel.removeClass('is-closed');
          fsLabel.addClass('is-open');
          document.getElementById("mySidenavfs").style.width = "250px";
          document.getElementById("wrapper").style.marginLeft = "250px";
          document.getElementById("fsbtn").style.marginLeft="248px";
        }
      }
    
    
    Laura Cappelli's avatar
    Laura Cappelli committed
    });    
    
    Laura Cappelli's avatar
    Laura Cappelli committed
    function openFileFromServer(url){
        var txtFile = new  XMLHttpRequest();
        txtFile.open("GET", url, true);
        txtFile.onreadystatechange = function(){
            if(txtFile.readyState === 4){
                if(txtFile.status === 200){
                    readData((txtFile.responseText));
                }
            }
        }
        txtFile.send(null);    
    }
    
    function callback(files) {
      //log il nome del file nella console
      console.log("Open file " + files[files.length-1].name);
      //creo l'oggetto filereader
      var readerObject: any = new FileReader();
      //dico come andrà letto il file
      readerObject.readAsBinaryString(files[files.length-1]);  
      readerObject.onload = function() {
        //riempio filestring con il contenuto del file solo dopo che il file
        //è stato caricato
        var fileString: string = readerObject.result; 
        readData(fileString);
      }
    }
    
    function makeDroppable(ele, callback) {
    
      //creo un elemento "input type file" non visibile nella pagina
      var input = document.createElement('input');
      input.setAttribute('type', 'file');
      input.setAttribute('multiple', true);
      input.style.display = 'none';
    
      //aggiungo a questo elemento un event listener al change
      input.addEventListener('change', triggerCallback);
      //aggiungo l'input all'elemento ele
      ele.appendChild(input);
    
      //questo evento è chiamato quando i file sono trascinati ma non ancora lasciati
      ele.addEventListener('dragover', function(e) {
        e.preventDefault(); //impediamo l'apertura del file
        e.stopPropagation();
        e.dataTransfer.dropEffect = 'copy';
        ele.classList.add('dragover'); //cambia lo stile dell'elemento
      });
    
      //l'evento è chiamato quando un file lascia la zona predefinita per il drag&drop
      ele.addEventListener('dragleave', function(e) {
        e.preventDefault();
        e.stopPropagation();
        ele.classList.remove('dragover');
      });
    
      //questo evento si innesca quando il drop è effettivamente avvenuto
      ele.addEventListener('drop', function(e) {
        e.preventDefault();
        e.stopPropagation();
        ele.classList.remove('dragover');
        triggerCallback(e);
      });
    
      //evento in caso di click
    
      // ele.addEventListener('click', function() {
      //   input.value = null;
      //   input.click();
      // });
    
    Laura Cappelli's avatar
    Laura Cappelli committed
    }
    
    //funzione che gestisce il tutto
    function triggerCallback(e) {
      var files; //array di file
      //controlliamo se il file è stato scelto o se è stato droppato
    
      if(e.dataTransfer) { //drop
    
    Laura Cappelli's avatar
    Laura Cappelli committed
        files = e.dataTransfer.files;
    
      }/*else if(e.target) { //click
    
    Laura Cappelli's avatar
    Laura Cappelli committed
        files = e.target.files;
    
    Laura Cappelli's avatar
    Laura Cappelli committed
      callback.call(null, files);
    }
    
    
    /*
    La funzione readData() prende in ingresso il file di input memorizzato nella 
    stringa "fileString". La funzione riempie la matrice "DataMatrix" con i dati
    in modo che essi siano memorizzati in un formato più leggibile. Sono ricavate
    anche altre variabili necessarie per il resto del codice.
    */ 
    function readData(fileString){
        var fileStringArray: any = fileString.split("\n");
        var readMode: string;
        var xMin: number = 0, yMin: number = 0;
        var xMax: number = 0, yMax: number = 0;
    
        //alert(fileStringArray);
        
        for(var i: number = 0; i < fileStringArray.length; i++){
            //mi soffermo solo sulle righe "intestazione delle x"
            if(parseInt(fileStringArray[i]) > 17000 && fileStringArray[i][0] =='5'){
                //se sono alla prima intestazione salvo la x e la y in xMin e yMin
                if(xMin == 0){
                    xMin = parseInt(fileStringArray[i]);
                    yMin = parseInt(fileStringArray[i+1]);
                    i++;
                //se ho già salvato la prima posizione controllo se sto leggendo per
                //righe o per colonne leggendo la seconda intestazione    
                } else {
                    if(parseInt(fileStringArray[i]) == xMin){
                        readMode = 'c';
                        //determino il passo (lato del pixel in micorn)
                        passo = Math.abs(yMin - fileStringArray[i+1]);
                        //se sto leggendo per colonne posso determinare qual'è xMax
                        //leggendo il vettore partendo dalla fine
                        for(var j: number = fileStringArray.length; j > i; j--){
                            //se la riga è "intestazione x" memorizzo xMax, lo
                            //confronto con xMin per vedere se occorre scambiarlo ed
                            //esco
                            if(parseInt(fileStringArray[j]) > 17000 && 
                                fileStringArray[j][0] =='5'){
    
                                xMax = parseInt(fileStringArray[j]);
                                if(xMax < xMin){
                                    var t: number = xMax;
                                    xMax = xMin;
                                    xMin = t;
                                }
                                break;
                            }
                        }
                    } else {
                        readMode = 'r';
                        //determino il passo (lato del pixel in micorn)
                        passo = Math.abs(xMin - fileStringArray[i]);
                        //se sto leggendo per righe posso determinare qual'è yMax
                        //leggendo il vettore partendo dalla fine
                        for(var j: number = fileStringArray.length; j > i; j--){
                            //se la riga è "intestazione y" memorizzo yMax, lo
                            //confronto con yMin per vedere se occorre scambiarlo ed
                            //esco
                            if(parseInt(fileStringArray[j]) > 17000 && 
                                fileStringArray[j][0] =='6'){
    
                                yMax = parseInt(fileStringArray[j]);
                                if(yMax < yMin){
                                    var t: number = yMax;
                                    yMax = yMin;
                                    yMin = t;
                                }
                                break;
                            }
                        }
                    }
                    //a questo punto posso uscire dal ciclo
                    break;
                }
            }
        }
    
        //alert(xMin + " " + xMax + " " + yMin + " " + yMax + " " + passo);
        
        /*
        A questo punto del codice ho determinato se sto leggendo per righe o per
        colonne e, nel primo caso, xMin e xMax, nel secondo caso yMin e yMax.
        Ora scorro nuovamente l'array distinguendo i casi in cui leggo per righe o
        per colonne, in questo modo determino o yMin e yMax, o xMin e xMax
        */
        for(var i: number = 2; i < fileStringArray.length; i++){
            //se leggo per colonne devo deterinare yMin e yMax
            if(readMode == 'c'){
                
                //mi soffermo sulle righe "intestazione y"
                if (parseInt(fileStringArray[i]) > 17000
                    && fileStringArray[i][0] == '6') {
                    
                    //cerco yMin e yMax
                    if (yMin > parseInt(fileStringArray[i])){
                        yMin = parseInt(fileStringArray[i]);
                    }
                    if(yMax < parseInt(fileStringArray[i])){
                        yMax = parseInt(fileStringArray[i]);
                    }
                }
    
                //quando arrivo a leggere la terza colonna sono sicura di aver già
                //trovato yMin e yMax quindi posso uscire dal ciclo
                if (parseInt(fileStringArray[i]) == xMin + (passo * 2)) {
                    break;
                }
    
            //se leggo per righe devo deterinare xMin e xMax 
            } else if (readMode == 'r') {
                //mi soffermo sulle righe "intestazione x"
                if (parseInt(fileStringArray[i]) > 17000
                    && fileStringArray[i][0] == '5') {
                    
                    //cerco xMin e xMax
                    if (xMin > parseInt(fileStringArray[i])){
                        xMin = parseInt(fileStringArray[i]);
                    }
                    if(xMax < parseInt(fileStringArray[i])){
                        xMax = parseInt(fileStringArray[i]);
                    }
                }
    
                //quando arrivo a leggere la terza riga sono sicura di aver già
                //trovato xMin e xMax quindi posso uscire dal ciclo
                if (parseInt(fileStringArray[i]) == yMin + 2000) {
                    break;
                }
            }
        }
    
        //alert(xMin + " " + xMax + " " + yMin + " " + yMax + " " + passo);
    
        /*
        a questo punto ho xMin, xMax, yMin e yMax; percorro l'array sistemando gli
        shift
        */
        for(var i: number = 0; i < fileStringArray.length; i++){
            //se leggo per colonne allora aggiungo 1passo alle y di tutte le colonne
            //dispari
            if(readMode == 'c' && parseInt(fileStringArray[i]) > 17000 &&
                fileStringArray[i][0] == '5' &&
                (parseInt(fileStringArray[i])/1000) % 2 != 0){
    
                fileStringArray[i+1] =
                    (parseInt(fileStringArray[i+1]) + passo).toString();
            }
            //se leggo per righe allora aggiungo 1 alle x di tutte le righe
            //dispari
            else if(readMode == 'r' && parseInt(fileStringArray[i]) > 17000 &&
                fileStringArray[i][0] == '5' &&
                (parseInt(fileStringArray[i+1])/1000) % 2 != 0){
    
                fileStringArray[i] =
                    (parseInt(fileStringArray[i]) + passo).toString();
                
            }
        }
    
        /*Ora che ho le posizioni corrette di ogni pixel posso riempire la matrice 
        che conterrà tutti i dati e sulla quale si opererà in tutto il programma.
        Definisco le dimensioni di tale matrice
        */
        if(readMode == 'c'){
            xDim = (xMax - xMin)/passo + 1;
            yDim = (yMax - yMin)/passo - 2;
        } else {
            xDim = (xMax - xMin)/passo - 2;
            yDim = (yMax - yMin)/passo + 1;
        }
    
        //alert(xDim + " " + yDim);
    
        /*
        definisco la matrice DataMatrix: yDim righe da xDim elementi, ogni
        elemento della matrice è un vettore di 16384 elementi
        */
        DataMatrix = new Array(xDim);
        for(var i: number = 0; i < xDim; i++){
            DataMatrix[i] = new Array(yDim);
            for(var j: number = 0; j < yDim; j++){
                DataMatrix[i][j] = new Array(16384);
                for(var k: number = 0; k < 16384; k++){
                    DataMatrix[i][j][k] = 0;
                }
            }
        }
        
        /*
        ora devo scorrere l'array con il contenuto del file per riempire la matrice
        */
        for(var i: number = 0; i < fileStringArray.length; i++){
            var x: number;
            var y: number;
            var write: boolean;
            //se leggo una riga "intestazione x":
            if(parseInt(fileStringArray[i]) > 17000 && 
                fileStringArray[i][0] == '5'){
                //memorizzo le x e le y del punto e avanzo direttamente al primo
                //conteggio perchè ho già letto la i successiva alla corrente
                x = (parseInt(fileStringArray[i]) - xMin);
                if(x != 0){
                    x /= passo;
                }
                y = (parseInt(fileStringArray[i+1]) - yMin);
                if(y != 0){
                    y /= passo;
                }
                i++;
    
                //se non è un pixel del bordo e sto leggendo per colonne allora
                //segnalo che i successivi valori sono da considerare e sistemo
                //la y del pixel così da normalizzarla dopo il taglio dei bordi
                if(readMode == 'c' && y != 0 && y != 1 && y != (yMax - yMin)/passo
                    && y != (yMax - yMin)/passo + 1){
                    write = true;
                    y -= 2;
                }
                //se non è un pixel del bordo e sto leggendo per righe allora
                //segnalo che i successivi valori sono da considerare e sistemo
                //la x del pixel così da normalizzarla dopo il taglio dei bordi
                else if(readMode == 'r' && x != 0 && x != 1 &&
                    x != (xMax - xMin)/passo && x != (xMax - xMin)/passo + 1){
                    write = true;
                    x -= 2;
                }
                //se sto leggendo un pixel del bordo segnalo che i valori successivi
                //sono da ignorare
                else{
                    write = false;
                }
                //if(write == true && (y < 0 || y > 92)) alert(x + " " + y);
            }
    
            //sto leggendo una riga di conteggio e il pixel in questione non è un
            //pixel del bordo
            else if(parseInt(fileStringArray[i]) < 17000 && write == true){
                //Aggiorno i dati nella matrice DataMatrix invertendo la posizione
                //delle x e delle y
                DataMatrix[xDim-x-1][yDim-y-1][parseInt(fileStringArray[i])] += 1;
            }
        }
    
        //calcolo il numero di conteggi per pixel e li salvo nella matrice nOfCounts
        nOfCounts = new Array(xDim);
        for(var i: number = 0; i < xDim; i++){
            nOfCounts[i] = new Array(yDim);
            for(var j: number = 0; j < yDim; j++){
                nOfCounts[i][j] = sumVect(DataMatrix[i][j], 0, DataMatrix[i][j].length);
            }
        }
        
        //definisco l'origine da utilizzare per il click del mouse
        newOrigin = {xp: 0, yp: 0};
    
        //calcolo il conteggio massimo della matrice
        maxAbsolute = findMax(nOfCounts, {xp: 0, yp: 0}, {xp: xDim-1, yp: yDim-1});
    
        //caricati i dati posso impostare i dati per il grafico nella sua
        //interezza e disegnare l'immagine
        setDataForCompleteChart();
        alert("Dati caricati con successo");
        drawImg({xp: 0, yp: 0}, {xp: xDim - 1, yp: yDim - 1}, 0, 55);
        drawChart({xp: 0, yp: 0}, {xp: xDim - 1, yp: yDim - 1}, 0, 55);
    }
    
    
    /*
    la funzione drawImg disegna il canvas con l'immagine selezionata: può essere
    l'immagine completa, l'immagine zoommata o l'immagine che mostra solo alcuni
    elementi. La funzione è anche responsabile di gestire le richieste degli utenti
    riguardo alla mappa.
    */
    function drawImg(pixel1: coordinates, pixel2:coordinates, xMinRange: number, xMaxRange: number){
        
        //determino le dimensioni del canvas e le dimensioni dei pixel per
        //questo disegno    
        var nPixelX: number = pixel2.xp - pixel1.xp + 1;
        var nPixelY: number = pixel2.yp - pixel1.yp + 1;
        var dimPixelx: number = Math.floor(maxMappaWidth/nPixelX);
        var dimPixely: number = Math.floor(maxMappaHeight/nPixelY);
        pixelDim = (dimPixelx < dimPixely) ? dimPixelx : dimPixely;    
        var canvas = <HTMLCanvasElement> document.getElementById("myCanvas");
        canvas.height = nPixelY * pixelDim;
        canvas.width = nPixelX * pixelDim;
        var ctx = canvas.getContext("2d");
    
    Laura Cappelli's avatar
    Laura Cappelli committed
        //se il range è completo, quindi non è stato selzionato nessun picco, 
        //procedo utilizzando nOfCounts come valori da rappresentare
        if(xMaxRange - xMinRange >= 55){
            //controllo se devo colorare con il massimo assoluto o con quello
            //relativo
            var max: number;
            if (rePrint) max = findMax(nOfCounts, pixel1, pixel2);
            else max = maxAbsolute;
    
            //controllo se è richiesta saturazione del massimo
            max = (max * document.getElementById("SaturationSlider").value)/100 ;
            
            //disegno la canvas passando la matrice con i dati e il massimo
            drawCanvas(nOfCounts, max);
    
        } else {
            //determino i canali da xMinRange e xMaxRange
            var xMinRangeCh: number = Math.floor((((xMinRange*1000)+b)/a)-1); //16
            var xMaxRangeCh: number = Math.floor((((xMaxRange*1000)+b)/a)-1); //16371
    
            //devo calcolare il numero di conteggi solo delle x selezionate
            var nOfCountsRelative: number[][];
            nOfCountsRelative = new Array(xDim);
            for(var i: number = 0; i < xDim; i++){
                nOfCountsRelative[i] = new Array(yDim);
                for(var j: number = 0; j < yDim; j++){
                    nOfCountsRelative[i][j] =
                        sumVect(DataMatrix[i][j], xMinRangeCh, xMaxRangeCh);
                }
            }
            //calcolo il massimo
            var max: number;
            if (rePrint)
                max = findMax(nOfCountsRelative, pixel1, pixel2);
            else
                max = findMax(nOfCountsRelative,{xp:0,yp:0},{xp:xDim-1,yp:yDim-1});
            max = (max * document.getElementById("SaturationSlider").value)/100 ;
    
            //disegno la canvas con i giusti valori
            drawCanvas(nOfCountsRelative, max);
        }
    
        /*
        La funzione drawCanvas riceve in input la matrice con i dati e il valore
        da utilizzare come massimo. La funzione disegna la mappa nel canvas.
        */
        function drawCanvas(noc, max){
            //alert(pixel1.xp + " " + pixel1.yp + " " + pixel2.xp + " " + pixel2.yp);
            //scorro tutti i pixel da disegnare: ne determino il colore e li disegno
            //nella giusta posizione.
    
            //prima verifico se devo aggiungere una trasparenza ai pixel
            var setTrsp: number = 1 -
                document.getElementById("TrasparencySlider").value / 100;
            
            var color:string = "";
            for (var i: number = pixel1.xp; i <= pixel2.xp; i++) {
                for (var j: number = pixel1.yp; j <= pixel2.yp; j++) {
                    var intensity: number = noc[i][j] / max;
                    if(intensity < 1/5) //blu
                        color = "rgba(0, 0, " + Math.floor(intensity*5*255) + "," +
                            setTrsp + ")";
                    else if (1/5 <= intensity && intensity < 2/5) //blu+verde
                        color="rgba(0, "+Math.floor((intensity-1/5)*5*255)+",255, "
                            + setTrsp + ")"; 
                    else if (2/5 <= intensity && intensity < 3/5) // verde-blu
                        color="rgba(0, 255, "+(255-Math.floor((intensity-2/5)*5*255))
                            + ", " + setTrsp + ")"; 
                    else if (3/5 <= intensity && intensity < 4/5) //verde + rosso 
                        color="rgba("+Math.floor((intensity-3/5)*5*255)+",255,0," +
                            setTrsp + ")"; 
                    else //rosso -verde
                        color="rgba(255,"+(255-Math.floor((intensity-4/5)*5*255)) +
                            ", 0, " + setTrsp + ")";
                    ctx.fillStyle = color;
                    ctx.fillRect((i - pixel1.xp) * pixelDim,
                        (j - pixel1.yp) * pixelDim, pixelDim, pixelDim);
                }
            }
            //annullo reprint
            rePrint = false;
    
            //Determino le dimensioni reali dei pixel
            var canvasDim: any = document.querySelector ('#myCanvas').getBoundingClientRect();
            realPixelDim = round3(((canvasDim.right - canvasDim.left)/nPixelX + (canvasDim.bottom - canvasDim.top)/nPixelY)/2);
            //alert(realPixelDim);
        }
        /*
        mi metto in ascolto della fine dello spostamento dello slider della
        saturazione: ridisegno il canvas con gli stessi input (verrà modificato il
        massimo in fase di disegno)
        */
        var satSlider = <HTMLButtonElement>document.getElementById("SaturationSlider");
        satSlider.onmouseup = function(){
            drawImg(pixel1, pixel2, xMinRange, xMaxRange);
        }  
    
        /*
        mi metto in ascolto del click sul bottone rePlot. Nel caso venga cliccato
        cambio stato alla variabile reprint, resetto la saturazione e ridisegno il
        canvas con gli stessi input
        */
        var rePlotButton = <HTMLButtonElement>document.getElementById("rePlot");
        rePlotButton.onclick = function(){
            rePrint = true;
            satSlider.value = "100";
            drawImg(pixel1, pixel2, xMinRange, xMaxRange);
        }
    
        /*
        mi metto in ascolto della fine dello spostamento dello slider della
        trasparenza: ridisegno il canvas con gli stessi input (verrà modificata la
        trasparenza in fase di disegno)
        */
        var trspSlider = <HTMLButtonElement>document.getElementById("TrasparencySlider");
        trspSlider.onmouseup = function(){
            drawImg(pixel1, pixel2, xMinRange, xMaxRange);
        }
    
        /*
        mi metto in ascolto del click sul bottone reset. Nel caso venga cliccato
        resetto tutte le variabili e disegno immagine e canvas
        */
        var resetButton = <HTMLButtonElement>document.getElementById("reset");
        resetButton.onclick = function(){
            newOrigin = {xp: 0, yp: 0};
            rePrint = false;
            calibrated = false;
            globalxMinRange = 0;
            globalxMaxRange = 55;
            satSlider.value = "100";
            trspSlider.value = "0";
            document.getElementById("spinBoxMin").setAttribute("value", "-");
            document.getElementById("spinBoxMax").setAttribute("value", "-");
            drawImg({xp: 0, yp: 0}, {xp: xDim - 1, yp: yDim - 1}, 0, 55);
            drawChart({xp: 0, yp: 0}, {xp: xDim - 1, yp: yDim - 1}, 0, 55);
        }
    
        //mi metto in ascolto del click sul bottone per il download dell'immagine
        var ExportImgButton = <HTMLButtonElement>document.getElementById("ExportImage");
        ExportImgButton.onclick = function(){
            var img = canvas.toDataURL("image/png");
            ExportImgButton.href = img;
            //document.write('<img src="'+img+'"/>');
        }
    
    
    }
    
    
    /*la funzione drawChart riceve in input i due estremi dell'immagine (può essere
    l'immagine completa o solo una parte) e i due estremi dell'intervallo da 
    rappresentare sull'asse x (anche in questo caso può essere l'asse x completa
    o un sotto-intervallo). La funzione disegna il grafico richiesto
    */
    function drawChart(pixel1: coordinates, pixel2:coordinates, xMinRange: number, xMaxRange: number){
        //definisco la variabile "grafico", i bottoni relativi al grafico, il tag
        //select e le due spinbox con il relativo botton
        var g: any;
        var setlinearButton =
            <HTMLButtonElement>document.getElementById("setlinearButton");
        var setlogButton =
            <HTMLButtonElement>document.getElementById("setlogButton");
        var setEnergyButton =
            <HTMLButtonElement>document.getElementById("setEnergyButton");
        var setChannelsButton =
            <HTMLButtonElement>document.getElementById("setChannelsButton");
        var box1 = <HTMLElement>document.getElementById("spinBoxMin");
        var box2 = <HTMLElement>document.getElementById("spinBoxMax");
        var SubmitRangeButton = 
            <HTMLButtonElement>document.getElementById("readSpinbox");
        var elementSelect = 
            <HTMLButtonElement>document.getElementById("elementSelect");
        var ExportGraphButton =
            <HTMLButtonElement>document.getElementById("ExportGraph");
        
    
        //controllo se il grafico è da disegnare calibrato poi regolo i bottoni
        if(calibrated){
            setEnergyButton.disabled = true;
            setChannelsButton.disabled = false;
            SubmitRangeButton.disabled = false;
        } else {
            setEnergyButton.disabled = false;
            setChannelsButton.disabled = true;
            SubmitRangeButton.disabled = true;
        }
        setlinearButton.disabled = true;
        setlogButton.disabled = false;
    
        //verifico se devo disegnare il grafico nella sua completezza: in quel caso
        //ho già la stringa con i dati e posso direttamente procedere con il disegno
        if(pixel1.xp == 0 && pixel1.yp == 0 && pixel2.xp == xDim-1 &&
            pixel2.yp == yDim-1){
            //controllo se devo disegare il grafico calibrato o non calibrato
            if(!calibrated){
                var chartTitle: string = "Chart from (0, 0) to (" + (xDim-1) + ", " 
                + (yDim-1) + ")";
                g = setChart(dataCompleteChart, chartTitle);
            } else {
                var chartTitle: string = "Calibrated chart from (0, 0) to (" +
                    (xDim-1) + ", " + (yDim-1) + ")";
                g = setChart(dataCompleteChartCalibrated, chartTitle);
            }
        //se devo disegnare il grafico solo parzialmente per alcuni pixel devo
        //calcolare i dati    
        } else {
            //creo un array di 16384 elementi con la somma dei conteggi solo dei
            //pixel da considerare
            var dataForChart: number[] = new Array(16384);
            for(var i: number = 0; i < 16384; i++){
                dataForChart[i] = 0;
            }
            for(var i: number = pixel1.xp; i <= pixel2.xp; i++){
                for(var j: number = pixel1.yp; j <= pixel2.yp; j++){
                    for(var k: number = 0; k < 16384; k++){
                        dataForChart[k] += DataMatrix[i][j][k];
                    }
                }
            }
            //controllo se devo disegare il grafico calibrato o non calibrato
            if(!calibrated){
                //definisco i dati da passare al grafico
                var dataChart: string = "Channel,Counts\n";
                for(var i: number = 0; i < 16348; i++){
                    dataChart += i + "," + dataForChart[i] + "\n";
                }
                //determino il titolo del grafico
                if(pixel1.xp == pixel2.xp && pixel1.yp == pixel2.yp){
                    var chartTitle: string = "Chart pixel (" + pixel1.xp + ", " +
                    (yDim - pixel1.yp - 1) + ")";
                } else {
                    var chartTitle: string = "Chart from (" + pixel1.xp + "," +
                    pixel2.xp + ") to (" + (yDim - pixel1.yp - 1) + ", " +
                    (yDim - pixel2.yp - 1) + ")";
                }
                //disegno il grafico
                g = setChart(dataChart, chartTitle);
            } else {
               //definisco i dati da passare al grafico
                var dataChartCalibrated: string = "Energy,Counts\n";
                for(var i: number = 0; i < 16348; i++){
                    dataChartCalibrated += round3(((i+1)*a-b)/1000)  +
                    "," + dataForChart[i] + "\n";
                }
                //determino il titolo del grafico
                if(pixel1.xp == pixel2.xp && pixel1.yp == pixel2.yp){
                    var chartTitle: string = "Calibrated chart pixel (" + pixel1.xp +
                    ", " + (yDim - pixel1.yp - 1) + ")";
                } else {
                    var chartTitle: string = "Calibrated chart from (" + pixel1.xp +
                    ", " + pixel2.xp + ") to (" + (yDim - pixel1.yp - 1) + ", " +
                    (yDim - pixel2.yp - 1) + ")";
                }
                //disegno il grafico
                g = setChart(dataChartCalibrated, chartTitle);
            }     
        }
    
        /*
        la funzione setChart riceve in input la stringa con i dati del grafico e il
        titolo del grafico. Dopo aver disegnato il grafico restituise in output la
        variabile con il grafico stesso 
        */
        function setChart(dataString: string, charTitle: string){
            //definisco la variabile che contiene gli estremi dell'asse x da
            //visualizzare e la riempio a seconda se sto disegnando il grafico
            //calibrato o non calibrato. Definisco anche l'etichetta delll'asse x
            var xArrayRange: number[];
            var xLab: string;
            if(!calibrated){
                xArrayRange = [0, 16383];
                xLab = "ADC Channel";
            }else{
                xArrayRange = [xMinRange, xMaxRange];
                xLab = "Energy (keV)";
            }
    
            //imposto le dimensioni del grafico
            var bb: any = document.querySelector ('#chart-pannel').getBoundingClientRect();
            var chartWidth = bb.right - bb.left - 50;
            $('#chart').css('width', chartWidth);
    
            var bb2: any = document.querySelector ('#myCanvas').getBoundingClientRect();
            var chartHeight: number = bb2.bottom - bb2.top;
            $('#chart').css('height', chartHeight);
    
            //disegno il grafico
            var graphs: any = new Dygraph(document.getElementById("chart"),
                dataString, {
                    title: charTitle,
                    ylabel: 'Counts',
                    xlabel: xLab,
                    //legend: 'always',
                    labelsDivStyles: { 'textAlign': 'right' },
                    dateWindow: xArrayRange,
                    showRangeSelector: true,
                    logscale: false
                }
            );
    
    
            //dimenioni responsive del grafico
            document.getElementById("fsbtn").onclick = function (){
                setTimeout(function(){
                    g = setChart(dataString, charTitle);
                }, 400);
                
            }
            document.getElementById("setbtn").onclick = function (){
                setTimeout(function(){
                    g = setChart(dataString, charTitle);
                }, 400);
            }
    
    
    Laura Cappelli's avatar
    Laura Cappelli committed
            return graphs;
        }
    
        //mi metto in ascolto dei click sui bottoni relativi al grafico
        setlinearButton.onclick = function(){
            g.updateOptions( {logscale: false} );
            setlinearButton.disabled = true;
            setlogButton.disabled = false;
        }
        setlogButton.onclick = function(){
            g.updateOptions( {logscale: true} );
            setlinearButton.disabled = false;
            setlogButton.disabled = true;
        }
        setEnergyButton.onclick = function () { 
            calibrated = true;
            drawChart(pixel1, pixel2, 0, 55);
            box1.setAttribute("value", "0");
            box2.setAttribute("value", "55");
        }
        setChannelsButton.onclick = function () {
            calibrated = false;
            drawChart(pixel1, pixel2, 0, 55);
            box1.setAttribute("value", "-");
            box2.setAttribute("value", "-");
        }
        ExportGraphButton.onclick = function(){
            var img = document.getElementById("chartToImg");
            Dygraph.Export.asPNG(g, img);
            ExportGraphButton.href = img.src.replace('image/png','image/octet-stream');
        }
        
        SubmitRangeButton.onclick = function(){
            peackSelection(0, 0);
        }
    
        /*
        la funzione peakSelection riceve in input gli estremi dell'intervallo da
        rappresentare e lancia le funzioni drawImg e drawChart con l'intervallo dato
        */
        function peackSelection(xMinRange: number, xMaxRange: number){
            //se l'intervallo è [0, 0] significa che devo leggere dalle spinbox i
            //valori desiderati.
            if(xMinRange == 0 && xMaxRange == 0){
                xMinRange = box1.value;
                xMaxRange = box2.value;
            }
            //Aggiornamento variabili globali
            globalxMinRange = xMinRange;
            globalxMaxRange = xMaxRange;
            newOrigin = { xp: 0, yp: 0};
            rePrint = false;
            calibrated = true;
            //disegni di immagine e grafico
            drawImg({xp:0, yp:0}, {xp:xDim-1, yp:yDim-1}, globalxMinRange, globalxMaxRange);
            drawChart({xp:0, yp:0}, {xp:xDim-1, yp:yDim-1}, globalxMinRange, globalxMaxRange);
        }
    
        //mi metto in ascolto di uno zoom manuale sul grafico
        var grp = <HTMLButtonElement>document.getElementById("chart");
        grp.onclick = function(){
            var r: number[];
            r = g.xAxisRange();
            if(!calibrated){
                r[0] = Math.floor((((r[0] + 1) * a) - b) / 1000);
                r[1] = Math.floor((((r[1] + 1) * a) - b) / 1000);
            } else {
                r[0] = round3(r[0]);
                r[1] = round3(r[1]);
                box1.setAttribute("value", r[0].toString());
                box2.setAttribute("value", r[1].toString());
            }
            globalxMinRange = r[0];
            globalxMaxRange = r[1];
            drawImg(pixel1, pixel2, r[0], r[1]);
        }
    
        /*
        mi metto in ascolto della selezione di un elemento
        */
        elementSelect.onchange = function(){
            var element: string = document.getElementById("elementSelect").value;
            switch(element){
                //Ca 
                case "1":
                    peackSelection(3.6, 3.8);
                    box1.setAttribute("value", "3.60");
                    box2.setAttribute("value", "3.80");
                    break;
                //Pb
                case "2":
                    peackSelection(10.4, 10.7);
                    box1.setAttribute("value", "10.40");
                    box2.setAttribute("value", "10.70");
                    break;
                //Hg
                case "3":
                    peackSelection(9.8, 10.15);
                    box1.setAttribute("value", "9.80");
                    box2.setAttribute("value", "10.15");
                    break;
                //Fe
                case "4":
                    peackSelection(6.3, 6.5);
                    box1.setAttribute("value", "6.30");
                    box2.setAttribute("value", "6.50");
                    break;
                //Cu
                case "5":
                    peackSelection(7.85, 8.2);
                    box1.setAttribute("value", "7.85");
                    box2.setAttribute("value", "8.20");
                    break;
                //Zn
                case "6":
                    peackSelection(8.5, 8.72);
                    box1.setAttribute("value", "8.50");
                    box2.setAttribute("value", "8.72"); 
                    break;
                //Ti
                case "7":
                    peackSelection(4.35, 4.65);
                    box1.setAttribute("value", "4.35");
                    box2.setAttribute("value", "4.65");
                    break;
                //K
                case "8":
                    peackSelection(3.2, 3.42);
                    box1.setAttribute("value", "3.20");
                    box2.setAttribute("value", "3.42");
                    break;
                //Co
                case "9":
                    peackSelection(6.8, 7.05);
                    box1.setAttribute("value", "6.80");
                    box2.setAttribute("value", "7.05");
                    break;
                //default
                default:
                    peackSelection(0, 55);
                    box1.setAttribute("value", "0");
                    box2.setAttribute("value", "55");
                    break;
            }