Newer
Older
// Copyright 2017 Istituto Nazionale di Fisica Nucleare
//
// Licensed under the EUPL
let a: number = 3.36275; //costante moltiplicativa per la calibrazione
let b: number = 58.2353; //costante additiva per la calibrazione
let pixelDim: number; //dimensione dei pixel responsive
let maxAbsolute: number; //massimo conteggio della matrice nOfCounts
let xDim: number = 0, yDim: number = 0; //numero di pixel nelle due dimensioni
let DataMatrix: number[][][], nOfCounts: number[][]; //matrici con i dati
let rePrint: boolean = false; //variabile per ricolorare con il max relativo
let newOrigin: coordinates; //nuovo origine nel caso di zoom
let zPixel1: coordinates; //pixel1 dello zoom
let zPixel2: coordinates; //pixel2 dello zoom
let dataCompleteChart: string = "Channel,Counts\n";
let dataCompleteChartCalibrated: string = "Energy,Counts\n";
let calibrated: boolean = false; //variabile per il controllo sulla calibrazione
let depth: number = 8000; //profondità massima della matrice
let channelDepth: number = round3(((depth + 1) * a - b) / 1000); //profondità massima in canali
let globalxMinRange: number = 0, globalxMaxRange: number = channelDepth;
$('[data-toggle="tooltip"]').tooltip();
//creazione dell'albero e gestione barre laterali
setImportFile();
let droppableArea: any = document.querySelector('.droppable');
zPixel1 = { xp: 0, yp: 0 };
zPixel2 = { xp: 0, yp: 0 };
});
//funzione per la compressione della sidenav sx
let fsLabel: any = $('.sidebar-label');
let isClosedfs: boolean = false;
$('.w3-bar-block').css('width', "65px");
$('.text-sidenav').css('display', 'none');
$('#collapse-symbol').attr('title', 'Open Sidebar');
$("#collapse-symbol").removeClass("fa-angle-double-left");
$("#collapse-symbol").addClass("fa-angle-double-right");
$('.w3-bar-block').css('width', "200px");
$('.text-sidenav').css('display', 'inline');
$("#collapse-symbol").removeClass("fa-angle-double-right");
$("#collapse-symbol").addClass("fa-angle-double-left");
}
}
}
//funzione che definisce l'area su cui si può eseguire il drag&drop
//creo l'elemento "input type file" non visibile e lo aggiungo a "droppableArea"
input.setAttribute('type', 'file');
input.setAttribute('multiple', true);
input.style.display = 'none';
droppableArea.appendChild(input);
//questo evento è chiamato quando i file sono trascinati ma non ancora lasciati
droppableArea.addEventListener('dragover', function (e)
{
e.preventDefault(); //impediamo l'apertura del file
e.stopPropagation();
e.dataTransfer.dropEffect = 'copy';
droppableArea.classList.add('dragover');
});
//l'evento è chiamato quando un file lascia la zona predefinita per il drag&drop
droppableArea.addEventListener('dragleave', function (e)
{
e.preventDefault();
e.stopPropagation();
droppableArea.classList.remove('dragover');
});
//questo evento si innesca quando il drop è effettivamente avvenuto
droppableArea.addEventListener('drop', function (e)
{
e.preventDefault();
e.stopPropagation();
droppableArea.classList.remove('dragover');
callback.call(null, e.dataTransfer.files);
});
}
//funzione chiamata in caso di drag&drop responsabile dell'apertura del file droppato,
//della sua lettura e del passaggio del suo contenuto alla funzione readData()
$("#load-spinner").css("display", "inline");
console.log("Try to open " + files[files.length - 1].name + " ...");
let readerObject: any = new FileReader();
readerObject.readAsBinaryString(files[files.length - 1]);
readerObject.onload = function ()
{
let fileString: string = readerObject.result;
readData(fileString);
}
}
//la funzione prepara i dati per il grafico completo
//per ogni pixel sommo i conteggi di tutti i canali rilevati
let dataForChart: number[] = new Array(depth);
for (let i: number = 0; i < depth; i++) {
dataForChart[i] = 0;
for (let i: number = 0; i < xDim; i++) {
for (let j: number = 0; j < yDim; j++) {
for (let k: number = 0; k < depth; k++) {
dataForChart[k] += DataMatrix[i][j][k];
}
}
}
//riempio le stringhe con i dati per il grafico
for (let i: number = 0; i < depth; i++) {
dataCompleteChart += (i + 1) + "," + dataForChart[i] + "\n";
dataCompleteChartCalibrated += round3(((i + 1) * a - b) / 1000) + "," + dataForChart[i] + "\n";
}
}
//La funzione riceve in input un vettore di cui somma gli elementi compresi tra
//gli indici from e to
function sumVect(vect: number[], from: number, to: number)
{
let sum: number = 0;
for (let i: number = from; i < to; i++) { sum += vect[i]; }
return sum;
}
//La funzione riceve in input la matrice e gli estremi della sottomatrice di cui
//calcola il massimo
function findMax(matrix: number[][], pixel1: coordinates, pixel2: coordinates)
{
let max: number = 0;
for (let i: number = pixel1.xp; i <= pixel2.xp; i++) {
for (let j: number = pixel1.yp; j <= pixel2.yp; j++) {
if (matrix[i][j] > max) {
max = matrix[i][j];
}
//Funzione per arrotondare il numero in input alla terza cifra decimale
return (Math.round(val * Math.pow(10, 3)) / Math.pow(10, 3));
}
//la funzione findPosition definisce la posizione del cursore del mouse
//relativa al canvas nel momento in cui avviene l'evento passato in input
function findPosition(event: any, pixel: coordinates)
{
let scrollTOP: number = (document.documentElement.scrollTop) ?
document.documentElement.scrollTop : document.body.scrollTop;
let scrollLEFT: number = (document.documentElement.scrollLeft) ?
document.documentElement.scrollLeft : document.body.scrollLeft;
let allX: number = event.clientX + scrollLEFT;
let allY: number = event.clientY + scrollTOP;
let elParent: any = document.getElementById('myCanvas');
let objX: number = 0, objY: number = 0;
while (elParent) {
objX += elParent.offsetLeft;
objY += elParent.offsetTop;
elParent = elParent.offsetParent;
}
pixel.xp = Math.floor((allX - objX - 1) / pixelDim) + newOrigin.xp;
pixel.yp = Math.floor((allY - objY - 1) / pixelDim) + newOrigin.yp;
}
//la funzione findPosDown memorizza la posizione del pixel cliccato
//la funzione findPosUp memorizza la posizione del pixel quando il mouse viene
//rilasciato, ordina le coordinate, aggiorna l'origine e la pagina.
if (zPixel1.xp > zPixel2.xp) {
tmp = zPixel1.xp;
zPixel1.xp = zPixel2.xp;
zPixel2.xp = tmp;
}
if (zPixel1.yp > zPixel2.yp) {
tmp = zPixel1.yp;
zPixel1.yp = zPixel2.yp;
zPixel2.yp = tmp;
}
//se è stato cliccato un punto disegno il grafico, altrimenti disegno anche il
//canvas e aggiorno l'origine
//alert(zPixel1.xp + ", " + zPixel1.yp + " - " + zPixel2.xp + ", " + zPixel2.yp);
if (zPixel1.xp != zPixel2.xp || zPixel1.yp != zPixel2.yp) {
newOrigin = { xp: zPixel1.xp, yp: zPixel1.yp };
drawImg(zPixel1, zPixel2, globalxMinRange, globalxMaxRange);
}
drawChart(zPixel1, zPixel2, globalxMinRange, globalxMaxRange);
}
//la funzione disegna il rettangolo durante la selezione di un'area della mappa
function zoomRect()
{
let selectCanvas = <HTMLCanvasElement>document.getElementById("selectionCanvas");
let ctx = selectCanvas.getContext("2d");
// style the context
ctx.fillStyle = "rgba(0, 110, 255, 0.25)";
// this flage is true when the user is dragging the mouse
// these vars will hold the starting mouse position
let startX: number;
let startY: number;
let mouseX: number;
let mouseY: number;
// these vars will hold the starting mouse position
//calculate mouse position
let scrollTOP: number = (document.documentElement.scrollTop) ?
document.documentElement.scrollTop : document.body.scrollTop;
let scrollLEFT: number = (document.documentElement.scrollLeft) ?
document.documentElement.scrollLeft : document.body.scrollLeft;
let allX: number = e.clientX + scrollLEFT;
let allY: number = e.clientY + scrollTOP;
let elParent: any = document.getElementById('myCanvas');
let objX: number = 0, objY: number = 0;
while (elParent) {
objX += elParent.offsetLeft;
objY += elParent.offsetTop;
elParent = elParent.offsetParent;
}
startX = allX - objX;
startY = allY - objY;
e.preventDefault();
e.stopPropagation();
// the drag is over, clear the dragging flag
isDown = false;
ctx.clearRect(0, 0, selectCanvas.width, selectCanvas.height);
e.preventDefault();
e.stopPropagation();
// the drag is over, clear the dragging flag
isDown = false;
ctx.clearRect(0, 0, selectCanvas.width, selectCanvas.height);
e.preventDefault();
e.stopPropagation();
// if we're not dragging, just return
//calculate mouse position
let scrollTOP: number = (document.documentElement.scrollTop) ?
document.documentElement.scrollTop : document.body.scrollTop;
let scrollLEFT: number = (document.documentElement.scrollLeft) ?
document.documentElement.scrollLeft : document.body.scrollLeft;
let allX: number = e.clientX + scrollLEFT;
let allY: number = e.clientY + scrollTOP;
let elParent: any = document.getElementById('myCanvas');
let objX: number = 0, objY: number = 0;
while (elParent) {
objX += elParent.offsetLeft;
objY += elParent.offsetTop;
elParent = elParent.offsetParent;
}
mouseX = allX - objX;
mouseY = allY - objY;
// Put your mousemove stuff here
// clear the canvas
ctx.clearRect(0, 0, selectCanvas.width, selectCanvas.height);
// calculate the rectangle width/height based
// on starting vs current mouse position
let width = mouseX - startX;
let height = mouseY - startY;
// draw a new rect from the start position
// to the current mouse position
$("#selectionCanvas").mousedown(function (e) { handleMouseDown(e); });
$("#selectionCanvas").mousemove(function (e) { handleMouseMove(e); });
$("#selectionCanvas").mouseup(function (e) { handleMouseUp(e); });
$("#selectionCanvas").mouseout(function (e) { handleMouseOut(e); });
}
//la funzione drawImg disegna il canvas con l'immagine desiderata ed è responsabile
//della gestione di tutti gli eventi ad essa associati
function drawImg(pixel1: coordinates, pixel2: coordinates, xMinRange: number, xMaxRange: number)
{
//numero di pixel per dimensione
let nPixelX: number = pixel2.xp - pixel1.xp + 1;
let nPixelY: number = pixel2.yp - pixel1.yp + 1;
//dimensione dei canvas
let mappaPannelDim: any = document.querySelector('#mappa-pannel').getBoundingClientRect();
let mappaWidth: number = mappaPannelDim.right - mappaPannelDim.left - 40;
let mappaHeigth: number = 400;
//dimensione reale dei pixel
let dimPixelx: number = Math.floor(mappaWidth / nPixelX);
let dimPixely: number = Math.floor(mappaHeigth / nPixelY);
pixelDim = (dimPixelx < dimPixely) ? dimPixelx : dimPixely;
//dimensioni esatte dei canvas
(<HTMLCanvasElement>document.getElementById("myCanvas")).height = nPixelY * pixelDim;
(<HTMLCanvasElement>document.getElementById("myCanvas")).width = nPixelX * pixelDim;
(<HTMLCanvasElement>document.getElementById("selectionCanvas")).height = nPixelY * pixelDim;
(<HTMLCanvasElement>document.getElementById("selectionCanvas")).width = nPixelX * pixelDim;
let ctx = (<HTMLCanvasElement>document.getElementById('myCanvas')).getContext('2d'); //contesto del canvas
if (xMaxRange - xMinRange >= channelDepth) { //range completo
let max: number; //massimo relativo o assoluto
if (rePrint) max = findMax(nOfCounts, pixel1, pixel2);
else max = maxAbsolute;
max = (max * document.getElementById("SaturationSlider").value) / 100;
//max = (max * parseInt($("#SaturationSlider").attr("value")))/100 ; //saturazione
drawCanvas(nOfCounts, max); //disegno
} else { //range parziale (solo alcuni canali)
let xMinRangeCh: number = Math.floor((((xMinRange * 1000) + b) / a) - 1); //16
let xMaxRangeCh: number = Math.floor((((xMaxRange * 1000) + b) / a) - 1); //16371
//calcolo il numero di conteggi solo dei canali selezionati
nOfCountsRelative[i][j] = sumVect(DataMatrix[i][j], xMinRangeCh, xMaxRangeCh);
}
}
//calcolo il massimo
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;
//max = (max * parseInt($("#SaturationSlider").attr("value")))/100 ; //saturazione
drawCanvas(nOfCountsRelative, max); //disegno
}
//La funzione, ricevuti dati e massimo, disegna la mappa nel canvas
let setTrsp: number = 1 - (document.getElementById("TrasparencySlider").value / 100);
//let setTrsp: number = 1-(parseInt($("#TrasparencySlider").attr("value"))/100);
//scorro tutti i pixel: ne determino il colore e li disegno
let color: string = "";
for (let i: number = pixel1.xp; i <= pixel2.xp; i++) {
for (let j: number = pixel1.yp; j <= pixel2.yp; j++) {
let 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 + ")";
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);
}
}
rePrint = false; //annullo rePrint
zoomRect();
}
$("#SaturationSlider").mouseup(function ()
{ //Slider della saturazione
drawImg(pixel1, pixel2, xMinRange, xMaxRange);
});
$("#rePlot").click(function ()
{ //bottone per colorare con il max relativo
rePrint = true;
(<HTMLInputElement>document.getElementById("SaturationSlider")).value = "100";
drawImg(pixel1, pixel2, xMinRange, xMaxRange);
});
$("#TrasparencySlider").mouseup(function ()
{ //Slider della trasparenza
drawImg(pixel1, pixel2, xMinRange, xMaxRange);
});
$("#reset").click(function ()
{ //bottone per il reset dell'applicazione
newOrigin = { xp: 0, yp: 0 };
rePrint = false;
calibrated = false;
globalxMinRange = 0;
(<HTMLInputElement>document.getElementById("SaturationSlider")).value = "100";
(<HTMLInputElement>document.getElementById("TrasparencySlider")).value = "0";
document.getElementById("spinBoxMin").setAttribute("value", "-");
document.getElementById("spinBoxMax").setAttribute("value", "-");
drawImg({ xp: 0, yp: 0 }, { xp: xDim - 1, yp: yDim - 1 }, 0, channelDepth);
drawChart({ xp: 0, yp: 0 }, { xp: xDim - 1, yp: yDim - 1 }, 0, channelDepth);
$("#ExportImage").click(function ()
{ //esportazione immagine
let img = (<HTMLCanvasElement>document.getElementById("myCanvas")).toDataURL("image/png");
$("#ExportLink").attr("href", img);
//document.write('<img src="'+img+'"/>');
});
}
//la funzione drawChart (input: estremi dell'immagine, estremi dell'intervallo)
//disegna il grafico richiesto relativo alla mappa visualizzata
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
let g: any;
let box1 = <HTMLElement>document.getElementById("spinBoxMin");
let box2 = <HTMLElement>document.getElementById("spinBoxMax");
if (pixel1.xp == 0 && pixel1.yp == 0 && pixel2.xp == xDim - 1 && pixel2.yp == yDim - 1) {
if (!calibrated) { //canali
let chartTitle: string = "Chart from (0, 0) to (" + (xDim - 1) + ", " + (yDim - 1) + ")";
g = setChart(dataCompleteChart, chartTitle);
} else { //energie
let chartTitle: string = "Calibrated chart from (0, 0) to (" + (xDim - 1) + ", " + (yDim - 1) + ")";
g = setChart(dataCompleteChartCalibrated, chartTitle);
}
} else {
//determino i conteggi dei pixel da disegnare
let dataForChart: number[] = new Array(depth);
for (let i: number = 0; i < depth; i++) {
for (let i: number = pixel1.xp; i <= pixel2.xp; i++) {
for (let j: number = pixel1.yp; j <= pixel2.yp; j++) {
for (let k: number = 0; k < depth; k++) {
dataForChart[k] += DataMatrix[i][j][k];
}
}
}
if (!calibrated) { //disegno in canali
let dataChart: string = "Channel,Counts\n";
for (let i: number = 0; i < depth; i++) {
if (pixel1.xp == pixel2.xp && pixel1.yp == pixel2.yp) {
let chartTitle: string = "Chart pixel (" + pixel1.xp + ", " + (yDim - pixel1.yp - 1) + ")";
let chartTitle: string = "Chart from (" + pixel1.xp + "," + pixel2.xp + ") to (" +
(yDim - pixel1.yp - 1) + ", " + (yDim - pixel2.yp - 1) + ")";
}
g = setChart(dataChart, chartTitle);
} else { //disegno in energie
let dataChartCalibrated: string = "Energy,Counts\n";
for (let i: number = 0; i < depth; i++) {
dataChartCalibrated += round3(((i + 1) * a - b) / 1000) + "," + dataForChart[i] + "\n";
if (pixel1.xp == pixel2.xp && pixel1.yp == pixel2.yp) {
let chartTitle: string = "Calibrated chart pixel (" + pixel1.xp + ", " + (yDim - pixel1.yp - 1) + ")";
let chartTitle: string = "Calibrated chart from (" + pixel1.xp + ", " + pixel2.xp +
") to (" + (yDim - pixel1.yp - 1) + ", " + (yDim - pixel2.yp - 1) + ")";
$('#setlinearButton').on('click', function ()
{ //selezione scala lineare
g.updateOptions({ logscale: false });
$('#setlogButton').on('click', function ()
{ //selezione scala logaritmica
g.updateOptions({ logscale: true });
$('#setEnergyButton').on('click', function ()
{ //selezione energie
$('#setChannelsButton').on('click', function ()
{ //selezione canali
box1.setAttribute("value", "-");
box2.setAttribute("value", "-");
});
$('#ExportGraph').on('click', function ()
{ //esportazione grafico
let img = <HTMLImageElement>document.getElementById("chartToImg");
$("#ExportGraph").attr("href", img.src.replace('image/png', 'image/octet-stream'));
$('#readSpinbox').on('click', function ()
{ //esportazione grafico
$('#chart').on('click', function ()
{ //zoom manuale sul grafico
let r: number[];
if (!calibrated) {
r[0] = Math.floor((((r[0] + 1) * a) - b) / 1000);
r[1] = Math.floor((((r[1] + 1) * a) - b) / 1000);
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]);
});
$('#elementSelect').on('change', function ()
{ //selezione elemento
let element: string = (<HTMLInputElement>document.getElementById("elementSelect")).value;
switch (element) {
case "1": //Ca
peackSelection(3.6, 3.8);
box1.setAttribute("value", "3.60");
box2.setAttribute("value", "3.80");
break;
case "2": //Pb
peackSelection(10.4, 10.7);
box1.setAttribute("value", "10.40");
box2.setAttribute("value", "10.70");
case "3": //Hg
peackSelection(9.8, 10.15);
box1.setAttribute("value", "9.80");
box2.setAttribute("value", "10.15");
case "4": //Fe
peackSelection(6.3, 6.5);
box1.setAttribute("value", "6.30");
box2.setAttribute("value", "6.50");
case "5": //Cu
peackSelection(7.85, 8.2);
box1.setAttribute("value", "7.85");
box2.setAttribute("value", "8.20");
case "6": //Zn
peackSelection(8.5, 8.72);
box1.setAttribute("value", "8.50");
break;
case "7": //Ti
peackSelection(4.35, 4.65);
box1.setAttribute("value", "4.35");
box2.setAttribute("value", "4.65");
break;
case "8": //K
peackSelection(3.2, 3.42);
box1.setAttribute("value", "3.20");
box2.setAttribute("value", "3.42");
case "9": //Co
peackSelection(6.8, 7.05);
box1.setAttribute("value", "6.80");
box2.setAttribute("value", "7.05");
break;
default:
break;
}
});
//la funzione setChart riceve in input i dati e il titolo del grafico da disegnare
//il quale è restituito il output
function setChart(dataString: string, charTitle: string)
{
let xArrayRange: number[]; //estremi asse x da visualizzare
let xLab: string;
if (!calibrated) {
xArrayRange = [xMinRange, xMaxRange];
xLab = "Energy (keV)";
}
//dimensioni grafico
let chartDim: any = document.querySelector('#chart-pannel').getBoundingClientRect();
let chartWidth = chartDim.right - chartDim.left - 50;
$('#chart').css('width', chartWidth);
$('#chart').css('height', "400");
let 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
});
return graphs;
}
//la funzione, dati gli estremi dell'intervallo da rappresentare, aggiorna mappa e grafico
function peackSelection(xMinRange: number, xMaxRange: number)
{
//se l'intervallo è [0, 0] devo leggere dalle i valori dalle spinbox
xMinRange = parseInt((<HTMLInputElement>box1).value);
xMaxRange = parseInt((<HTMLInputElement>box2).value);
}
globalxMinRange = xMinRange;
globalxMaxRange = xMaxRange;
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);