/******************************************************************************
* Aladin Lite project
*
* File MOC
*
* This class represents a MOC (Multi Order Coverage map) layer
*
* Author: Thomas Boch[CDS], Matthieu Baumann[CDS]
*
*****************************************************************************/
import { Aladin } from "./Aladin.js";
import { Utils } from "./Utils";
import { Color } from "./Color.js";
import { ALEvent } from "./events/ALEvent.js";
/**
* @typedef {Object} MOCOptions
* @description Options for configuring a MOC (Multi-Order-Coverage).
*
* @property {string} [name="MOC"] - The name of the catalog.
* @property {string} [color] - The color of the MOC HEALPix cell edges.
* @property {string} [fillColor] - A filling color of the MOC HEALPix cells.
* @property {string} [fill=false] - Fill the MOC with `options.fillColor`
* @property {string} [edge=true] - Draw the edges of the HEALPix cells with `options.color`.
* @property {number} [lineWidth=3] - The line width in pixels
* @property {Boolean} [perimeter=false] - A filling color of the MOC HEALPix cells.
* @property {number} [opacity=1.0] - The opacity of the MOC
*/
export let MOC = (function() {
/**
* Represents a Multi-Order-Coverage with configurable options for display and interaction.
*
* @class
* @constructs MOC
* @param {MOCOptions} options - Configuration options for the MOC
*/
let MOC = function(options) {
//this.order = undefined;
this.uuid = Utils.uuidv4();
this.type = 'moc';
// TODO homogenize options parsing for all kind of overlay (footprints, catalog, MOC)
options = options || {};
this.name = options.name || "MOC";
this.color = options.color || Color.getNextColor();
this.color = Color.standardizeColor(this.color);
this.fillColor = options.fillColor || this.color;
this.fillColor = Color.standardizeColor(this.fillColor);
if (options && options.perimeter) {
this.perimeter = true;
} else {
this.perimeter = false;
}
this.opacity = options.opacity || 1;
if (options && options.fill) {
this.fill = true;
} else {
this.fill = false;
}
if (options && options.opacity) {
this.fill = true;
}
if (options && options.edge) {
this.edge = true;
} else {
this.edge = false;
}
if (!this.fill && !this.perimeter && options && !options.edge) {
this.edge = true;
}
this.opacity = Math.max(0, Math.min(1, this.opacity)); // 0 <= this.opacity <= 1
this.lineWidth = options["lineWidth"] || 3;
//this.proxyCalled = false; // this is a flag to check whether we already tried to load the MOC through the proxy
this.isShowing = true;
this.ready = false;
this.skyFrac = undefined;
}
/**
* Return a value between 0 and 1 denoting the fraction of the sky
* covered by the MOC
*
* @memberof MOC
*
* @returns {number} The sky fraction covered by the MOC
*/
MOC.prototype.skyFraction = function() {
return this.skyFrac;
};
/**
* set MOC data by parsing a MOC serialized in JSON
* (as defined in IVOA MOC document, section 3.1.1)
*/
MOC.prototype.parse = function(data, successCallback, errorCallback) {
if (typeof data === 'string' || data instanceof String) {
let url = data;
this.promiseFetchData = Utils.fetch({
url,
method: 'GET',
dataType: 'blob',
error: function(err) {
console.log('Something went wrong: ' + err);
}
}).then(blob => blob.arrayBuffer());
} else {
this.promiseFetchData = Promise.resolve(data)
}
this.successCallback = successCallback;
this.errorCallback = errorCallback;
};
MOC.prototype.setView = function(view, idx) {
let self = this;
this.view = view;
this.mocParams = new Aladin.wasmLibs.core.MOC(this.uuid, this.opacity, this.lineWidth, this.perimeter, this.fill, this.edge, this.isShowing, this.color, this.fillColor);
this.promiseFetchData
.then((data) => {
if (data instanceof ArrayBuffer) {
// from an url
const buf = data;
self.view.wasm.addFITSMOC(self.mocParams, new Uint8Array(buf));
} else if(data.ra && data.dec && data.radius) {
// circle
const c = data;
self.view.wasm.addConeMOC(self.mocParams, c.ra, c.dec, c.radius);
} else if(data.ra && data.dec) {
// polygon
const p = data;
self.view.wasm.addPolyMOC(self.mocParams, p.ra, p.dec);
} else {
// json moc
self.view.wasm.addJSONMoc(self.mocParams, data);
}
// Add the fetched moc to the rust backend
self.ready = true;
if (self.successCallback) {
self.successCallback(self)
}
// Cache the sky fraction
self.skyFrac = self.view.wasm.getMOCSkyFraction(this.mocParams);
// Add it to the view
self.view.mocs.push(self);
self.view.insertOverlay(self, idx);
// Tell the MOC has been fully loaded and can be sent as an event
ALEvent.GRAPHIC_OVERLAY_LAYER_ADDED.dispatchedTo(self.view.aladinDiv, {layer: self});
self.view.requestRedraw();
})
.catch(e => {
console.error('MOC load error:' + e)
if (self.errorCallback)
self.errorCallback(self);
})
};
MOC.prototype.reportChange = function() {
if (this.view) {
// update the new moc params to the backend
this.mocParams = new Aladin.wasmLibs.core.MOC(this.uuid, this.opacity, this.lineWidth, this.perimeter, this.fill, this.edge, this.isShowing, this.color, this.fillColor);
this.view.wasm.setMocParams(this.mocParams);
this.view.requestRedraw();
}
};
MOC.prototype.delete = function() {
if (this.view) {
// update the new moc params to the backend
this.view.wasm.removeMoc(this.mocParams);
this.view.requestRedraw();
}
};
/**
* Show the MOC object
*
* @memberof MOC
*/
MOC.prototype.show = function() {
if (this.isShowing) {
return;
}
this.isShowing = true;
this.reportChange();
};
/**
* Hide the MOC object
*
* @memberof MOC
*/
MOC.prototype.hide = function() {
if (! this.isShowing) {
return;
}
this.isShowing = false;
this.reportChange();
};
/**
* Tests whether a given (ra, dec) point on the sky is within the current MOC object
*
* @memberof MOC
* @param {number} ra - Right-Ascension of the location in degrees and ICRS frame
* @param {number} dec - Declination of the location in degrees and ICRS frame
*
* @returns {boolean} True if the point is contained, false otherwise
*/
MOC.prototype.contains = function(ra, dec) {
if (!this.ready) {
throw this.name + " is not yet ready, either because it has not been downloaded yet or because it has not been added to the aladin instance."
}
// update the new moc params to the backend
return this.view.wasm.mocContains(this.mocParams, ra, dec);
};
/**
* Serialize a MOC into different format
*
* @memberof MOC
* @param {string} [format='json'] - The output format. Only `json` is currently supported but `fits` could be added.
*/
MOC.prototype.serialize = function(format) {
if (!this.ready) {
throw this.name + " is not yet ready, either because it has not been downloaded yet or because it has not been added to the aladin instance."
}
return this.view.wasm.mocSerialize(this.mocParams, format);
}
return MOC;
})();