import { FITSHeaderTable, LicensePanel } from "./modules/page_overlay.js";
import { CoordinatesFormatter } from "./modules/utils.js";
import { InfosBlock } from "./modules/olqv_infosblock.js";
import { Settings } from "./modules/olqv_settings.js";
import { MarkersFactory, MarkerList } from "./modules/olqv_markers.js";
import { ContoursFactory, ContoursFactoryGUI } from "./modules/olqv_contours.js";
import { BoxesFactory } from "./modules/olqv_boxes.js";
import { Viewer } from "./modules/olqv_viewer.js";
import { KeyCodeProcessor } from "./modules/olqv_keyboardevents.js";
import { getProjection } from "./modules/olqv_projections.js";
import { CustomControls } from "./modules/olqv_customcontrols.js";
import { FITS_HEADER } from "./modules/fitsheader.js";
import { AxesFactory } from "./modules/olqv_axes.js";
import { sAMPPublisher,setOnHubAvailabilityButtons } from "./modules/samp_utils.js";
import { PublishSAMPButton, ResetButton, DeleteButton } from "./modules/olqv_olbuttons.js";
import { withSAMP, dataPaths, testMode, default_lut_index} from './modules/init.js';
import { DOMAccessor } from "./modules/domelements.js";
import { LastClickMarkerNoChannel } from "./modules/lastclickmarker.js";
import { ServerApi } from "./modules/serverApi.js";
import {setNedUiListeners } from "./modules/listeners.js";
import {Tester} from "./tests/test2d.js";
import { SourceTable } from "./modules/olqv_ned.js";
import { SpectroscopyUI } from "./modules/olqv_spectro.js";
/**
* Returns an event signaling that a slice has been modified
* data packed inside the event are used in testing context
* @param {object} data spectrum data
* @returns Event
*/
function get2DImageLoadedEvent(meta){
let event = new Event("2d");
event.rmsValue = meta.rmsVal;
event.rmsUnit = meta.rmsUnit;
event.xRef = Math.round(FITS_HEADER.naxis1 / 2);
event.yRef = Math.round(FITS_HEADER.naxis2 / 2);
event.boxExtent = getInitialBoxCoordinates();
event.minValue = meta.minValue;
event.maxValue = meta.maxValue;
return event;
}
/**
* Returns the coordinates of a box automatically displayed
* when a 2D cube is opened
* @returns array
*/
function getInitialBoxCoordinates() {
const naxis1Index = FITS_HEADER.naxis1 -1;
const naxis2Index = FITS_HEADER.naxis2 -1;
const iRA0 = Math.round(naxis1Index / 2 - naxis1Index / 16);
const iRA1 = Math.round(naxis1Index / 2 + naxis1Index / 16);
const iDEC0 = Math.round(naxis2Index / 2 - naxis2Index / 16);
const iDEC1 = Math.round(naxis2Index / 2 + naxis2Index / 16);
return [iRA0, iRA1, iDEC0, iDEC1];
}
/**
* Triggers the test procedure
* @param {object} statistics some statistics related to the opened data cube
* @param {BoxesFactory} boxesFactory object to create a box on the cube image
*/
function triggerTest(statistics, boxesFactory){
let coords = getInitialBoxCoordinates();
let f = boxesFactory.addBox(coords[0], coords[1], coords[2], coords[3]);
//viewer.map.addFeature(feature);
let meta = {"rmsVal": statistics.stdev, "rmsUnit": FITS_HEADER.bunit, "minValue": statistics.min, "maxValue": statistics.max};
let tester = new Tester();
tester.imageLoaded( get2DImageLoadedEvent(meta));
}
var enter = function(what) {
console.group(what);
}
var exit = function() {
console.groupEnd();
}
//
// This section determines the projection that will be used to calculate the physical coordinates.
//
//var projection; // This variable will contain the appropriate instance of a class derived of Projection.
//
// Projections are deduced from the three last non blank letters of CTYPEn keywords in the FITS header
//
try{
var projection = getProjection(FITS_HEADER.projectionType);
}catch(e){
alert(e);
}
let projCode1 = FITS_HEADER.ctype1.trim().slice(-3); // FITS_HEADER_DIRECT["CTYPE1"].trim().slice(-3);
let projCode2 = FITS_HEADER.ctype2.trim().slice(-3); //FITS_HEADER_DIRECT["CTYPE2"].trim().slice(-3);
let optionsMenuDisplay = "none";
if (projCode1 != projCode2) {
alert(`Don't know how to proceed with two different projections : ${projCode1} , ${projCode1}`);
throw new Error(`Don't know how to proceed with two different projections : ${projCode1} , ${projCode1}`);
}
// This is the (hidden) canvas where the images are actually drawn.
var hiddenCanvas = document.getElementById("hiddenSlice");
var displaySlice = function(relFITSFilePath, sliceIndex, viewer, contourer, sAMPPublisher) {
enter(displaySlice.name);
const lutConf = DOMAccessor.getConfiguration();
let lutName = lutConf.lutName;
let ittName = lutConf.ittName;
let vmName = lutConf.vmName;
DOMAccessor.showLoaderAction(true);
$.post('png', { 'si': sliceIndex, 'relFITSFilePath': relFITSFilePath, 'ittName': ittName, 'lutName': lutName, 'vmName': vmName }).done(
function(resp) {
console.group("$.post('/png', {'si': _sliceIndex, 'relFITSFilePath': _relFITSFilePath})");
DOMAccessor.showLoaderAction(false);
if (resp["status"] == false) {
alert("Something went wrong during the generation of the image. The message was '" + resp["message"] + "'");
} else {
let dataSteps = resp["result"]["data_steps"];
let statistics = resp["result"]["statistics"];
let path_to_png = resp["result"]["path_to_png"];
let path_to_legend_png = resp["result"]["path_to_legend_png"];
let imageURL = `${ctxt["urlRoot"]}/${path_to_png}`;
let colorBarURL = `${ctxt["urlRoot"]}/${path_to_legend_png}`;
console.log("Image's URL is " + imageURL);
DOMAccessor.updateSingleSliceColorBar(colorBarURL);
viewer.display(imageURL, sliceIndex, dataSteps, statistics);
// executes the test procedure if testMode is activated
if(testMode)
triggerTest(statistics, new BoxesFactory(viewer));
if (sAMPPublisher && typeof sAMPPublisher === "object") {
// This is a poor test to ensure that it's maybe a function
dataPaths.relSlicePNG= path_to_png;
}
if (contourer) {
contourer.setDefaultValue([statistics["mean"] + statistics["stdev"]]);
}
}
DOMAccessor.showLoaderAction(false);
DOMAccessor.markLoadingDone();
console.groupEnd();
});
exit();
};
// The header is a template parameter.
var header = ctxt["header"];
// The complete URL of the present page is built upon two template parameters
var urlRoot = ctxt["urlRoot"];
var originalURL = ctxt["originalURL"];
var url = `${urlRoot}${originalURL}`;
var viewer;
// list of sources downloaded from NED catalog
let sourceTable;
// get user input from spectroscopy form
let spectroUI = new SpectroscopyUI();
//let markerList = new MarkerList("input-markers", "show-markers", "clear-markers");
//ned data selection
sourceTable = new SourceTable('ned-data', 'ned-modal-title', spectroUI);
//sourceTable.addListener(markerList);
setNedUiListeners(sourceTable, spectroUI);
$(document).ready(function() {
enter("What to do when document is ready");
DOMAccessor.selectLut(default_lut_index);
$('[data-tooltip="tooltip"]').tooltip();
var FITSHDR = new FITSHeaderTable(document.getElementById("FITSHDR"), header);
$('#show-fits-header').click(function() {
FITSHDR.show()
});
$("#spectrum-info-title").html(FITS_HEADER.getSpectrumTitle());
$('#show-license').click(function() {
let Licences = new LicensePanel(document.getElementById("licences"));
Licences.show()
});
$("#toggle-options").on("click", function(event) {
if(optionsMenuDisplay ==="block" ){
optionsMenuDisplay = "none";
document.getElementById("img-canvas").classList.replace("col-9", "col-12");
event.currentTarget.textContent = "<<<";
}else{
optionsMenuDisplay = "block";
document.getElementById("img-canvas").classList.replace("col-12", "col-9");
event.currentTarget.textContent = ">>>";
}
Array.from(document.getElementsByClassName("last-col")).forEach(function(element){
element.style.display = optionsMenuDisplay;
});
// update size of image in viewport. If not called, it is simply stretched and coordinates are messed up.
viewer.map.updateSize();
});
DOMAccessor.showLoaderAction(true);
let serverApi = new ServerApi();
serverApi.getRADECRangeInDegrees(dataPaths.relFITSFilePath, (resp)=>{
$("#cube-infos").html(FITS_HEADER.getFitsSummary(true));
//let RADECRangeInDegrees = resp.data["result"];
/*
var naxis3 = 1;
if (naxis > 2) {
naxis3 = FITS_HEADER.naxis3;
}
var naxis4 = 1;
if (naxis > 4) {
naxis4 = FITS_HEADER.naxis4;
}*/
/* Keep things square */
if (width > height) {
height = width;
} else if (width < height) {
width = height;
}
var naxis = FITS_HEADER.naxis;
var naxis1 = FITS_HEADER.naxis1;
var naxis2 = FITS_HEADER.naxis2;
// Let's keep things square
var width = Math.max(naxis1, naxis2);
var height = width;
// Please note that cdelt is expected to contain values in degree unit !!!
var coordinatesFormatter = new CoordinatesFormatter(hiddenCanvas, FITS_HEADER.bunit, projection);
//var infosLine = document.getElementById("infos-line");
var context = {
'file': dataPaths.relFITSFilePath,
'url': url,
'pixel-slice-range': 0,
'slice-phys-chars': {
'type': FITS_HEADER.ctype3,
'unit': FITS_HEADER.cunit3,
'value': FITS_HEADER.crval3
},
'array-phys-chars': { 'type': FITS_HEADER.btype, 'unit': FITS_HEADER.bunit }
};
var infosBlock = new InfosBlock(document.getElementById("infos-line"),
document.getElementsByTagName("body")[0], context);
viewer = new Viewer(dataPaths.relFITSFilePath, width, height, "slice",
"hiddenSlice", coordinatesFormatter, infosBlock);
let lastClickMarker = new LastClickMarkerNoChannel(viewer.map, "popup-single");
// displays value at clicked pixel on canvas
viewer.addClickEvent((event)=>{
// do request if click is in canvas ( not in left menu ) and no interaction enabled
//show flux value at clicked position
function processResult(data){
// show click marker if value exists
if(data.result !== null){
const x = Math.round(event.coordinate[0]);
const y = Math.round(event.coordinate[1]);
const raDec = coordinatesFormatter.getRaDec(x, y);
if(x >= 0 && y >= 0){
lastClickMarker.setPositions(x, y, raDec['ra'], raDec['dec']);
lastClickMarker.setFluxDensity(data.result.value, data.result.unit);
lastClickMarker.updateLastClickInfos();
}
}
}
if( event.originalEvent.target.localName == "canvas" && !viewer.hasCurrentInteraction()){
if(FITS_HEADER.naxis == 2){
serverApi.getPixelValue(dataPaths.relFITSFilePath,
Math.round(event.coordinate[0]),
Math.round(event.coordinate[1]),
processResult);
}else if(FITS_HEADER.naxis >= 3){
serverApi.getPixelFreqValue(dataPaths.relFITSFilePath,
Math.round(event.coordinate[0]),
Math.round(event.coordinate[1]),
0,
processResult);
}else{
alert("Incorrect number of axis : " + FITS_HEADER.naxis);
}
}
});
var keyCodeProcessor = new KeyCodeProcessor(viewer);
keyCodeProcessor.open();
// buttons in side bar
var customControls = new CustomControls(viewer);
/*var settings = new Settings(viewer, infosBlock);
ctxt["luts"].forEach(lut => settings.appendLUT(lut));
settings.setLUTSelectorIndex(ctxt["default_lut_index"]);
ctxt["itts"].forEach(itt => settings.appendITT(itt));
settings.setITTSelectorIndex(ctxt["default_itt_index"]);
ctxt["vmodes"].forEach(vmode => settings.appendVM(vmode));
settings.setVideoModeSelectorIndex(ctxt["default_vmode_index"]);
customControls.addButton(settings.getButton());
keyCodeProcessor.teach("V", () => settings.getButton().click());
keyCodeProcessor.teach("v", () => settings.getButton().click());*/
var selector = viewer.getSelector();
customControls.addButton(selector.getButtonObject().getButton());
for(let key of selector.getButtonObject().getKeyboardMapping()){
keyCodeProcessor.teach(key, () => selector.getButtonObject().getButton().click());
}
var markersFactory = new MarkersFactory(viewer);
let nedListener = {
// a source has been selected in NED
sourceTableCall(event){
markersFactory.addMarkers([{"RAInDD": event.detail.ra,
"DECInDD":event.detail.dec,
"label": event.detail.object}]);
markersFactory.source.refresh();
if(!markersFactory.isOpened){
markersFactory.button.click();
}
}
}
sourceTable.addListener(nedListener);
customControls.addButton(markersFactory.getButtonObject().getButton());
for(let key of markersFactory.getButtonObject().getKeyboardMapping()){
keyCodeProcessor.teach(key, () => markersFactory.getButtonObject().getButton().click());
}
var contoursFactory = new ContoursFactory(viewer /*, infosBlock*/ );
customControls.addButton(contoursFactory.getButtonObject().getButton());
//contoursFactory.getButtonObject().setClickAction(()=>{contoursFactory.getButtonClick()});
for(let key of contoursFactory.getButtonObject().getKeyboardMapping()){
keyCodeProcessor.teach(key, () => contoursFactory.getButtonObject().getButton().click());
}
var contoursFactoryGUI = new ContoursFactoryGUI(viewer, dataPaths.relFITSFilePath);
contoursFactoryGUI.connect(contoursFactory);
var boxesFactory = new BoxesFactory(viewer, infosBlock);
customControls.addButton(boxesFactory.getButtonObject().getButton());
for(let key of boxesFactory.getButtonObject().getKeyboardMapping()){
keyCodeProcessor.teach(key, () => boxesFactory.getButtonObject().getButton().click());
}
if (withSAMP) {
var publishSAMP = new PublishSAMPButton(this.viewer);
publishSAMP.setClickAction(()=>{
sAMPPublisher.sendPNGSlice();
sAMPPublisher.sendMarkers(markersFactory.getMarkersList());
});
setOnHubAvailabilityButtons(DOMAccessor.get2DSampConnection(),customControls,publishSAMP);
}
// Pressing x|X => remove the selected feature.
let deleteButton = new DeleteButton(this.viewer);
for(let key of deleteButton.getKeyboardMapping()){
keyCodeProcessor.teach(key, () => { if (selector.isOpened()) selector.removeSelection() });
}
let axesFactory = new AxesFactory(viewer, FITS_HEADER.projectionType);
axesFactory.build();
axesFactory.getButtonObject().setClickAction(()=>{axesFactory.getButtonClick()});
customControls.addButton(axesFactory.getButtonObject().getButton());
for(let key of axesFactory.getButtonObject().getKeyboardMapping()){
keyCodeProcessor.teach(key, () => axesFactory.getButtonObject().getButton().click());
}
let reset = new ResetButton(this.viewer);
reset.setClickAction(()=>{viewer.reset()});
customControls.addButton(reset.getButton());
for(let key of reset.getKeyboardMapping()){
keyCodeProcessor.teach(key, () => reset.getButton().click());
}
selector.getButtonObject().getButton().click()
displaySlice(dataPaths.relFITSFilePath, 0, viewer, contoursFactoryGUI, sAMPPublisher);
$('#rccap').click(function() {
displaySlice(dataPaths.relFITSFilePath, 0, viewer, contoursFactoryGUI, sAMPPublisher);
});
exit;
});
exit();
});