Index: /trunk/FACT++/www/viewer/index.js
===================================================================
--- /trunk/FACT++/www/viewer/index.js	(revision 17771)
+++ /trunk/FACT++/www/viewer/index.js	(revision 17772)
@@ -1,3 +1,38 @@
 'use strict';
+
+// ==========================================================================
+
+function onRightMouseClick(event)
+{
+    if (event.button!=2)
+        return;
+
+    var strData = event.target.toDataURL("image/png");
+
+    var img = document.createElement("img");
+    img.src = strData;
+
+    $(img).css({ "z-index": "9999", "position": "absolute" });
+    $(img).insertBefore($(event.target));
+
+    setTimeout(function () { $(img).remove(); }, 100);
+}
+
+(function ($)
+ {
+
+    $.plot.plugins.push({
+        init: function(plot, classes)
+            {
+                plot.hooks.bindEvents.push(function(plot, eventHolder) { eventHolder.mousedown(onRightMouseClick); });
+                plot.hooks.shutdown.push(function(plot, eventHolder) { eventHolder.unbind("mousedown", onRightMouseClick); });
+            },
+        name: 'saveAsImage',
+        version: '1.0'
+    });
+
+ })(jQuery);
+
+// ==========================================================================
 
 var editor1;
@@ -49,12 +84,24 @@
 }
 
-function onResizeCenter(event, ui)
-{
-    var w = document.getElementById("cameracontainer").clientWidth/4;
+function setSize(id, w, h)
+{
+    w = parseInt(w);
+    h = parseInt(h);
+
+    $("#"+id).width(w);
+    $("#"+id).height(h);
+
+    document.getElementById(id).width=w;
+    document.getElementById(id).height=h;
+}
+
+function onResizeGrid(id)
+{
+    var w = document.getElementById(id+"container").clientWidth/4;
 
     var offy = 0;
     var offx = 5;
 
-    var cont = document.getElementById("center").childNodes[0];
+    var cont = document.getElementById("center"+id).childNodes[0];
 
     var nn;
@@ -62,44 +109,27 @@
     {
         nn = parseInt(cont.id[cont.id.length-1]);
-
-        document.getElementById("camera"+nn).height=parseInt(w*2);
-        document.getElementById("camera"+nn).width=parseInt(w*2);
+        setSize(id+nn, w*2, w*2);
     }
 
     if (nn!=1)
-    {
-        document.getElementById("camera1").height=parseInt(w)-offy;
-        document.getElementById("camera1").width=parseInt(w)-offx;
-    }
-
+        setSize(id+'1', w-offx, w-offy);
     if (nn!=2)
-    {
-        document.getElementById("camera2").height=parseInt(w)-offy;
-        document.getElementById("camera2").width=parseInt(w)-offx;
-    }
-
+        setSize(id+'2', w-offx, w-offy);
     if (nn!=3)
-    {
-        document.getElementById("camera3").height=parseInt(w)-offy;
-        document.getElementById("camera3").width=parseInt(w)-offx;
-    }
-
+        setSize(id+'3', w-offx, w-offy);
     if (nn!=4)
-    {
-        document.getElementById("camera4").height=parseInt(w)-offy;
-        document.getElementById("camera4").width=parseInt(w)-offx;
-    }
-
-    document.getElementById("center").width=parseInt(w*2);
-
-    document.getElementById("cont1").width=parseInt(w);
-    document.getElementById("cont2").width=parseInt(w);
-    document.getElementById("cont3").width=parseInt(w);
-    document.getElementById("cont4").width=parseInt(w);
-
-    document.getElementById("cont1").height=parseInt(w);
-    document.getElementById("cont2").height=parseInt(w);
-    document.getElementById("cont3").height=parseInt(w);
-    document.getElementById("cont4").height=parseInt(w);
+        setSize(id+'4', w-offx, w-offy);
+
+    document.getElementById("center"+id).width=parseInt(w*2);
+
+    setSize('cont'+id+'1', w, w);
+    setSize('cont'+id+'2', w, w);
+    setSize('cont'+id+'3', w, w);
+    setSize('cont'+id+'4', w, w);
+}
+
+function onResizeCameras(event, ui)
+{
+    onResizeGrid('camera');
 
     drawFullCam("camera1");
@@ -107,4 +137,9 @@
     drawFullCam("camera3");
     drawFullCam("camera4");
+}
+
+function onResizeHistograms(event, ui)
+{
+    onResizeGrid('hist');
 }
 
@@ -182,4 +217,16 @@
     $('#cbpx-x').prop('disabled', disabled);
     $('#file').prop('disabled', disabled);
+
+    if (disabled)
+        $('#calibrated').prop('disabled', true);
+    else
+    {
+        var list = document.getElementById("file").data;
+        if (list)
+        {
+            var file = document.getElementById("file").value;
+            $('#calibrated').prop('disabled', !list[file]);
+        }
+    }
 }
 
@@ -228,11 +275,19 @@
     $("#textcontainer2").on("resize", onResize);
 
-    $("#cameracontainer").on("resize", onResizeCenter);
-    onResizeCenter();
-
-    $("#cont1").click(onClickNew);
-    $("#cont2").click(onClickNew);
-    $("#cont3").click(onClickNew);
-    $("#cont4").click(onClickNew);
+    $("#cameracontainer").on("resize", onResizeCameras);
+    onResizeCameras();
+
+    $("#histcontainer").on("resize", onResizeHistograms);
+    onResizeHistograms();
+
+    $("#contcamera1").click(onClickContCamera);
+    $("#contcamera2").click(onClickContCamera);
+    $("#contcamera3").click(onClickContCamera);
+    $("#contcamera4").click(onClickContCamera);
+
+    $("#conthist1").click(onClickContHist);
+    $("#conthist2").click(onClickContHist);
+    $("#conthist3").click(onClickContHist);
+    $("#conthist4").click(onClickContHist);
 
     $("#camera1").click(onClick);
@@ -241,4 +296,9 @@
     $("#camera4").click(onClick);
 
+    $('#camera1').mousedown(onRightMouseClick);
+    $('#camera2').mousedown(onRightMouseClick);
+    $('#camera3').mousedown(onRightMouseClick);
+    $('#camera4').mousedown(onRightMouseClick);
+
     editor1 = createEditor("editor1");
     editor2 = createEditor("editor2");
@@ -251,4 +311,5 @@
 
     setupAccordion('#accordion2', '#cameracontainer');
+    setupAccordion('#accordion7', '#histcontainer');
     setupAccordion('#accordion3', '#waveformcontainer');
     setupAccordion('#accordion4', '#helpcontainer', true);
@@ -272,4 +333,11 @@
 function onFileSelect(event, ui)
 {
+    var list = document.getElementById("file").data;
+    var file = ui.item.value;
+
+    $('#calibrated').prop('disabled', !list[file]);
+    if (!list[file])
+        $('#calibrated').prop('checked', false);
+
     document.getElementById("event").value = 0;
     onSubmit(ui.item.value);
@@ -295,7 +363,13 @@
     }
 
+    document.getElementById("file").data = rc;
+
+    var list = [ ];
+    for (var file in rc)
+        list.push(file);
+
     var opts =
     {
-        source: rc,
+        source: list,
         select: onFileSelect,
         position: { my: "right top", at: "right bottom", collision: "flipfit" },
@@ -328,7 +402,63 @@
 }
 
-function processCameraData(id, data)
-{
-    var canv = document.getElementById(id);
+function drawHist(n)
+{
+    var canv = document.getElementById("camera"+n);
+    var hist = document.getElementById("hist"+n);
+
+    var xmin  = parseFloat(document.getElementById("histmin"+n).value);
+    var xmax  = parseFloat(document.getElementById("histmax"+n).value);
+    var nbins = 100;//parseInt(xmax-xmin);
+    var step  = (xmax-xmin)/nbins;
+    if (step<1)
+    {
+        step = 1;
+        nbins = parseInt(xmax-xmin)+1;
+    }
+
+    var bins = new Array(nbins);
+    for (var i=0; i<nbins; i++)
+        bins[i] = [ xmin+i*step, 0 ];
+
+    var data = canv.dataAbs;
+    for (var i=0; i<1440; i++)
+        if (data[i]!==undefined && data[i]!==null)
+        {
+            var ix = parseInt((data[i]-xmin)/step);
+            if (ix>=0 && ix<nbins)
+                bins[ix][1] ++;
+        }
+
+    var opts =
+    {
+        grid: {
+            hoverable: true,
+        }
+    };
+
+    var hist = $.plot("#hist"+n, [ { data:bins, bars: {show:true} } ], opts);
+    $('#hist'+n).bind("plothover", function (event, pos, item)
+                      {
+                          if (!item)
+                          {
+                              $("#tooltip").fadeOut(100);
+                              return;
+                          }
+
+                          var x = item.datapoint[0].toFixed(2);
+                          var y = item.datapoint[1].toFixed(2);
+
+                          var tooltip = $("#tooltip");
+                          tooltip.html(parseInt(x) + " / " + y);
+                          tooltip.css({top: item.pageY-20, left: item.pageX+5});
+                          tooltip.fadeIn(200);
+                      });
+
+
+}
+
+function processCameraData(n, data)
+{
+    var canv = document.getElementById("camera"+n);
 
     canv.dataAbs = new Array(1440);
@@ -345,10 +475,22 @@
             canv.dataRel[i] = (data[i]-canv.min)/canv.max;
 
-    var n = id[id.length-1];
-
     if (document.getElementById("cameraminon"+n).checked)
         document.getElementById("cameramin"+n).value = canv.min;
     if (document.getElementById("cameramaxon"+n).checked)
         document.getElementById("cameramax"+n).value = canv.max;
+
+    // ---------------------------
+
+    var hist = document.getElementById("hist"+n);
+
+    hist.min = canv.min;
+    hist.max = canv.max;
+
+    if (document.getElementById("histminon"+n).checked)
+        document.getElementById("histmin"+n).value = canv.min;
+    if (document.getElementById("histmaxon"+n).checked)
+        document.getElementById("histmax"+n).value = canv.max;
+
+    drawHist(n);
 }
 
@@ -419,6 +561,4 @@
     }
 
-    var canv = document.getElementById("camera1");
-
     if (rc.debug!==undefined)
     {
@@ -434,16 +574,16 @@
     {
         if (rc.ret[0] instanceof Object)
-            processCameraData("camera1", rc.ret[0]);
+            processCameraData(1, rc.ret[0]);
         else
-            processCameraData("camera1", rc.ret);
+            processCameraData(1, rc.ret);
 
         if (rc.ret.length>1)
-            processCameraData("camera2", rc.ret[1]);
+            processCameraData(2, rc.ret[1]);
 
         if (rc.ret.length>2)
-            processCameraData("camera3", rc.ret[2]);
+            processCameraData(3, rc.ret[2]);
 
         if (rc.ret.length>3)
-            processCameraData("camera4", rc.ret[3]);
+            processCameraData(4, rc.ret[3]);
     }
 
@@ -454,7 +594,4 @@
     onCameraMinMax(4);
 
-    //if (canv.dataAbs && evt)
-    //    document.getElementById("value").value = canv.dataAbs[evt.pixel];
-
     debug("Total time = "+(rc.timePhp*1000).toFixed(1)+" ms");
     debug("Peak memory = "+rc.memory+" MiB");
@@ -466,8 +603,8 @@
 
         var data = [
-                    new Array(evt.numRoi),
-                    new Array(evt.numRoi),
-                    new Array(evt.numRoi),
-                    new Array(evt.numRoi)
+                    { label: "[0] ", data: new Array(evt.numRoi) },
+                    { label: "[1] ", data: new Array(evt.numRoi) },
+                    { label: "[2] ", data: new Array(evt.numRoi) },
+                    { label: "[3] ", data: new Array(evt.numRoi) },
                     ];
 
@@ -479,6 +616,7 @@
             max.push(Math.max.apply(Math, rc.waveform));
 
+            var d = data[0].data;
             for (var i=0; i<evt.numRoi; i++)
-                data[0][i] = [ i, rc.waveform[i] ];
+                d[i] = [ i, rc.waveform[i] ];
 
             waveform.data[0] = rc.waveform;
@@ -494,6 +632,7 @@
                 max.push(Math.max.apply(Math, ref));
 
+                var d = data[j].data;
                 for (var i=0; i<evt.numRoi; i++)
-                    data[j][i] = [ i, ref[i] ];
+                    d[i] = [ i, ref[i] ];
 
                 waveform.data[j] = ref;
@@ -573,8 +712,7 @@
                           var x = item.datapoint[0].toFixed(2);
                           var y = item.datapoint[1].toFixed(2);
-                          //item.series.label
 
                           var tooltip = $("#tooltip");
-                          tooltip.html(parseInt(x) + " / " + y);
+                          tooltip.html(parseInt(x) + " / " + y+"  "+item.series.label);
                           tooltip.css({top: item.pageY-20, left: item.pageX+5});
                           tooltip.fadeIn(200);
@@ -582,5 +720,4 @@
     }
 
-    //$("#accordion").accordion("refresh");
 }
 
@@ -601,4 +738,6 @@
     }
 
+    var calibrated = document.getElementById("calibrated");
+    var calib   = !calibrated.disabled && calibrated.checked;
     var event   = document.getElementById("event").value;
     var pixel   = document.getElementById("pixel").value;
@@ -610,4 +749,6 @@
     if (!pixelOnly)
         uri += "&source2="+encodeURIComponent(source2);
+    if (calib)
+        uri += "&calibrated=1";
 
     $.ajax({
@@ -661,6 +802,34 @@
 }
 
+function checkPixel()
+{
+    var pix  = parseInt(document.getElementById("pixel").value);
+    var c    = parseInt(document.getElementById("cbpx-c").value);
+    var b    = parseInt(document.getElementById("cbpx-b").value);
+    var p    = parseInt(document.getElementById("cbpx-p").value);
+    var x    = parseInt(document.getElementById("cbpx-x").value);
+    var cbpx = parseInt(document.getElementById("cbpx").value);;
+
+    if (pix >=0 && pix <1440 &&
+        c   >=0 && c   <   4 &&
+        b   >=0 && b   <  10 &&
+        p   >=0 && p   <   4 &&
+        x   >=0 && x   <   9 &&
+        cbpx>=0 && cbpx<1440)
+        return;
+
+    document.getElementById("pixel").value = 0;
+    document.getElementById("cbpx-c").value = 1;
+    document.getElementById("cbpx-b").value = 0;
+    document.getElementById("cbpx-p").value = 3;
+    document.getElementById("cbpx-x").value = 6;
+    document.getElementById("cbpx").value = 393;
+}
+
+
 function onPixel()
 {
+    checkPixel();
+
     var p = parseInt(document.getElementById("pixel").value);
 
@@ -678,4 +847,6 @@
 function onCBPX()
 {
+    checkPixel();
+
     var c = parseInt(document.getElementById("cbpx-c").value);
     var b = parseInt(document.getElementById("cbpx-b").value);
@@ -693,4 +864,6 @@
 function onHW()
 {
+    checkPixel();
+
     var cbpx = parseInt(document.getElementById("cbpx").value);;
 
@@ -776,14 +949,14 @@
 }
 
-var inprogress = 0;
-function moveAnimate(n, target)
-{
-    if (inprogress==n || inprogress<0)
+var inprogress = { };
+function moveElement(id, n, target, callback)
+{
+    if (inprogress[id]==n || inprogress[id]<0)
         return;
 
-    inprogress = target ? -n : n;
-
-    var element   = $("#camera"+n); //Allow passing in either a JQuery object or selector
-    var newParent = $(target ? target : "#cont"+n); //Allow passing in either a JQuery object or selector
+    inprogress[id] = target ? -n : n;
+
+    var element   = $("#"+id+n); //Allow passing in either a JQuery object or selector
+    var newParent = $(target ? target : "#cont"+id+n); //Allow passing in either a JQuery object or selector
 
     var oldOffset = element.offset();
@@ -804,5 +977,5 @@
     {
         temp = temp.appendTo(newParent);
-        temp.css('position', 'default');
+        temp.css('position', 'relative');
         temp.css('width', 'default');
         temp.css('height', 'default');
@@ -810,38 +983,56 @@
         temp.css('top', '0');
 
-        var canv = document.getElementById("camera"+n);
-
-        canv.width = w;
-        canv.height = h;
-
-        drawFullCam("camera"+n);
-
-        inprogress = 0;
+        setSize(id+n, w, h);
+
+        if (callback)
+            callback(id+n);
+
+        inprogress[id] = 0;
     });
 }
 
-function onClickNew(event)
+function onClickCont(event, callback)
 {
     var id = event.target.id;
+    if (!id)
+        id = event.target.parentNode.id;
+
     var n = parseInt(id[id.length-1]);
-
-    if (id.substr(0, 3)=="cam")
-    {
-        var cont = document.getElementById("center").childNodes[0];
+    var type = id.substr(0, id.length-1);
+
+    if (id.substr(0, 4)=="cont")
+        id = id.substr(4, id.length-4);
+    if (type.substr(0, 4)=="cont")
+        type = type.substr(4, type.length-4);
+
+    if (id.substr(0, type.length)==type)
+    {
+        var cont = document.getElementById("center"+type).childNodes[0];
         if (cont)
         {
             var nn = parseInt(cont.id[cont.id.length-1]);
-            moveAnimate(nn);
+            moveElement(type, nn, null, callback);
         }
-        moveAnimate(n, "#center");
+        moveElement(type, n, "#center"+type, callback);
 
     }
     else
-        moveAnimate(n);
+        moveElement(type, n, null, callback);
+
+}
+
+function onClickContCamera(event)
+{
+    onClickCont(event, function(el) { drawFullCam(el); });
+}
+
+function onClickContHist(event)
+{
+    onClickCont(event);
 }
 
 function onClick(event)
 {
-    var cont = document.getElementById("center").childNodes[0];
+    var cont = document.getElementById("centercamera").childNodes[0];
     if (!cont)
         return;
@@ -878,39 +1069,60 @@
 }
 
+function onMinMax(id, n)
+{
+    var el = document.getElementById(id+n);
+
+    el.zmin = document.getElementById(id+"min"+n).value;
+    el.zmax = document.getElementById(id+"max"+n).value;
+}
+
 function onCameraMinMax(n)
 {
-    var canv = document.getElementById("camera"+n);
-
-    canv.zmin = document.getElementById("cameramin"+n).value;
-    canv.zmax = document.getElementById("cameramax"+n).value;
-
+    onMinMax("camera", n);
     drawFullCam("camera"+n);
 }
 
+function onHistMinMax(n)
+{
+    onMinMax("hist", n);
+    drawHist(n);
+}
+
+function onMinMaxOn(id, n)
+{
+    var el = document.getElementById(id+n);
+
+    var redraw;
+    if (document.getElementById(id+"minon"+n).checked)
+    {
+        document.getElementById(id+"min"+n).setAttribute("disabled", "true");
+        document.getElementById(id+"min"+n).value = el.min;
+        redraw = true;
+    }
+    else
+        document.getElementById(id+"min"+n).removeAttribute("disabled");
+
+    if (document.getElementById(id+"maxon"+n).checked)
+    {
+        document.getElementById(id+"max"+n).setAttribute("disabled", "true");
+        document.getElementById(id+"max"+n).value = el.max;
+        redraw = true;
+    }
+    else
+        document.getElementById(id+"max"+n).removeAttribute("disabled");
+
+    return redraw;
+}
+
 function onCameraMinMaxOn(n)
 {
-    var canv = document.getElementById("camera"+n);
-
-    var redraw;
-    if (document.getElementById("cameraminon"+n).checked)
-    {   
-        document.getElementById("cameramin"+n).setAttribute("disabled", "true");
-        document.getElementById("cameramin"+n).value = canv.min;
-        redraw = true;
-    }
-    else
-        document.getElementById("cameramin"+n).removeAttribute("disabled");
-
-    if (document.getElementById("cameramaxon"+n).checked)
-    {
-        document.getElementById("cameramax"+n).setAttribute("disabled", "true");
-        document.getElementById("cameramax"+n).value = canv.max;
-        redraw = true;
-    }
-    else
-        document.getElementById("cameramax"+n).removeAttribute("disabled");
-
-    if (redraw)
+    if (onMinMaxOn("camera", n))
         onCameraMinMax(n);
+}
+
+function onHistMinMaxOn(n)
+{
+    if (onMinMaxOn("hist", n))
+        onHistMinMax(n);
 }
 
@@ -1209,3 +1421,2 @@
     ctx.strokeText(lmin, 5+mw, 5);
 }
-
