Skip to content
Snippets Groups Projects
LoadFile.ts 43.5 KiB
Newer Older
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;
        }