Refac and fix UI and cooFrame problems, add API doc too

This commit is contained in:
Matthieu Baumann
2024-03-14 19:52:28 +01:00
parent 2b618ff38d
commit 389654ba39
39 changed files with 869 additions and 1191 deletions

View File

@@ -2,6 +2,14 @@
## 3.3.0
* [fixed] A.on('select') (debugged from ipyaladin)
* [fixed] Simbad pointer in galactical frame, cone search of simbad/vizier cats/other cone search services in galactical frame and MOC creation from selection in galactical frame => there is now a new `frame` optional param to Aladin.pix2world. If not given, the coo returned are in the frame of the view.
* [doc] Add doc for image survey definition
* [deprecation] A.createImageSurvey/A.newImageSurvey are now deprecated (but still in the API). Please use `A.imageHiPS` instead by providing a valid url or CDS ID conformed to <https://aladin.cds.unistra.fr/hips/list>
* [refac] Simplify the instanciation of an imageHiPS/ imageFITS. Add a `A.imageHiPS` method for defining a HiPS object
* [fixed] At initialisation, giving a fov > 180 was clamped back to 180 even if we specify allsky projection (i.e. accepting fov > 180). This is now fixed.
* [fixed] MeasurementTable now display the full cell values (no ellipsis anymore)
* [fixed] aladin.on('select') has been implemented. Callback is triggered on a circle and rect selections for not on polygonal selection.
* [fixed] the cooFrame UI selector is updated if the user calls `aladin.setFrame`
* [fixed] `reticleColor` and `reticleSize` options in the public API
* Restore setFoVRange

View File

@@ -11,6 +11,7 @@ Aladin Lite is built to be easily embeddable in any web page. It powers astronom
More details on [Aladin Lite documentation page](http://aladin.u-strasbg.fr/AladinLite/doc/).
[![Run tests](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml/badge.svg)](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml)
[![API Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://cds-astro.github.io/aladin-lite)
# How to test it ?

View File

@@ -9,8 +9,8 @@
A.init.then(() => {
let aladin = A.aladin('#aladin-lite-div', {fov: 70,projection: "AIT"});
//let hsc = aladin.newImageSurvey("P/HSC/DR2/deep/g", {colormap:"Purples", imgFormat: "fits"});
//aladin.setBaseImageLayer(hsc);
let hsc = aladin.newImageSurvey("P/HSC/DR2/deep/g", {colormap:"Purples", imgFormat: "fits"});
aladin.setBaseImageLayer(hsc);
});
</script>

View File

@@ -252,13 +252,13 @@
aladin.addCatalog(hipsCats['constellations-boundaries']);
aladin.addCatalog(hipsCats['gaia']);
var coronelliStars = {
'coronelli-stars-white': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/white.xml", {name: 'Coronelli white', color: '#ffffff', shape: 'rhomb', sourceSize: 10}),
'coronelli-stars-yellow': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/yellow.xml", {name: 'Coronelli yellow', color: '#f6f874', shape: 'rhomb', sourceSize: 10}),
'coronelli-stars-red': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/red.xml", {name: 'Coronelli red', color: '#ff5555', shape: 'rhomb', sourceSize: 10}),
'coronelli-stars-blue': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/blue.xml", {name: 'Coronelli blue', color: '#1ca5ec', shape: 'rhomb', sourceSize: 10})
'coronelli-stars-white': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/white.xml", {name: 'Coronelli white', color: '#ffffff', shape: 'rhomb', sourceSize: 10}),
'coronelli-stars-yellow': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/yellow.xml", {name: 'Coronelli yellow', color: '#f6f874', shape: 'rhomb', sourceSize: 10}),
'coronelli-stars-red': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/red.xml", {name: 'Coronelli red', color: '#ff5555', shape: 'rhomb', sourceSize: 10}),
'coronelli-stars-blue': A.catalogFromURL("http://cdsweb.u-strasbg.fr/~derriere/coronelli/blue.xml", {name: 'Coronelli blue', color: '#1ca5ec', shape: 'rhomb', sourceSize: 20})
};
coronelliStars['coronelli-stars-white'].hide();
coronelliStars['coronelli-stars-yellow'].hide();
coronelliStars['coronelli-stars-red'].hide();

View File

@@ -70,7 +70,7 @@
aladin.addStatusBarMessage({
duration: 10000,
type: 'info',
message: 'Aladin Lite v3.3 is out. New features available:<ul><li>New Button, Box objects</li><li>Polygonal, circular selection</li></ul>'
message: 'Aladin Lite v3.3 is out. New features available:<ul><li>New Button, Box <b>objects</b></li><li>Polygonal, circular selection</li></ul>'
})
});
</script>
@@ -94,6 +94,11 @@
background-color: pink;
}
.aladin-cooFrame {
position: absolute;
top: 10rem;
}
</style>
</body>
</html>

View File

@@ -26,6 +26,7 @@
}, // no optional params
(ra, dec, fov, image) => {
// ra, dec and fov are centered around the fits image
console.log("jjj", image)
image.setColormap("magma", {stretch: "asinh"});
aladin.gotoRaDec(ra, dec);

View File

@@ -16,8 +16,8 @@
showContextMenu: true,
fullScreen: true,
showSimbadPointerControl: true,
showSimbadPointerControl: false,
showShareControl: true,
showSettingsControl: true,
showStackLayerControl: true,
samp: true,
});

View File

@@ -13,9 +13,9 @@
aladin = A.aladin('#aladin-lite-div', {survey: 'http://alasky.cds.unistra.fr/ancillary/GaiaDR2/hips-density-map/', showProjectionControl: true, showContextMenu: true, showStatusBar: true, fullScreen: true, target: 'galactic center'});
const fluxMap = aladin.createImageSurvey('gdr3-color-flux-map', 'Gaia DR3 flux map', 'https://alasky.u-strasbg.fr/ancillary/GaiaEDR3/color-Rp-G-Bp-flux-map', 'equatorial', 7);
const densityMap = aladin.createImageSurvey('gdr3-density-map', 'Gaia DR3 density map', 'sdfsg', 'equatorial', 7, {imgFormat: 'fits'});
const decaps = aladin.createImageSurvey("decaps", "DECaPS DR1", "http://alasky.u-strasbg.fr/DECaPS/DR1/color/", "equatorial", 11, {imgFormat: 'png'});
const panstarrs = aladin.createImageSurvey("panstarrs", "PanSTARRS", "http://alasky.u-strasbg.fr/Pan-STARRS/DR1/color-i-r-g/", "equatorial", 11, {imgFormat: 'jpg'});
const densityMap = aladin.createImageSurvey('gdr3-density-map', 'Gaia DR3 density map', 'sdfsg', 'equatorial', 7, {formats: ['fits']});
const decaps = aladin.createImageSurvey("decaps", "DECaPS DR1", "http://alasky.u-strasbg.fr/DECaPS/DR1/color/", "equatorial", 11, {formats: ['png'], tileSize: 512});
const panstarrs = aladin.createImageSurvey("panstarrs", "PanSTARRS", "http://alasky.u-strasbg.fr/Pan-STARRS/DR1/color-i-r-g/", "equatorial", 11, {formats: ['jpg']});
aladin.setOverlayImageLayer(fluxMap)
aladin.setOverlayImageLayer(densityMap, "density")

View File

@@ -9,6 +9,8 @@
<script type="module">
import A from '../src/js/A.js';
var aladin;
console.log("jkjkjk")
A.init.then(() => {
aladin = A.aladin(
'#aladin-lite-div',
@@ -29,7 +31,7 @@
showZoomControl: true,
showContextMenu: true,
showCooGridControl: true,
showSimbadPointerControl: true,
//showSimbadPointerControl: true,
showFullscreenControl: true,
}
);

View File

@@ -4,12 +4,11 @@
</head>
<body>
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
<script>var aladin;</script>
<script type="module">
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, survey: ['P/DM/vizMine', 'P/HST/GOODS/color', 'P/MATLAS/g'], target: '0 0', showProjectionControl: true, showCooGrid: true, fov: 180});
aladin = A.aladin('#aladin-lite-div', {projection: 'MOL', fullScreen: true, fov: 360, survey: ['P/DM/vizMine', 'P/HST/GOODS/color', 'P/MATLAS/g'], target: '0 0', showProjectionControl: true, showSettingsControl: true, showCooGrid: true});
});
</script>

View File

@@ -0,0 +1,27 @@
<!doctype html>
<html>
<head>
</head>
<body>
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
<script type="module">
import A from '../src/js/A.js';
A.init.then(() => {
let aladin = A.aladin('#aladin-lite-div', {fov: 70,projection: "AIT"});
aladin.setOverlayImageLayer(A.imageHiPS(
'Fermi',
"https://alasky.cds.unistra.fr/Fermi/Color",
{
name: "Fermi color",
maxOrder: 3,
imgFormat: 'jpeg',
tileSize: 512,
cooFrame: 'equatorial'
}
));
});
</script>
</body>
</html>

View File

@@ -43,10 +43,9 @@ pub struct HiPSProperties {
// Associated with the HiPS
url: String,
max_order: u8,
frame: CooSystem,
coo_frame: CooSystem,
tile_size: i32,
formats: Vec<ImageExt>,
dataproduct_subtype: Option<Vec<String>>,
is_planetary_body: Option<bool>,
@@ -103,7 +102,7 @@ impl HiPSProperties {
#[inline(always)]
pub fn get_frame(&self) -> CooSystem {
self.frame
self.coo_frame
}
#[inline(always)]
@@ -125,11 +124,6 @@ impl HiPSProperties {
pub fn get_initial_dec(&self) -> Option<f64> {
self.hips_initial_dec
}
#[inline(always)]
pub fn get_dataproduct_subtype(&self) -> &Option<Vec<String>> {
&self.dataproduct_subtype
}
}
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]

View File

@@ -4,10 +4,10 @@ pub mod uv;
use al_api::hips::ImageExt;
use al_api::hips::ImageMetadata;
use al_core::colormap::Colormap;
use al_core::colormap::Colormaps;
use al_core::image::format::ChannelType;
use al_core::image::format::ImageFormatType;
use al_core::image::Image;
use al_core::log::console_log;
use al_core::shader::Shader;
@@ -282,9 +282,7 @@ pub fn get_raster_shader<'a>(
shaders: &'a mut ShaderManager,
config: &HiPSConfig,
) -> Result<&'a Shader, JsValue> {
let colored_hips = config.is_colored();
if colored_hips && cmap.label() == "native" {
if config.get_format().is_colored() && cmap.label() == "native" {
crate::shader::get_shader(gl, shaders, "RasterizerVS", "RasterizerColorFS")
} else {
if config.tex_storing_unsigned_int {
@@ -318,8 +316,8 @@ pub fn get_raytracer_shader<'a>(
shaders: &'a mut ShaderManager,
config: &HiPSConfig,
) -> Result<&'a Shader, JsValue> {
let colored_hips = config.is_colored();
if colored_hips && cmap.label() == "native" {
//let colored_hips = config.is_colored();
if config.get_format().is_colored() && cmap.label() == "native" {
crate::shader::get_shader(gl, shaders, "RayTracerVS", "RayTracerColorFS")
} else {
if config.tex_storing_unsigned_int {

View File

@@ -168,8 +168,8 @@ pub struct HiPSConfig {
pub frame: CooSystem,
pub bitpix: Option<i32>,
format: ImageFormatType,
dataproduct_subtype: Option<Vec<String>>,
colored: bool,
//dataproduct_subtype: Option<Vec<String>>,
//colored: bool,
pub creator_did: String,
}
@@ -272,7 +272,7 @@ impl HiPSConfig {
}),
}?;
let dataproduct_subtype = properties.get_dataproduct_subtype().clone();
/*let dataproduct_subtype = properties.get_dataproduct_subtype().clone();
let colored = if tex_storing_fits {
false
} else {
@@ -281,7 +281,7 @@ impl HiPSConfig {
} else {
false
}
};
};*/
let empty_image = EmptyTileImage::new(tile_size, format.get_channel());
@@ -341,8 +341,8 @@ impl HiPSConfig {
bitpix,
format,
tile_size,
dataproduct_subtype,
colored,
//dataproduct_subtype,
//colored,
};
Ok(hips_config)
@@ -421,7 +421,7 @@ impl HiPSConfig {
self.empty_image = EmptyTileImage::new(self.tile_size, self.format.get_channel());
// Recompute if the survey will be colored or not
self.colored = if self.tex_storing_fits {
/*self.colored = if self.tex_storing_fits {
false
} else {
if let Some(subtypes) = &self.dataproduct_subtype {
@@ -429,7 +429,7 @@ impl HiPSConfig {
} else {
false
}
};
};*/
Ok(())
}
@@ -528,7 +528,7 @@ impl HiPSConfig {
#[inline(always)]
pub fn is_colored(&self) -> bool {
self.colored
self.format.is_colored()
}
#[inline(always)]

View File

@@ -80,7 +80,7 @@ body { overscroll-behavior: contain; }
display: block;
max-height: 33vh;
max-height: 30vh;
max-width: 100%;
-ms-overflow-style: none;
overscroll-behavior-x: none;
@@ -150,8 +150,8 @@ body { overscroll-behavior: contain; }
white-space: nowrap;
overflow: hidden;
text-align: center;
max-width: 150px;
text-overflow: ellipsis;
/*max-width: 150px;
text-overflow: ellipsis;*/
}
.aladin-measurement-div table td.aladin-text-td-container {
@@ -159,8 +159,8 @@ body { overscroll-behavior: contain; }
white-space: nowrap;
overflow: hidden;
max-width: 150px;
text-overflow: ellipsis;
/*max-width: 150px;
text-overflow: ellipsis;*/
}
.aladin-measurement-div table td.aladin-href-td-container:hover {
@@ -464,10 +464,12 @@ canvas {
}
.aladin-input-text.search.aladin-unknownObject {
-webkit-box-shadow:inset 0px 0px 0px 3px #f00;
-moz-box-shadow:inset 0px 0px 0px 3px #f00;
box-shadow:inset 0px 0px 0px 3px #f00;
}
-webkit-box-shadow:inset 0px 0px 0px 1px #f00;
-moz-box-shadow:inset 0px 0px 0px 1px #f00;
box-shadow:inset 0px 0px 0px 1px #f00;
border: 1px solid red;
}
.aladin-dark-theme {
color: white;
@@ -654,10 +656,14 @@ canvas {
.aladin-status-bar-message {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 300px;
text-wrap: nowrap;
-ms-overflow-style: none;
overscroll-behavior-x: none;
overflow-y: scroll;
scrollbar-width: none;
max-width: 30rem;
font-size: 1rem;
}
@@ -988,6 +994,7 @@ canvas {
border-radius: 2px;
top:0%;
left:0%;
z-index: 100;

View File

@@ -87,6 +87,7 @@ let A = {};
*/
A.aladin = function (divSelector, options) {
let divElement;
if (!(divSelector instanceof HTMLElement)) {
divElement = document.querySelector(divSelector)
} else {
@@ -95,6 +96,45 @@ A.aladin = function (divSelector, options) {
return new Aladin(divElement, options);
};
/**
* Creates a HiPS image object
*
* @function
* @name A.imageHiPS
* @memberof A
* @param {string} id - Mandatory unique identifier for the layer.
* @param {string} url - Can be an `url` that refers to a HiPS.
* Or it can be a "CDS ID" pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}.
* @param {ImageSurveyOptions} [options] - Options describing the survey
* @returns {ImageSurvey} - A HiPS image object
*/
A.imageHiPS = function (id, url, options) {
return Aladin.createImageSurvey(
id,
options && options.name,
url,
options && options.cooFrame,
options && options.maxOrder,
options
);
}
/**
* Creates a celestial source object with the given coordinates.
*
* @function
* @name A.imageFITS
* @memberof A
* @param {string} url - Options describing the fits file. An url is mandatory
* @param {ImageFITSOptions} [options] - Options describing the fits file. An url is mandatory
* @returns {ImageSurvey} - A HiPS image object
* @example
* const sourceObj = A.source(180.0, 30.0, data, options);
*/
A.imageFITS = function (url, options) {
return Aladin.createImageFITS(url, options.name, options, options.successCallback, options.errorCallback);
}
/**
* Creates a celestial source object with the given coordinates.
*

View File

@@ -56,14 +56,11 @@ import { Location } from "./gui/Location.js";
import { FoV } from "./gui/FoV.js";
import { ShareActionButton } from "./gui/Button/ShareView.js";
import { ContextMenu } from "./gui/Widgets/ContextMenu.js";
import { Input } from "./gui/Widgets/Input.js";
import { Popup } from "./Popup.js";
import A from "./A.js";
import { StatusBarBox } from "./gui/Box/StatusBarBox.js";
import { FullScreenActionButton } from "./gui/Button/FullScreen.js";
import { ProjectionActionButton } from "./gui/Button/Projection.js";
import { Toolbar } from './gui/Widgets/Toolbar';
import { ImageLayer } from './ImageLayer';
// features
import { SettingsButton } from "./gui/Button/Settings";
@@ -80,7 +77,7 @@ import { CooFrame } from './gui/Input/CooFrame';
* @property {string[]} [surveyUrl=["https://alaskybis.unistra.fr/DSS/DSSColor", "https://alasky.unistra.fr/DSS/DSSColor"]]
* Array of URLs for the survey images. This replaces the survey parameter.
* @property {string} [target="0 +0"] - Target coordinates for the initial view.
* @property {string} [cooFrame="J2000"] - Coordinate frame.
* @property {CooFrame} [cooFrame="J2000"] - Coordinate frame.
* @property {number} [fov=60] - Field of view in degrees.
* @property {string} [backgroundColor="rgb(60, 60, 60)"] - Background color in RGB format.
*
@@ -130,13 +127,18 @@ import { CooFrame } from './gui/Input/CooFrame';
* @property {boolean} [gridOptions.showLabels=true] - Whether the grid has labels.
* @property {number} [gridOptions.labelSize=15] - The font size of the labels.
*
* @property {string} [projection="SIN"] - Projection type.
* @property {string} [projection="SIN"] - Projection type. Can be 'SIN' for orthographic, 'MOL' for mollweide, 'AIT' for hammer-aitoff, 'ZEA' for zenital equal-area or 'MER' for mercator
* @property {boolean} [log=true] - Whether to log events.
* @property {boolean} [samp=false] - Whether to enable SAMP (Simple Application Messaging Protocol).
* @property {boolean} [realFullscreen=false] - Whether to use real fullscreen mode.
* @property {boolean} [pixelateCanvas=true] - Whether to pixelate the canvas.
*/
/**
* @typedef {string} CooFrame
* String with possible values: 'equatorial', 'ICRS', 'ICRSd', 'j2000', 'gal, 'galactic'
*/
export let Aladin = (function () {
/**
* Creates an instance of the Aladin interactive sky atlas.
@@ -214,11 +216,9 @@ export let Aladin = (function () {
// parent div
aladinDiv.classList.add("aladin-container");
// measurement table
// Init the measurement table
this.measurementTable = new MeasurementTable(this);
//var location = new Location(locationDiv.find('.aladin-location-text'));
// set different options
// Reticle
this.view = new View(this);
@@ -229,7 +229,6 @@ export let Aladin = (function () {
this.reticle = new Reticle(this.options, this);
this.popup = new Popup(this.aladinDiv, this.view);
this.cacheSurveys = new Map();
this.ui = [];
// Background color
@@ -249,10 +248,6 @@ export let Aladin = (function () {
}
this.setCooGrid(gridOptions);
// Set the projection
let projection = (options && options.projection) || 'SIN';
this.setProjection(projection)
this.gotoObject(options.target, undefined);
if (options.log) {
@@ -279,12 +274,14 @@ export let Aladin = (function () {
i++;
});
} else if (options.survey === ImageSurvey.DEFAULT_SURVEY_ID) {
const survey = ImageSurvey.fromLayerOptions(this, ImageLayer.DEFAULT_SURVEY);
// DSS is cached inside ImageSurvey class, no need to provide any further information
const survey = this.createImageSurvey(ImageSurvey.DEFAULT_SURVEY_ID);
this.setBaseImageLayer(survey);
} else {
this.setBaseImageLayer(options.survey)
}
} else if (options.surveyUrl) {
} else {
// Add the image layers
// For that we check the survey key of options
// It can be given as a single string or an array of strings
@@ -301,9 +298,6 @@ export let Aladin = (function () {
}
this.setBaseImageLayer(url);
} else {
// This case should not happen because if there is no survey given
// then the surveyUrl pointing to the DSS is given.
}
this.view.showCatalog(options.showCatalog);
@@ -348,11 +342,7 @@ export let Aladin = (function () {
// Status bar
if (options.showStatusBar) {
let statusBarOptions = {};
if (typeof options.showStatusBar === "object") {
statusBarOptions = options.showStatusBar;
}
this.statusBar = new StatusBarBox(this, statusBarOptions);
this.statusBar = new StatusBarBox(this);
this.addUI(this.statusBar)
}
@@ -853,7 +843,7 @@ export let Aladin = (function () {
}
// planetary case
else {
const body = baseImageLayer.properties.hipsBody;
const body = baseImageLayer.hipsBody;
PlanetaryFeaturesNameResolver.resolve(targetName, body,
function (data) { // success callback
self.view.pointTo(data.lon, data.lat);
@@ -1179,29 +1169,51 @@ export let Aladin = (function () {
this.view.removeLayer(layer);
};
// @oldAPI
Aladin.prototype.createImageSurvey = function(id, name, rootUrl, cooFrame, maxOrder, options = {}) {
let cfg = this.cacheSurveys.get(id);
if (!cfg) {
// Add the cooFrame and maxOrder given by the user
// to the list of options passed to the ImageSurvey constructor
if (cooFrame) {
options.cooFrame = cooFrame;
}
/**
* @deprecated
* Creates and return an image survey (HiPS) object
*
* @memberof Aladin
* @param {string} id - Mandatory unique identifier for the layer.
* @param {string} [name] - A convinient name for the survey, optional
* @param {string} url - Can be an `url` that refers to a HiPS.
* Or it can be a "CDS ID" pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}.
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
* @param {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
* @param {ImageSurveyOptions} [options] - Options describing the survey
* @returns {ImageSurvey} A HiPS image object.
*/
Aladin.prototype.createImageSurvey = function(id, name, url, cooFrame, maxOrder, options) {
let surveyOptions = ImageSurvey.cache[id];
if (maxOrder) {
options.maxOrder = maxOrder;
}
cfg = {id, name, rootUrl, options};
this.cacheSurveys.set(id, cfg);
} else {
cfg = Utils.clone(cfg)
if (!surveyOptions) {
surveyOptions = {url, name, maxOrder, cooFrame, ...options};
ImageSurvey.cache[id] = surveyOptions;
}
return new ImageSurvey(cfg.id, cfg.name, cfg.rootUrl, cfg.options, this.view);
return new ImageSurvey(id, surveyOptions.url, surveyOptions);
};
Aladin.prototype.createImageFITS = function(url, name, options = {}, successCallback = undefined, errorCallback = undefined) {
/**
* @deprecated
* Creates and return an image survey (HiPS) object
*
* @function createImageSurvey
* @memberof Aladin
* @static
* @param {string} id - Mandatory unique identifier for the layer.
* @param {string} [name] - A convinient name for the survey, optional
* @param {string} url - Can be an `url` that refers to a HiPS.
* Or it can be a "CDS ID" pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}.
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
* @param {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
* @param {ImageSurveyOptions} [options] - Options describing the survey
* @returns {ImageSurvey} A HiPS image object.
*/
Aladin.createImageSurvey = Aladin.prototype.createImageSurvey;
Aladin.prototype.createImageFITS = function(url, name, options, successCallback, errorCallback) {
try {
url = new URL(url);
} catch(e) {
@@ -1213,30 +1225,53 @@ export let Aladin = (function () {
// Do not use proxy with CORS headers until we solve that: https://github.com/MattiasBuelens/wasm-streams/issues/20
//url = Utils.handleCORSNotSameOrigin(url);
let cfg = this.cacheSurveys.get(url);
if (!cfg) {
cfg = {url, name, options, successCallback, errorCallback}
this.cacheSurveys.set(url, cfg);
} else {
cfg = Utils.clone(cfg)
let image = ImageFITS.cache[url];
if (!image) {
image = new ImageFITS(url, name, options, successCallback, errorCallback)
ImageFITS.cache[url] = image;
}
return new ImageFITS(cfg.url, cfg.name, this.view, cfg.options, cfg.successCallback, cfg.errorCallback);
return image;
};
Aladin.prototype.newImageSurvey = function(rootUrlOrId, options) {
const idOrUrl = rootUrlOrId;
// Check if the survey has already been added
// Create a new ImageSurvey
const name = idOrUrl;
/**
* Creates a FITS image object
*
* @function createImageFITS
* @memberof Aladin
* @static
* @param {string} url - The url of the fits.
* @param {string} [name] - The url of the fits.
* @param {ImageSurveyOptions} [options] - Options for rendering the image
* @param {function} [success] - A success callback
* @param {function} [error] - A success callback
* @returns {ImageSurvey} A FITS image object.
*/
Aladin.createImageFITS = Aladin.prototype.createImageFITS;
return this.createImageSurvey(idOrUrl, name, idOrUrl, null, null, options);
/**
* @deprecated
* Create a new layer from an url or CDS ID.
*
* @memberof Aladin
* @static
* @param {string} url - Can be an `url` that refers to a HiPS.
* Or it can be a "CDS ID" pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}.
* @param {ImageSurveyOptions} [options] - Options for rendering the image
* @param {function} [success] - A success callback
* @param {function} [error] - A success callback
* @returns {ImageSurvey} A FITS image object.
*/
Aladin.prototype.newImageSurvey = function(url, options) {
const id = url;
return A.imageHiPS(id, url, options);
}
Aladin.prototype.addNewImageLayer = function() {
let layerName = Utils.uuidv4();
// A HIPS_LAYER_ADDED will be called after the hips is added to the view
this.setOverlayImageLayer('CDS/P/DSS2/color', layerName);
this.setOverlayImageLayer(ImageSurvey.DEFAULT_SURVEY_ID, layerName);
}
// @param imageSurvey : ImageSurvey object or image survey identifier
@@ -1273,8 +1308,8 @@ export let Aladin = (function () {
};
Aladin.prototype.setBaseImageLayer = function(idOrSurvey) {
return this.setOverlayImageLayer(idOrSurvey, "base");
Aladin.prototype.setBaseImageLayer = function(idOrUrlOrImageLayer) {
return this.setOverlayImageLayer(idOrUrlOrImageLayer, "base");
};
// @api
@@ -1288,26 +1323,9 @@ export let Aladin = (function () {
// 1. User gives an ID
if (typeof idOrUrlOrImageLayer === "string") {
const idOrUrl = idOrUrlOrImageLayer;
// Check if the survey has already been added
// Create a new ImageSurvey
/*let isUrl = false;
if (idOrUrl.includes("http")) {
isUrl = true;
}
const name = idOrUrl;
if (isUrl) {
const url = idOrUrl;
const id = url;
// Url
imageLayer = this.createImageSurvey(idOrUrl, name, idOrUrl, null, null);
} else {
const id = idOrUrl;
// ID
imageLayer = this.createImageSurvey(idOrUrl, name, idOrUrl, null, null);
}*/
const name = idOrUrl;
imageLayer = this.createImageSurvey(idOrUrl, name, idOrUrl, null, null);
imageLayer = A.imageHiPS(idOrUrl, idOrUrl);
// 2. User gives a non resolved promise
} else {
imageLayer = idOrUrlOrImageLayer;
@@ -1457,11 +1475,6 @@ export let Aladin = (function () {
Aladin.prototype.select = async function (mode = 'rect', callback) {
await this.reticle.loaded;
// Default callback selects objects
callback = callback || ((selection) => {
this.view.selectObjects(selection);
});
this.fire('selectstart', {mode, callback});
};
@@ -1635,7 +1648,7 @@ export let Aladin = (function () {
let radecsys;
if (this.getBaseImageLayer().isPlanetaryBody()) {
const body = this.getBaseImageLayer().properties.hipsBody
const body = this.getBaseImageLayer().hipsBody
if (body in solarSystemObjects) {
cooType1 = `${solarSystemObjects[body]}LN-`;
cooType2 = `${solarSystemObjects[body]}LT-`;
@@ -1715,13 +1728,29 @@ export let Aladin = (function () {
* @memberof Aladin
* @param {number} x - The x-coordinate in pixel coordinates.
* @param {number} y - The y-coordinate in pixel coordinates.
* @param {CooFrame} [frame] - The frame in which we want to retrieve the coordinates.
* If not given, the frame chosen is the one from the view
*
* @returns {number[]} - An array representing the [Right Ascension, Declination] coordinates in degrees.
* @returns {number[]} - An array representing the [Right Ascension, Declination] coordinates in degrees in the `frame`.
* If not specified, returns the coo in the frame of the current view.
*
* @throws {Error} Throws an error if an issue occurs during the transformation.
*/
Aladin.prototype.pix2world = function (x, y) {
const [ra, dec] = this.view.wasm.screenToWorld(x, y);
Aladin.prototype.pix2world = function (x, y, frame) {
let radec = this.view.wasm.screenToWorld(x, y);
frame = frame || this.view.cooFrame.label;
frame = CooFrameEnum.fromString(frame, CooFrameEnum.J2000);
if (frame !== this.view.cooFrame) {
if (frame.label === 'Galactic') {
console.warn('Conversion from icrs to galactic not yet impl')
} else {
radec = this.view.wasm.viewToICRSCooSys(radec[0], radec[1]);
}
}
let [ra, dec] = radec;
if (ra < 0) {
return [ra + 360.0, dec];
@@ -1734,8 +1763,8 @@ export let Aladin = (function () {
* Transform world coordinates to pixel coordinates in the view.
*
* @memberof Aladin
* @param {number} ra - The Right Ascension (RA) coordinate in degrees.
* @param {number} dec - The Declination (Dec) coordinate in degrees.
* @param {number} ra - The Right Ascension (RA) coordinate in degrees. Frame considered is the current view frame
* @param {number} dec - The Declination (Dec) coordinate in degrees. Frame considered is the current view frame
*
* @returns {number[]} - An array representing the [x, y] coordinates in pixel coordinates in the view.
*
@@ -1753,14 +1782,16 @@ export let Aladin = (function () {
* @param {number} y1 - The y-coordinate of the first pixel coordinates.
* @param {number} x2 - The x-coordinate of the second pixel coordinates.
* @param {number} y2 - The y-coordinate of the second pixel coordinates.
* @param {CooFrame} [frame] - The frame in which we want to retrieve the coordinates.
* If not given, the frame chosen is the one from the view
*
* @returns {number} - The angular distance between the two pixel coordinates in degrees
*
* @throws {Error} Throws an error if an issue occurs during the transformation.
*/
Aladin.prototype.angularDist = function (x1, y1, x2, y2) {
const [ra1, dec1] = this.pix2world(x1, y1);
const [ra2, dec2] = this.pix2world(x2, y2);
Aladin.prototype.angularDist = function (x1, y1, x2, y2, frame) {
const [ra1, dec1] = this.pix2world(x1, y1, frame);
const [ra2, dec2] = this.pix2world(x2, y2, frame);
return this.wasm.angularDist(ra1, dec1, ra2, dec2);
};

View File

@@ -55,7 +55,6 @@ export let Catalog = (function() {
* @param {string} [options.name="catalog"] - The name of the catalog.
* @param {string} [options.color] - The color associated with the catalog.
* @param {number} [options.sourceSize=8] - The size of the sources in the catalog.
* @param {number} [options.markerSize=12] - The size of the markers associated with sources.
* @param {string} [options.shape="square"] - The shape of the sources (can be, "square", "circle", "plus", "cross", "rhomb", "triangle").
* @param {number} [options.limit] - The maximum number of sources to display.
* @param {function} [options.onClick] - The callback function to execute on a source click.

View File

@@ -222,7 +222,31 @@
return [this.minCut, this.maxCut];
};
ColorCfg.COLORMAPS = [];
ColorCfg.COLORMAPS = [
"blues",
"cividis",
"cubehelix",
"eosb",
"grayscale",
"inferno",
"magma",
"native",
"parula",
"plasma",
"rainbow",
"rdbu",
"rdylbu",
"redtemperature",
"sinebow",
"spectral",
"summer",
"viridis",
"ylgnbu",
"ylorbr",
"red",
"green",
"blue"
];
return ColorCfg;
})();

View File

@@ -1,275 +0,0 @@
// Copyright 2013 - UDS/CNRS
// The Aladin Lite program is distributed under the terms
// of the GNU General Public License version 3.
//
// This file is part of Aladin Lite.
//
// Aladin Lite is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Aladin Lite is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available in COPYING file
// along with Aladin Lite.
//
/******************************************************************************
* Aladin Lite project
*
* File ColorMap.js
*
* Author: Thomas Boch[CDS]
*
*****************************************************************************/
import { AladinUtils } from "./AladinUtils.js";
/**
* @deprecated since version 3.0
*/
export let ColorMap = (function() {
// constructor
let ColorMap = function(view) {
this.view = view;
this.reversed = false;
this.mapName = 'native';
this.sig = this.signature();
};
ColorMap.MAPS = {};
ColorMap.MAPS['eosb'] = {
name: 'Eos B',
r: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,9,18,27,36,45,49,57,72,81,91,100,109,118,127,
136,131,139,163,173,182,191,200,209,218,227,213,221,255,255,255,255,255,
255,255,255,229,229,255,255,255,255,255,255,255,255,229,229,255,255,255,
255,255,255,255,255,229,229,255,255,255,255,255,255,255,255,229,229,255,
255,255,255,255,255,255,255,229,229,255,255,255,255,255,255,255,255,229,
229,255,255,255,255,255,255,255,255,229,229,255,255,255,255,255,255,255,
255,229,229,255,255,255,255,255,255,255,255,229,229,255,253,251,249,247,
245,243,241,215,214,235,234,232,230,228,226,224,222,198,196,216,215,213,
211,209,207,205,203,181,179,197,196,194,192,190,188,186,184,164,162,178,
176,175,173,171,169,167,165,147,145,159,157,156,154,152,150,148,146,130,
128,140,138,137,135,133,131,129,127,113,111,121,119,117,117],
g: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,23,31,39,47,55,57,64,79,87,95,
103,111,119,127,135,129,136,159,167,175,183,191,199,207,215,200,207,239,
247,255,255,255,255,255,255,229,229,255,255,255,255,255,255,255,255,229,
229,255,255,255,255,255,255,255,255,229,229,255,250,246,242,238,233,229,
225,198,195,212,208,204,199,195,191,187,182,160,156,169,165,161,157,153,
148,144,140,122,118,127,125,123,121,119,116,114,112,99,97,106,104,102,
99,97,95,93,91,80,78,84,82,80,78,76,74,72,70,61,59,63,61,59,57,55,53,50,
48,42,40,42,40,38,36,33,31,29,27,22,21,21,19,16,14,12,13,8,6,3,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
b: [116,121,127,131,136,140,144,148,153,
157,145,149,170,174,178,182,187,191,195,199,183,187,212,216,221,225,229,
233,238,242,221,225,255,247,239,231,223,215,207,199,172,164,175,167,159,
151,143,135,127,119,100,93,95,87,79,71,63,55,47,39,28,21,15,7,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0]
};
ColorMap.MAPS['rainbow'] = {
name: 'Rainbow',
r: [0,4,9,13,18,22,27,31,36,40,45,50,54,
58,61,64,68,69,72,74,77,79,80,82,83,85,84,86,87,88,86,87,87,87,85,84,84,
84,83,79,78,77,76,71,70,68,66,60,58,55,53,46,43,40,36,33,25,21,16,12,4,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,12,21,25,29,33,42,
46,51,55,63,67,72,76,80,89,93,97,101,110,114,119,123,131,135,140,144,153,
157,161,165,169,178,182,187,191,199,203,208,212,221,225,229,233,242,246,
250,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255],
g: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,4,8,16,21,25,29,38,42,46,51,55,63,67,72,76,84,89,93,97,
106,110,114,119,127,131,135,140,144,152,157,161,165,174,178,182,187,195,
199,203,208,216,220,225,229,233,242,246,250,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,250,242,238,233,229,221,216,212,208,199,195,191,187,178,174,170,165,
161,153,148,144,140,131,127,123,119,110,106,102,97,89,85,80,76,72,63,59,
55,51,42,38,34,29,21,17,12,8,0],
b: [0,3,7,10,14,19,23,28,32,38,43,48,53,
59,63,68,72,77,81,86,91,95,100,104,109,113,118,122,127,132,136,141,145,
150,154,159,163,168,173,177,182,186,191,195,200,204,209,214,218,223,227,
232,236,241,245,250,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,246,242,238,233,225,220,216,212,203,199,195,191,
187,178,174,170,165,157,152,148,144,135,131,127,123,114,110,106,102,97,
89,84,80,76,67,63,59,55,46,42,38,34,25,21,16,12,8,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
};
ColorMap.MAPS['cubehelix'] = {
name: 'Cubehelix',
r: [0,1,3,4,6,8,9,10,12,13,14,15,17,18,
19,20,20,21,22,23,23,24,24,25,25,25,26,26,26,26,26,26,26,26,26,26,26,25,
25,25,25,24,24,24,23,23,23,23,22,22,22,21,21,21,21,21,21,20,20,20,21,21,
21,21,21,22,22,22,23,23,24,25,26,27,27,28,30,31,32,33,35,36,38,39,41,43,
45,47,49,51,53,55,57,60,62,65,67,70,72,75,78,81,83,86,89,92,95,98,101,104,
107,110,113,116,120,123,126,129,132,135,138,141,144,147,150,153,155,158,
161,164,166,169,171,174,176,178,181,183,185,187,189,191,193,194,196,198,
199,201,202,203,204,205,206,207,208,209,209,210,211,211,211,212,212,212,
212,212,212,212,212,211,211,211,210,210,210,209,208,208,207,207,206,205,
205,204,203,203,202,201,201,200,199,199,198,197,197,196,196,195,195,194,
194,194,193,193,193,193,193,193,193,193,193,193,194,194,195,195,196,196,
197,198,199,200,200,202,203,204,205,206,208,209,210,212,213,215,217,218,
220,222,223,225,227,229,231,232,234,236,238,240,242,244,245,247,249,251,
253,255],
g: [0,0,1,1,2,2,3,4,4,5,6,6,7,8,9,10,
11,11,12,13,14,15,17,18,19,20,21,22,24,25,26,28,29,31,32,34,35,37,38,40,
41,43,45,46,48,50,52,53,55,57,58,60,62,64,66,67,69,71,73,74,76,78,79,81,
83,84,86,88,89,91,92,94,95,97,98,99,101,102,103,104,106,107,108,109,110,
111,112,113,114,114,115,116,116,117,118,118,119,119,120,120,120,121,121,
121,121,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,121,
121,121,121,121,121,121,121,121,120,120,120,120,120,120,120,120,120,120,
121,121,121,121,121,122,122,122,123,123,124,124,125,125,126,127,127,128,
129,130,131,131,132,133,135,136,137,138,139,140,142,143,144,146,147,149,
150,152,154,155,157,158,160,162,164,165,167,169,171,172,174,176,178,180,
182,183,185,187,189,191,193,194,196,198,200,202,203,205,207,208,210,212,
213,215,216,218,219,221,222,224,225,226,228,229,230,231,232,233,235,236,
237,238,239,240,240,241,242,243,244,244,245,246,247,247,248,248,249,250,
250,251,251,252,252,253,253,254,255],
b: [0,1,3,4,6,8,9,11,13,15,17,19,21,23,
25,27,29,31,33,35,37,39,41,43,45,47,48,50,52,54,56,57,59,60,62,63,65,66,
67,69,70,71,72,73,74,74,75,76,76,77,77,77,78,78,78,78,78,78,78,77,77,77,
76,76,75,75,74,73,73,72,71,70,69,68,67,66,66,65,64,63,61,60,59,58,58,57,
56,55,54,53,52,51,51,50,49,49,48,48,47,47,47,46,46,46,46,46,47,47,47,48,
48,49,50,50,51,52,53,55,56,57,59,60,62,64,65,67,69,71,74,76,78,81,83,86,
88,91,94,96,99,102,105,108,111,114,117,120,124,127,130,133,136,140,143,
146,149,153,156,159,162,165,169,172,175,178,181,184,186,189,192,195,197,
200,203,205,207,210,212,214,216,218,220,222,224,226,227,229,230,231,233,
234,235,236,237,238,239,239,240,241,241,242,242,242,243,243,243,243,243,
243,243,243,243,243,242,242,242,242,241,241,241,241,240,240,240,239,239,
239,239,239,238,238,238,238,238,238,238,238,239,239,239,240,240,240,241,
242,242,243,244,245,246,247,248,249,250,252,253,255]
};
ColorMap.MAPS_CUSTOM = ['cubehelix', 'eosb', 'rainbow'];
ColorMap.MAPS_NAMES = ['native', 'grayscale'].concat(ColorMap.MAPS_CUSTOM);
ColorMap.prototype.reverse = function(val) {
if (val) {
this.reversed = val;
}
else {
this.reversed = ! this.reversed;
}
this.sig = this.signature();
this.view.requestRedraw();
};
ColorMap.prototype.signature = function() {
var s = this.mapName;
if (this.reversed) {
s += ' reversed';
}
return s;
};
ColorMap.prototype.update = function(mapName) {
this.mapName = mapName;
this.sig = this.signature();
this.view.requestRedraw();
};
ColorMap.prototype.apply = function(img) {
if ( this.sig=='native' ) {
return img;
}
if (img.cmSig==this.sig) {
return img.cmImg; // return cached pixels
}
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixelData = imageData.data;
var length = pixelData.length;
var a, b, c;
var switchCase = 3;
if (this.mapName=='grayscale') {
switchCase = 1;
}
else if (ColorMap.MAPS_CUSTOM.indexOf(this.mapName)>=0) {
switchCase = 2;
}
for (var i = 0; i < length; i+= 4) {
switch(switchCase) {
case 1:
a = b = c = AladinUtils.myRound((pixelData[i]+pixelData[i+1]+pixelData[i+2])/3);
break;
case 2:
if (this.reversed) {
a = ColorMap.MAPS[this.mapName].r[255-pixelData[i]];
b = ColorMap.MAPS[this.mapName].g[255-pixelData[i+1]];
c = ColorMap.MAPS[this.mapName].b[255-pixelData[i+2]];
}
else {
a = ColorMap.MAPS[this.mapName].r[pixelData[i]];
b = ColorMap.MAPS[this.mapName].g[pixelData[i+1]];
c = ColorMap.MAPS[this.mapName].b[pixelData[i+2]];
}
break;
default:
a = pixelData[i];
b = pixelData[i + 1];
c = pixelData[i + 2];
}
if (switchCase!=2 && this.reversed) {
a = 255-a;
b = 255-b;
c = 255-c;
}
pixelData[i] = a;
pixelData[i + 1] = b;
pixelData[i + 2] = c;
}
//imageData.data = pixelData; // not needed, and create an error in strict mode !
ctx.putImageData(imageData, 0, 0);
// cache image with color map applied
img.cmSig = this.sig;
img.cmImg = canvas;
return img.cmImg;
};
return ColorMap;
})();

View File

@@ -19,6 +19,7 @@
import { FSM } from "../FiniteStateMachine";
import { View } from "../View";
import { Selector } from "../Selector";
/******************************************************************************
* Aladin Lite project
*
@@ -83,7 +84,8 @@ export class CircleSelect extends FSM {
x = this.startCoo.x;
y = this.startCoo.y;
(typeof this.callback === 'function') && this.callback({
let s = {
x, y, r,
label: 'circle',
contains(s) {
@@ -100,21 +102,25 @@ export class CircleSelect extends FSM {
h: 2*r
}
}
});
};
// execute general callback
if (view.aladin.callbacksByEventName) {
var callback = view.aladin.callbacksByEventName['select'];
if (typeof callback === "function") {
let objList = Selector.getObjects(s, view);
callback(objList);
}
}
// execute selection callback only
(typeof this.callback === 'function') && this.callback(s);
// TODO: remove these modes in the future
view.aladin.showReticle(true)
view.setCursor('default');
console.log("end select", view)
// execute general callback
if (view.callbacksByEventName) {
var callback = view.callbacksByEventName['select'];
if (typeof callback === "function") {
// !todo
let selectedObjects = view.selectObjects(this);
callback(selectedObjects);
}
}
view.setMode(View.PAN)
view.requestRedraw();
};

View File

@@ -163,13 +163,23 @@ export class PolySelect extends FSM {
let y = yMin;
let w = xMax - xMin;
let h = yMax - yMin;
(typeof this.callback === 'function') && this.callback({
let s = {
vertices: this.coos,
label: 'polygon',
bbox() {
return {x, y, w, h}
}
});
};
(typeof this.callback === 'function') && this.callback(s);
// execute general callback
if (view.aladin.callbacksByEventName) {
var callback = view.aladin.callbacksByEventName['select'];
if (typeof callback === "function") {
console.warn('polygon selection is not fully implemented, PolySelect.contains is needed for finding sources inside a polygon')
}
}
this.coos = [];

View File

@@ -19,6 +19,7 @@
import { FSM } from "../FiniteStateMachine";
import { View } from "../View";
import { Selector } from "../Selector";
/******************************************************************************
* Aladin Lite project
*
@@ -91,7 +92,7 @@ export class RectSelect extends FSM {
h = -h;
}
(typeof this.callback === 'function') && this.callback({
let s = {
x, y, w, h,
label: 'rect',
contains(s) {
@@ -100,21 +101,20 @@ export class RectSelect extends FSM {
bbox() {
return {x, y, w, h}
}
});
};
(typeof this.callback === 'function') && this.callback(s);
// TODO: remove these modes in the future
view.aladin.showReticle(true)
view.setCursor('default');
// execute general callback
if (view.callbacksByEventName) {
var callback = view.callbacksByEventName['select'];
if (view.aladin.callbacksByEventName) {
var callback = view.aladin.callbacksByEventName['select'];
if (typeof callback === "function") {
// !todo
let selectedObjects = view.selectObjects(this);
console.log(selectedObjects)
callback(selectedObjects);
let objList = Selector.getObjects(s, view);
callback(objList);
}
}
view.setMode(View.PAN)

View File

@@ -13,7 +13,7 @@ import { Utils } from './Utils';
export let GenericPointer = function (view, e) {
const xymouse = Utils.relMouseCoords(e);
let radec = view.aladin.pix2world(xymouse.x, xymouse.y);
let radec = view.aladin.pix2world(xymouse.x, xymouse.y, 'icrs');
if (radec) {
// sky case
if (view.aladin.getBaseImageLayer().isPlanetaryBody() === false) {
@@ -23,7 +23,7 @@ export let GenericPointer = function (view, e) {
// planetary body case
else {
// TODO: replace with actual value
const body = view.aladin.getBaseImageLayer().properties.hipsBody;
const body = view.aladin.getBaseImageLayer().hipsBody;
PlanetaryFeaturesPointer.query(radec[0], radec[1], Math.min(80, view.fov / 20.0), body, view.aladin);
}
} else {

View File

@@ -65,7 +65,6 @@ HiPSProperties.fetchFromID = async function(ID) {
// Exactly one matching
result = metadata[0];
}
return result;
}
}
@@ -74,7 +73,7 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
try {
urlOrId = new URL(urlOrId);
} catch (e) {
// Relative path
// Relative path test
try {
urlOrId = Utils.getAbsoluteURL(urlOrId)

View File

@@ -29,15 +29,11 @@
*****************************************************************************/
import { ALEvent } from "./events/ALEvent.js";
import { ColorCfg } from "./ColorCfg.js";
import { ImageLayer } from "./ImageLayer.js";
import { Utils } from "./Utils";
export let ImageFITS = (function () {
function ImageFITS(url, name, view, options, successCallback = undefined, errorCallback = undefined) {
this.view = view;
this.wasm = view.wasm;
function ImageFITS(url, name, options, successCallback = undefined, errorCallback = undefined) {
// Name of the layer
this.layer = null;
this.added = false;
@@ -46,110 +42,102 @@ export let ImageFITS = (function () {
this.url = url.toString();
this.id = url.toString();
this.name = name;
this.name = name || this.url;
this.imgFormat = "fits";
this.properties = {
formats: ["fits"]
}
this.formats = ["fits"]
// callbacks
this.successCallback = successCallback;
this.errorCallback = errorCallback;
// initialize the color meta data here
// set a asinh stretch by default if there is none
if (options) {
/*if (options) {
options.stretch = options.stretch || "asinh";
}
}*/
this.colorCfg = new ColorCfg(options);
let self = this;
updateMetadata(self);
ImageLayer.update(self);
this.query = Promise.resolve(self);
}
// A cache storing directly the images to not query for the properties each time
ImageFITS.cache = {};
ImageFITS.prototype.setView = function(view) {
this.view = view;
}
// @api
ImageFITS.prototype.setOpacity = function (opacity) {
let self = this;
updateMetadata(self, () => {
this._updateMetadata(() => {
self.colorCfg.setOpacity(opacity);
});
};
// @api
ImageFITS.prototype.setBlendingConfig = function (additive = false) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg.setBlendingConfig(additive);
});
};
// @api
ImageFITS.prototype.setColormap = function (colormap, options) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg.setColormap(colormap, options);
});
}
// @api
ImageFITS.prototype.setCuts = function (lowCut, highCut) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg.setCuts(lowCut, highCut);
});
};
// @api
ImageFITS.prototype.setGamma = function (gamma) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg.setGamma(gamma);
});
};
ImageFITS.prototype.getAvailableFormats = function() {
return this.properties.formats;
}
// @api
ImageFITS.prototype.setSaturation = function (saturation) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg.setSaturation(saturation);
});
};
ImageFITS.prototype.setBrightness = function (brightness) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg.setBrightness(brightness);
});
};
ImageFITS.prototype.setContrast = function (contrast) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg.setContrast(contrast);
});
};
ImageFITS.prototype.metadata = function () {
return {
...this.colorCfg.get(),
longitudeReversed: false,
imgFormat: this.imgFormat
};
}
// Private method for updating the view with the new meta
var updateMetadata = function (self, callback = undefined) {
ImageFITS.prototype._updateMetadata = function (callback) {
if (callback) {
callback();
}
// Tell the view its meta have changed
try {
if (self.added) {
const metadata = self.metadata();
self.wasm.setImageMetadata(self.layer, metadata);
ALEvent.HIPS_LAYER_CHANGED.dispatchedTo(self.view.aladinDiv, { layer: self });
if (this.added) {
this.view.wasm.setImageMetadata(this.layer, {
...this.colorCfg.get(),
longitudeReversed: false,
imgFormat: this.imgFormat
});
ALEvent.HIPS_LAYER_CHANGED.dispatchedTo(this.view.aladinDiv, { layer: this });
}
} catch (e) {
// Display the error message
@@ -161,13 +149,19 @@ export let ImageFITS = (function () {
this.layer = layer;
let self = this;
const promise = self.wasm.addImageFITS({
const promise = self.view.wasm.addImageFITS({
layer: self.layer,
url: self.url,
meta: self.metadata()
meta: {
...this.colorCfg.get(),
longitudeReversed: false,
imgFormat: this.imgFormat
}
}).then((imagesParams) => {
// There is at least one entry in imageParams
self.added = true;
self.children = [];
let hduIdx = 0;
@@ -176,7 +170,6 @@ export let ImageFITS = (function () {
let image = new ImageFITS(
imageParams.url,
self.name + "_ext_" + hduIdx.toString(),
self.view,
null,
null,
null
@@ -185,6 +178,7 @@ export let ImageFITS = (function () {
// Set the layer corresponding to the onein the backend
image.layer = imageParams.layer;
image.added = true;
image.setView(self.view);
// deep copy of the color object of self
image.colorCfg = Utils.deepCopy(self.colorCfg);
// Set the automatic computed cuts
@@ -259,7 +253,7 @@ export let ImageFITS = (function () {
ImageFITS.prototype.setAlpha = ImageFITS.prototype.setOpacity;
ImageFITS.prototype.setColorCfg = function (colorCfg) {
updateMetadata(this, () => {
this._updateMetadata(() => {
this.colorCfg = colorCfg;
});
};
@@ -283,7 +277,7 @@ export let ImageFITS = (function () {
// @api
ImageFITS.prototype.readPixel = function (x, y) {
return this.wasm.readPixel(x, y, this.layer);
return this.view.wasm.readPixel(x, y, this.layer);
};
return ImageFITS;

View File

@@ -1,218 +0,0 @@
export let ImageLayer = {};
ImageLayer.update = function (layer) {
const foundLayer = ImageLayer.contains(layer.id)
const options = layer.metadata;
// The survey has not been found among the ones cached
if (foundLayer) {
foundLayer.options = options;
} else {
ImageLayer.LAYERS.push({
id: layer.id,
name: layer.name,
url: layer.url,
options,
subtype: layer.subtype,
});
}
}
ImageLayer.contains = function(id) {
return ImageLayer.LAYERS.find((layer) => layer.id.endsWith(id));
}
ImageLayer.DEFAULT_SURVEY = {
id: "P/DSS2/color",
name: "DSS colored",
url: "https://alasky.cds.unistra.fr/DSS/DSSColor",
maxOrder: 9,
subtype: "survey",
tileSize: 512,
formats: ['jpeg'],
creatorDid: "ivo://CDS/P/DSS2/color",
dataproductSubtype: ['color'],
frame: "ICRS"
}
ImageLayer.LAYERS = [
ImageLayer.DEFAULT_SURVEY,
{
id: "P/2MASS/color",
name: "2MASS colored",
url: "https://alasky.cds.unistra.fr/2MASS/Color",
maxOrder: 9,
subtype: "survey",
},
{
id: "P/DSS2/red",
name: "DSS2 Red (F+R)",
url: "https://alasky.cds.unistra.fr/DSS/DSS2Merged",
maxOrder: 9,
subtype: "survey",
// options
options: {
minCut: 1000.0,
maxCut: 10000.0,
colormap: "magma",
stretch: 'Linear',
imgFormat: "fits"
}
},
{
id: "P/DM/I/350/gaiaedr3",
name: "Density map for Gaia EDR3 (I/350/gaiaedr3)",
url: "https://alasky.cds.unistra.fr/ancillary/GaiaEDR3/density-map",
maxOrder: 7,
subtype: "survey",
// options
options: {
minCut: 0,
maxCut: 12000,
stretch: 'asinh',
colormap: "rdylbu",
imgFormat: "fits",
}
},
{
id: "P/PanSTARRS/DR1/g",
name: "PanSTARRS DR1 g",
url: "https://alasky.cds.unistra.fr/Pan-STARRS/DR1/g",
maxOrder: 11,
subtype: "survey",
// options
options: {
minCut: -34,
maxCut: 7000,
stretch: 'asinh',
colormap: "redtemperature",
imgFormat: "fits",
}
},
{
id: "P/PanSTARRS/DR1/color-z-zg-g",
name: "PanSTARRS DR1 color",
url: "https://alasky.cds.unistra.fr/Pan-STARRS/DR1/color-z-zg-g",
maxOrder: 11,
subtype: "survey",
},
{
id: "P/DECaPS/DR1/color",
name: "DECaPS DR1 color",
url: "https://alasky.cds.unistra.fr/DECaPS/DR1/color",
maxOrder: 11,
subtype: "survey",
},
{
id: "P/Fermi/color",
name: "Fermi color",
url: "https://alasky.cds.unistra.fr/Fermi/Color",
maxOrder: 3,
subtype: "survey",
},
{
id: "P/Finkbeiner",
name: "Halpha",
url: "https://alasky.cds.unistra.fr/FinkbeinerHalpha",
maxOrder: 3,
subtype: "survey",
// options
options: {
minCut: -10,
maxCut: 800,
colormap: "rdbu",
imgFormat: "fits",
}
},
{
id: "P/GALEXGR6_7/NUV",
name: "GALEXGR6_7 NUV",
url: "http://alasky.cds.unistra.fr/GALEX/GALEXGR6_7_NUV/",
maxOrder: 8,
subtype: "survey",
},
{
id: "P/IRIS/color",
name: "IRIS colored",
url: "https://alasky.cds.unistra.fr/IRISColor",
maxOrder: 3,
subtype: "survey",
},
{
id: "P/Mellinger/color",
name: "Mellinger colored",
url: "https://alasky.cds.unistra.fr/MellingerRGB",
maxOrder: 4,
subtype: "survey",
},
{
id: "P/SDSS9/color",
name: "SDSS9 colored",
url: "https://alasky.cds.unistra.fr/SDSS/DR9/color",
maxOrder: 10,
subtype: "survey",
},
{
id: "P/SDSS9/g",
name: "SDSS9 band-g",
url: "https://alasky.cds.unistra.fr/SDSS/DR9/band-g",
maxOrder: 10,
subtype: "survey",
options: {
stretch: 'asinh',
colormap: "redtemperature",
imgFormat: 'fits'
}
},
{
id: "P/SPITZER/color",
name: "IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)",
url: "http://alasky.cds.unistra.fr/Spitzer/SpitzerI1I2I4color/",
maxOrder: 9,
subtype: "survey",
},
{
id: "P/VTSS/Ha",
name: "VTSS-Ha",
url: "https://alasky.cds.unistra.fr/VTSS/Ha",
maxOrder: 3,
subtype: "survey",
options: {
minCut: -10.0,
maxCut: 100.0,
colormap: "grayscale",
imgFormat: "fits"
}
},
{
id: "xcatdb/P/XMM/PN/color",
name: "XMM PN colored",
url: "https://alasky.cds.unistra.fr/cgi/JSONProxy?url=https://saada.unistra.fr/PNColor",
maxOrder: 7,
subtype: "survey",
},
{
id: "P/allWISE/color",
name: "AllWISE color",
url: "https://alasky.cds.unistra.fr/AllWISE/RGB-W4-W2-W1/",
maxOrder: 8,
subtype: "survey",
},
{
id: "P/GLIMPSE360",
name: "GLIMPSE360",
// This domain is not giving the CORS headers
// We need to query by with a proxy equipped with CORS header.
url: "https://alasky.cds.unistra.fr/cgi/JSONProxy?url=https://www.spitzer.caltech.edu/glimpse360/aladin/data",
subtype: "survey",
options: {
maxOrder: 9,
imgFormat: "jpg",
minOrder: 3,
}
},
];
ImageLayer.getAvailableLayers = function () {
return ImageLayer.LAYERS;
};

View File

@@ -30,14 +30,13 @@
import { Utils } from "./Utils";
import { ALEvent } from "./events/ALEvent.js";
import { ColorCfg } from "./ColorCfg.js";
import { ImageLayer } from "./ImageLayer.js";
import { HiPSProperties } from "./HiPSProperties.js";
let PropertyParser = {};
// Utilitary functions for parsing the properties and giving default values
/// Mandatory tileSize property
PropertyParser.tileSize = function(options, properties = {}) {
let tileSize = (options && options.tileSize) || (properties.hips_tile_width && (+properties.hips_tile_width)) || 512;
PropertyParser.tileSize = function(properties) {
let tileSize = (properties && properties.hips_tile_width && (+properties.hips_tile_width)) || 512;
// Check if the tile width size is a power of 2
if (tileSize & (tileSize - 1) !== 0) {
@@ -48,35 +47,25 @@ PropertyParser.tileSize = function(options, properties = {}) {
}
/// Mandatory frame property
PropertyParser.frame = function(options, properties = {}) {
let frame = (options && options.cooFrame) || (properties.hips_body && "ICRSd") || properties.hips_frame;
if (frame == "ICRS" || frame == "ICRSd" || frame == "equatorial" || frame == "j2000") {
frame = "ICRS";
} else if (frame == "galactic") {
frame = "GAL";
} else {
frame = "ICRS";
console.warn('Invalid cooframe given: ' + cooFrame + '. Coordinate systems supported: "ICRS", "ICRSd", "j2000" or "galactic". ICRS is chosen by default');
}
return frame;
PropertyParser.cooFrame = function(properties) {
let cooFrame = (properties && properties.hips_body && "ICRSd") || (properties && properties.hips_frame) || "ICRS";
return cooFrame;
}
/// Mandatory maxOrder property
PropertyParser.maxOrder = function(options, properties = {}) {
let maxOrder = (options && options.maxOrder) || (properties.hips_order && (+properties.hips_order));
PropertyParser.maxOrder = function(properties) {
let maxOrder = properties && properties.hips_order && (+properties.hips_order);
return maxOrder;
}
/// Mandatory minOrder property
PropertyParser.minOrder = function(options, properties = {}) {
const minOrder = (options && options.minOrder) || (properties.hips_order_min && (+properties.hips_order_min)) || 0;
PropertyParser.minOrder = function(properties) {
const minOrder = (properties && properties.hips_order_min && (+properties.hips_order_min)) || 0;
return minOrder;
}
PropertyParser.formats = function(options, properties = {}) {
let formats = properties.hips_tile_format || "jpeg";
PropertyParser.formats = function(properties) {
let formats = properties && properties.hips_tile_format || "jpeg";
formats = formats.split(' ')
.map((fmt) => fmt.toLowerCase());
@@ -84,8 +73,8 @@ PropertyParser.formats = function(options, properties = {}) {
return formats;
}
PropertyParser.initialFov = function(options, properties = {}) {
let initialFov = properties.hips_initial_fov && +properties.hips_initial_fov;
PropertyParser.initialFov = function(properties) {
let initialFov = properties && properties.hips_initial_fov && (+properties.hips_initial_fov);
if (initialFov && initialFov < 0.00002777777) {
initialFov = 360;
@@ -94,13 +83,13 @@ PropertyParser.initialFov = function(options, properties = {}) {
return initialFov;
}
PropertyParser.skyFraction = function(options, properties = {}) {
const skyFraction = (properties.moc_sky_fraction && (+properties.moc_sky_fraction)) || 0.0;
PropertyParser.skyFraction = function(properties) {
const skyFraction = (properties && properties.moc_sky_fraction && (+properties.moc_sky_fraction)) || 0.0;
return skyFraction;
}
PropertyParser.cutouts = function(options, properties = {}) {
let cuts = properties.hips_pixel_cut && properties.hips_pixel_cut.split(" ");
PropertyParser.cutouts = function(properties) {
let cuts = properties && properties.hips_pixel_cut && properties.hips_pixel_cut.split(" ");
const minCutout = cuts && parseFloat(cuts[0]);
const maxCutout = cuts && parseFloat(cuts[1]);
@@ -108,25 +97,32 @@ PropertyParser.cutouts = function(options, properties = {}) {
return [minCutout, maxCutout];
}
PropertyParser.bitpix = function(options, properties = {}) {
const bitpix = properties.hips_pixel_bitpix && (+properties.hips_pixel_bitpix);
PropertyParser.bitpix = function(properties) {
const bitpix = properties && properties.hips_pixel_bitpix && (+properties.hips_pixel_bitpix);
return bitpix;
}
PropertyParser.dataproductSubtype = function(options, properties = {}) {
let dataproductSubtype = properties.dataproduct_subtype || "color";
PropertyParser.dataproductSubtype = function(properties) {
let dataproductSubtype = (properties && properties.dataproduct_subtype) || "color";
dataproductSubtype = dataproductSubtype.split(" ")
.map((subtype) => subtype.toLowerCase());
return dataproductSubtype;
}
PropertyParser.isPlanetaryBody = function(options, properties = {}) {
return properties.hips_body !== undefined;
PropertyParser.isPlanetaryBody = function(properties) {
return properties && properties.hips_body !== undefined;
}
/**
* @typedef {Object} ImageSurveyOptions
*
* @property {string} [name] - The name of the survey to be displayed in the UI
* @property {string} [imgFormat] - Formats accepted 'webp', 'png', 'jpeg' or 'fits'. Will raise an error if the HiPS does not contain tiles in this format
* @property {CooFrame} [cooFrame="J2000"] - Coordinate frame of the survey tiles
* @property {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
* @property {number} [numBitsPerPixel] - useful if you want to display the FITS tiles of a HiPS. It specifies the number of bits per pixel. Possible values are:
* -64: double, -32: float, 8: unsigned byte, 16: short, 32: integer 32 bits, 64: integer 64 bits
* @property {number} [tileSize] - The width of the HEALPix tile images. Mostly 512 pixels for can be 256, 128, 64, 32
* @property {number} [opacity=1.0] - Opacity of the survey or image (value between 0 and 1).
* @property {string} [colormap="native"] - The colormap configuration for the survey or image.
* @property {string} [stretch="linear"] - The stretch configuration for the survey or image.
@@ -138,12 +134,9 @@ PropertyParser.isPlanetaryBody = function(options, properties = {}) {
* @property {number} [saturation=0.0] - The saturation value for the color configuration.
* @property {number} [brightness=0.0] - The brightness value for the color configuration.
* @property {number} [contrast=0.0] - The contrast value for the color configuration.
* @property {number} [maxOrder] - If not given, retrieved from the properties of the survey.
* @property {number} [minOrder] - If not given, retrieved from the properties of the survey.
* @property {boolean} [longitudeReversed=false] - Set it to True for planetary survey visualization
* @property {string} [imgFormat] - If not given, look into the properties to see the accepted format. The format is chosen from WEBP > PNG > JPEG > FITS (in this importance order).
* @property {string} [cooFrame] - If not given, look into the properties. If it is a planet, then ICRS is chosen, otherwise its hips_frame key is read. If no value is found in the properties, ICRS is chosen by default.
*/
*/
export let ImageSurvey = (function () {
/**
* The object describing an image survey
@@ -151,36 +144,57 @@ export let ImageSurvey = (function () {
* @class
* @constructs ImageSurvey
*
* @param {string} [id] - Optional, a uniq id for the survey. See {@link https://aladin.cds.unistra.fr/hips/list|here} for the list of IDs.
* Keep in mind that it is better to directly provide an url as it will not request our mocserver first to get final survey tiles retrieval url.
* @param {string} [name] - The name of the survey to be displayed in the UI
* @param {string} url - The url where the survey is located. Check the hips list {@link https://aladin.cds.unistra.fr/hips/list|here} for the valid survey urls to display.
* @param {string} id - Mandatory unique identifier for the layer.
* Can be an arbitrary name
* @param {string} url - Can be an url to the survey or a "CDS" ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}
* @param {ImageSurveyOptions} [options] - The option for the survey
*
* @description Prefer provide an url better than an id. If both are given, the url will be requested first for the survey data.
* @description For the `url` param, prefer provide an url better than an CDS ID. Giving a CDS ID will do a query to the mocserver more but will also check for the presence of faster HiPS nodes.
*/
function ImageSurvey(id, name, url, options, view) {
this.view = view;
function ImageSurvey(id, url, options) {
this.added = false;
// Unique identifier for a survey
this.id = id;
this.name = name;
this.name = options.name || id || url;
this.subtype = "survey";
this.properties = options.properties || {};
this.url = url;
this.maxOrder = options.maxOrder;
this.minOrder = options.minOrder || 0;
this.cooFrame = options.cooFrame;
this.tileSize = options.tileSize;
this.longitudeReversed = options.longitudeReversed === undefined ? false : options.longitudeReversed;
this.imgFormat = options.imgFormat;
this.numBitsPerPixel = options.numBitsPerPixel;
this.creatorDid = options.creatorDid;
this.colorCfg = new ColorCfg(options);
};
ImageSurvey.prototype.setView = function(view) {
let self = this;
self.query = (async () => {
if (!options.properties) {
let obsTitle, creatorDid, maxOrder, frame, tileSize, formats, minCutout, maxCutout, bitpix, skyFraction, minOrder, initialFov, initialRa, initialDec, hipsBody, isPlanetaryBody, dataproductSubtype;
self.view = view;
let isMOCServerToBeQueried = true;
if (this.imgFormat === 'fits') {
// a fits is given
isMOCServerToBeQueried = !(this.maxOrder && this.url && this.imgFormat && this.tileSize && this.cooFrame && this.numBitsPerPixel)
} else {
isMOCServerToBeQueried = !(this.maxOrder && this.url && this.imgFormat && this.tileSize && this.cooFrame);
}
self.query = (async () => {
if (isMOCServerToBeQueried) {
let properties;
let isCDSId = false;
try {
properties = await HiPSProperties.fetchFromUrl(url)
properties = await HiPSProperties.fetchFromUrl(self.url)
.catch(async (e) => {
// url not valid so we try with the id
try {
return await HiPSProperties.fetchFromID(id);
isCDSId = true;
return await HiPSProperties.fetchFromID(self.url);
} catch(e) {
throw e;
}
@@ -189,200 +203,201 @@ export let ImageSurvey = (function () {
throw e;
}
obsTitle = properties.obs_title;
creatorDid = properties.creator_did;
// Set it to a default value
if (!properties.hips_service_url) {
throw 'no valid service URL for retrieving the tiles'
if (isCDSId) {
self.url = properties.hips_service_url;
}
url = Utils.fixURLForHTTPS(properties.hips_service_url);
//obsTitle = properties.obs_title;
self.creatorDid = properties.creator_did || self.creatorDid;
// url
// Request all the properties to see which mirror is the fastest
HiPSProperties.getFasterMirrorUrl(properties)
.then((url) => {
self._setUrl(url);
})
.catch(e => {
//alert(e);
console.error(e);
// the survey has been added so we remove it from the stack
self.view.removeImageLayer(self.layer)
//throw e;
})
if (!self.url) {
self.url = properties.hips_service_url
if (!self.url) {
throw 'no valid service URL for retrieving the tiles'
}
self.url = Utils.fixURLForHTTPS(self.url);
// Request all the properties to see which mirror is the fastest
HiPSProperties.getFasterMirrorUrl(properties)
.then((url) => {
if (self.url !== url) {
console.info("Change url of ", self.id, " from ", self.url, " to ", url)
// If added to the backend, then we need to tell it the url has changed
if (self.added) {
self.view.wasm.setHiPSUrl(self.url, url);
}
self.url = url;
// save the new url to the cache
ImageSurvey.cache[self.id].url = self.url;
}
})
/*.catch(e => {
//alert(e);
console.error(e);
// the survey has been added so we remove it from the stack
self.view.removeImageLayer(self.layer)
//throw e;
})*/
}
// Max order
maxOrder = PropertyParser.maxOrder(options, properties);
self.maxOrder = PropertyParser.maxOrder(properties) || self.maxOrder;
// Tile size
tileSize = PropertyParser.tileSize(options, properties);
self.tileSize = PropertyParser.tileSize(properties) || self.tileSize;
// Tile formats
formats = PropertyParser.formats(options, properties);
self.formats = PropertyParser.formats(properties) || self.formats;
// min order
minOrder = PropertyParser.minOrder(options, properties);
self.minOrder = PropertyParser.minOrder(properties) || self.minOrder;
// Frame
frame = PropertyParser.frame(options, properties);
self.cooFrame = PropertyParser.cooFrame(properties) || self.cooFrame;
// sky fraction
skyFraction = PropertyParser.skyFraction(options, properties);
self.skyFraction = PropertyParser.skyFraction(properties);
// Initial fov/ra/dec
initialFov = PropertyParser.initialFov(options, properties);
initialRa = +properties.hips_initial_ra;
initialDec = +properties.hips_initial_dec;
self.initialFov = PropertyParser.initialFov(properties);
self.initialRa = properties && properties.hips_initial_ra && (+properties.hips_initial_ra);
self.initialDec = properties && properties.hips_initial_dec && (+properties.hips_initial_dec);
// Cutouts
[minCutout, maxCutout] = PropertyParser.cutouts(options, properties);
const cutoutFromProperties = PropertyParser.cutouts(properties);
self.minCut = cutoutFromProperties[0];
self.maxCut = cutoutFromProperties[1];
// Bitpix
bitpix = PropertyParser.bitpix(options, properties);
// Dataproduct subtype
dataproductSubtype = PropertyParser.dataproductSubtype(options, properties);
self.numBitsPerPixel = PropertyParser.bitpix(properties) || self.numBitsPerPixel;
// HiPS body
isPlanetaryBody = PropertyParser.isPlanetaryBody(options, properties);
if (properties.hips_body) {
hipsBody = properties.hips_body;
self.hipsBody = properties.hips_body;
// Use the property to define and check some user given infos
// Longitude reversed
self.longitudeReversed = true;
}
self.properties = {
creatorDid,
obsTitle,
url,
maxOrder,
frame,
tileSize,
formats,
minCutout,
maxCutout,
bitpix,
skyFraction,
minOrder,
hipsInitialFov: initialFov,
hipsInitialRa: initialRa,
hipsInitialDec: initialDec,
dataproductSubtype,
isPlanetaryBody,
hipsBody
};
// Give a better name if we have the HiPS metadata
self.name = self.name || properties.obsTitle;
self.cooFrame = properties.cooFrame || self.cooFrame;
}
// Give a better name if we have the HiPS metadata
self.name = self.name || self.properties.obsTitle;
// Use the property to define and check some user given infos
// Longitude reversed
let longitudeReversed = false;
if (options && options.longitudeReversed === true) {
longitudeReversed = true;
}
if (self.properties.hipsBody) {
longitudeReversed = true;
}
self.longitudeReversed = longitudeReversed;
self.creatorDid = self.creatorDid || self.id || self.url;
// Image format
let imgFormat = options && options.imgFormat;
if (imgFormat) {
if (self.imgFormat) {
// transform to lower case
imgFormat = imgFormat.toLowerCase();
self.imgFormat = self.imgFormat.toLowerCase();
// convert JPG -> JPEG
if (imgFormat === "jpg") {
imgFormat = "jpeg";
if (self.imgFormat === "jpg") {
self.imgFormat = "jpeg";
}
// user wants a fits but the properties tells this format is not available
if (imgFormat === "fits" && self.properties.formats && self.properties.formats.indexOf('fits') < 0) {
if (self.imgFormat === "fits" && self.formats && self.formats.indexOf('fits') < 0) {
throw self.name + " does not provide fits tiles";
}
if (imgFormat === "webp" && self.properties.formats && self.properties.formats.indexOf('webp') < 0) {
if (self.imgFormat === "webp" && self.formats && self.formats.indexOf('webp') < 0) {
throw self.name + " does not provide webp tiles";
}
if (imgFormat === "png" && self.properties.formats && self.properties.formats.indexOf('png') < 0) {
if (self.imgFormat === "png" && self.formats && self.formats.indexOf('png') < 0) {
throw self.name + " does not provide png tiles";
}
if (imgFormat === "jpeg" && self.properties.formats && self.properties.formats.indexOf('jpeg') < 0) {
if (self.imgFormat === "jpeg" && self.formats && self.formats.indexOf('jpeg') < 0) {
throw self.name + " does not provide jpeg tiles";
}
} else {
// user wants nothing then we choose one from the properties
if (self.properties.formats.indexOf('webp') >= 0) {
imgFormat = "webp";
} else if (self.properties.formats.indexOf('png') >= 0) {
imgFormat = "png";
} else if (self.properties.formats.indexOf('jpeg') >= 0) {
imgFormat = "jpeg";
} else if (self.properties.formats.indexOf('fits') >= 0) {
imgFormat = "fits";
if (self.formats.indexOf('webp') >= 0) {
self.imgFormat = "webp";
} else if (self.formats.indexOf('png') >= 0) {
self.imgFormat = "png";
} else if (self.formats.indexOf('jpeg') >= 0) {
self.imgFormat = "jpeg";
} else if (self.formats.indexOf('fits') >= 0) {
self.imgFormat = "fits";
} else {
throw "Unsupported format(s) found in the properties: " + self.properties.formats;
throw "Unsupported format(s) found in the properties: " + self.formats;
}
}
self.imgFormat = imgFormat;
// Initialize the color meta data here
// Cutouts
let minCut, maxCut;
if (imgFormat === "fits") {
if (self.imgFormat === "fits") {
// Take into account the default cuts given by the property file (this is true especially for FITS HiPSes)
minCut = self.colorCfg.minCut || (options && options.minCut) || self.properties.minCutout || 0.0;
maxCut = self.colorCfg.maxCut || (options && options.maxCut) || self.properties.maxCutout || 1.0;
minCut = self.colorCfg.minCut || self.minCut || 0.0;
maxCut = self.colorCfg.maxCut || self.maxCut || 1.0;
} else {
minCut = self.colorCfg.minCut || (options && options.minCut) || 0.0;
maxCut = self.colorCfg.maxCut || (options && options.maxCut) || 1.0;
minCut = self.colorCfg.minCut || 0.0;
maxCut = self.colorCfg.maxCut || 1.0;
}
self.colorCfg.setCuts(minCut, maxCut);
ImageLayer.update(self);
// Coo frame
if (self.cooFrame == "ICRS" || self.cooFrame == "ICRSd" || self.cooFrame == "equatorial" || self.cooFrame == "j2000") {
self.cooFrame = "ICRS";
} else if (self.cooFrame == "galactic") {
self.cooFrame = "GAL";
} else {
self.cooFrame = "ICRS";
console.warn('Invalid cooframe given: ' + self.cooFrame + '. Coordinate systems supported: "ICRS", "ICRSd", "j2000" or "galactic". ICRS is chosen by default');
}
self.formats = self.formats || [self.imgFormat];
self._save();
return self;
})();
};
ImageSurvey.fromLayerOptions = function(aladin, options) {
return new ImageSurvey(
options.id,
options.name,
options.url,
{
properties: options,
...options.options
},
aladin.view
);
}
ImageSurvey.prototype._setUrl = function (url) {
if (this.properties.url !== url) {
console.info("Change url of ", this.id, " from ", this.properties.url, " to ", url)
ImageSurvey.prototype._save = function() {
let self = this;
// If added to the backend, then we need to tell it the url has changed
if (this.added) {
this.view.wasm.setHiPSUrl(this.properties.url, url);
}
this.properties.url = url;
let surveyOpt = {
creatorDid: self.creatorDid,
name: self.name,
url: self.url,
cooFrame: self.cooFrame,
maxOrder: self.maxOrder,
tileSize: self.tileSize,
imgFormat: self.imgFormat,
}
}
if (self.numBitsPerPixel) {
surveyOpt.numBitsPerPixel = self.numBitsPerPixel;
}
ImageSurvey.cache[self.id] = {
// Erase by the cache already put values which is considered
// as the ground truth
...ImageSurvey.cache[self.id],
// append new important infos from the properties queried
...surveyOpt,
}
}
/**
* Checks if the ImageSurvey represents a planetary body.
*
* This method returns a boolean indicating whether the ImageSurvey corresponds to a planetary body, e.g. the earth or a celestial body.
*
* @memberof ImageSurvey
*
* @returns {boolean} Returns true if the ImageSurvey represents a planetary body; otherwise, returns false.
*/
* Checks if the ImageSurvey represents a planetary body.
*
* This method returns a boolean indicating whether the ImageSurvey corresponds to a planetary body, e.g. the earth or a celestial body.
*
* @memberof ImageSurvey
*
* @returns {boolean} Returns true if the ImageSurvey represents a planetary body; otherwise, returns false.
*/
ImageSurvey.prototype.isPlanetaryBody = function() {
return this.properties.isPlanetaryBody;
return self.hipsBody !== undefined;;
}
/**
@@ -419,7 +434,7 @@ export let ImageSurvey = (function () {
// Check the properties to see if the given format is available among the list
// If the properties have not been retrieved yet, it will be tested afterwards
const availableFormats = self.properties.formats;
const availableFormats = self.formats;
// user wants a fits but the metadata tells this format is not available
if (imgFormat === "fits" && availableFormats.indexOf('fits') < 0) {
throw self.id + " does not provide fits tiles";
@@ -439,8 +454,8 @@ export let ImageSurvey = (function () {
// Switch from png/webp/jpeg to fits
if ((self.imgFormat === 'png' || self.imgFormat === "webp" || self.imgFormat === "jpeg") && imgFormat === 'fits') {
if (self.properties.minCutout && self.properties.maxCutout) {
self.setCuts(self.properties.minCutout, self.properties.maxCutout)
if (self.minCut && self.maxCut) {
self.setCuts(self.minCut, self.maxCut)
}
// Switch from fits to png/webp/jpeg
} else if (self.imgFormat === "fits") {
@@ -453,7 +468,7 @@ export let ImageSurvey = (function () {
})
};
/**
/**
* Sets the opacity factor when rendering the ImageSurvey
*
* @memberof ImageSurvey
@@ -461,7 +476,7 @@ export let ImageSurvey = (function () {
* @returns {string[]} Returns the formats accepted for the survey, i.e. the formats of tiles that are availables. Could be PNG, WEBP, JPG and FITS.
*/
ImageSurvey.prototype.getAvailableFormats = function() {
return this.properties.formats;
return this.formats;
}
/**
@@ -624,14 +639,12 @@ export let ImageSurvey = (function () {
// Tell the view its meta have changed
try {
this.metadata = {
...this.colorCfg.get(),
longitudeReversed: this.longitudeReversed,
imgFormat: this.imgFormat
};
if (this.added) {
this.view.wasm.setImageMetadata(this.layer, this.metadata);
this.view.wasm.setImageMetadata(this.layer, {
...this.colorCfg.get(),
longitudeReversed: this.longitudeReversed,
imgFormat: this.imgFormat
});
// once the meta have been well parsed, we can set the meta
ALEvent.HIPS_LAYER_CHANGED.dispatchedTo(this.view.aladinDiv, { layer: this });
}
@@ -643,17 +656,31 @@ export let ImageSurvey = (function () {
ImageSurvey.prototype.add = function (layer) {
this.layer = layer;
this.metadata = {
...this.colorCfg.get(),
longitudeReversed: this.longitudeReversed,
imgFormat: this.imgFormat
};
let self = this;
this.view.wasm.addImageSurvey({
layer,
properties: this.properties,
meta: this.metadata,
properties: {
creatorDid: self.creatorDid,
url: self.url,
maxOrder: self.maxOrder,
cooFrame: self.cooFrame,
tileSize: self.tileSize,
formats: self.formats,
bitpix: self.numBitsPerPixel,
skyFraction: self.skyFraction,
minOrder: self.minOrder,
hipsInitialFov: self.initialFov,
hipsInitialRa: self.initialRa,
hipsInitialDec: self.initialDec,
isPlanetaryBody: self.isPlanetaryBody(),
hipsBody: self.hipsBody
},
meta: {
...this.colorCfg.get(),
longitudeReversed: this.longitudeReversed,
imgFormat: this.imgFormat
},
});
this.added = true;
@@ -696,7 +723,203 @@ export let ImageSurvey = (function () {
return this.view.wasm.readPixel(x, y, this.layer);
};
ImageSurvey.DEFAULT_SURVEY_ID = "P/DSS2/color";
ImageSurvey.DEFAULT_SURVEY_ID = "DSS2_color";
// A cache storing directly surveys important information to not query for the properties each time
ImageSurvey.cache = {
DSS2_color: {
creatorDid: "ivo://CDS/P/DSS2/color",
name: "DSS colored",
url: "https://alasky.cds.unistra.fr/DSS/DSSColor",
maxOrder: 9,
tileSize: 512,
imgFormat: 'jpeg',
cooFrame: "ICRS"
},
MASS2_color: {
creatorDid: "ivo://CDS/P/2MASS/color",
name: "2MASS colored",
url: "https://alasky.cds.unistra.fr/2MASS/Color",
maxOrder: 9,
tileSize: 512,
imgFormat: 'jpeg',
cooFrame: "ICRS"
},
DSS2_red: {
creatorDid: "ivo://CDS/P/DSS2/red",
name: "DSS2 Red (F+R)",
url: "https://alasky.cds.unistra.fr/DSS/DSS2Merged",
maxOrder: 9,
tileSize: 512,
imgFormat: 'fits',
cooFrame: "ICRS",
numBitsPerPixel: 16,
// options
minCut: 1000.0,
maxCut: 10000.0,
colormap: "magma",
stretch: 'Linear',
imgFormat: "fits"
},
GAIA_EDR3: {
creatorDid: "ivo://CDS/P/DM/I/350/gaiaedr3",
name: "Density map for Gaia EDR3 (I/350/gaiaedr3)",
url: "https://alasky.cds.unistra.fr/ancillary/GaiaEDR3/density-map",
maxOrder: 7,
tileSize: 512,
numBitsPerPixel: -32,
cooFrame: "ICRS",
minCut: 0,
maxCut: 12000,
stretch: 'asinh',
colormap: "rdylbu",
imgFormat: "fits",
},
PanSTARRS_DR1_g: {
creatorDid: "ivo://CDS/P/PanSTARRS/DR1/g",
name: "PanSTARRS DR1 g",
url: "https://alasky.cds.unistra.fr/Pan-STARRS/DR1/g",
maxOrder: 11,
tileSize: 512,
imgFormat: 'fits',
cooFrame: "ICRS",
numBitsPerPixel: -32,
// options
minCut: -34,
maxCut: 7000,
stretch: 'asinh',
colormap: "redtemperature",
},
PanSTARRS_DR1_color: {
creatorDid: "ivo://CDS/P/PanSTARRS/DR1/color-z-zg-g",
name: "PanSTARRS DR1 color",
url: "https://alasky.cds.unistra.fr/Pan-STARRS/DR1/color-z-zg-g",
maxOrder: 11,
tileSize: 512,
imgFormat: 'jpeg',
cooFrame: "ICRS",
},
DECaPS_DR2_color: {
creatorDid: "ivo://CDS/P/DECaPS/DR2/color",
name: "DECaPS DR2 color",
url: "https://alasky.cds.unistra.fr/DECaPS/DR2/CDS_P_DECaPS_DR2_color/",
maxOrder: 11,
cooFrame: "equatorial",
tileSize: 512,
imgFormat: 'png',
},
Fermi_color: {
creatorDid: "ivo://CDS/P/Fermi/color",
name: "Fermi color",
url: "https://alasky.cds.unistra.fr/Fermi/Color",
maxOrder: 3,
imgFormat: 'jpeg',
tileSize: 512,
cooFrame: 'equatorial'
},
/*
{
id: "P/Finkbeiner",
name: "Halpha",
url: "https://alasky.cds.unistra.fr/FinkbeinerHalpha",
maxOrder: 3,
subtype: "survey",
// options
options: {
minCut: -10,
maxCut: 800,
colormap: "rdbu",
imgFormat: "fits",
}
},
{
id: "P/GALEXGR6_7/NUV",
name: "GALEXGR6_7 NUV",
url: "http://alasky.cds.unistra.fr/GALEX/GALEXGR6_7_NUV/",
maxOrder: 8,
subtype: "survey",
},
{
id: "P/IRIS/color",
name: "IRIS colored",
url: "https://alasky.cds.unistra.fr/IRISColor",
maxOrder: 3,
subtype: "survey",
},
{
id: "P/Mellinger/color",
name: "Mellinger colored",
url: "https://alasky.cds.unistra.fr/MellingerRGB",
maxOrder: 4,
subtype: "survey",
},
{
id: "P/SDSS9/color",
name: "SDSS9 colored",
url: "https://alasky.cds.unistra.fr/SDSS/DR9/color",
maxOrder: 10,
subtype: "survey",
},
{
id: "P/SDSS9/g",
name: "SDSS9 band-g",
url: "https://alasky.cds.unistra.fr/SDSS/DR9/band-g",
maxOrder: 10,
subtype: "survey",
options: {
stretch: 'asinh',
colormap: "redtemperature",
imgFormat: 'fits'
}
},
{
id: "P/SPITZER/color",
name: "IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)",
url: "http://alasky.cds.unistra.fr/Spitzer/SpitzerI1I2I4color/",
maxOrder: 9,
subtype: "survey",
},
{
id: "P/VTSS/Ha",
name: "VTSS-Ha",
url: "https://alasky.cds.unistra.fr/VTSS/Ha",
maxOrder: 3,
subtype: "survey",
options: {
minCut: -10.0,
maxCut: 100.0,
colormap: "grayscale",
imgFormat: "fits"
}
},
{
id: "xcatdb/P/XMM/PN/color",
name: "XMM PN colored",
url: "https://alasky.cds.unistra.fr/cgi/JSONProxy?url=https://saada.unistra.fr/PNColor",
maxOrder: 7,
subtype: "survey",
},
{
id: "P/allWISE/color",
name: "AllWISE color",
url: "https://alasky.cds.unistra.fr/AllWISE/RGB-W4-W2-W1/",
maxOrder: 8,
subtype: "survey",
},
{
id: "P/GLIMPSE360",
name: "GLIMPSE360",
// This domain is not giving the CORS headers
// We need to query by with a proxy equipped with CORS header.
url: "https://alasky.cds.unistra.fr/cgi/JSONProxy?url=https://www.spitzer.caltech.edu/glimpse360/aladin/data",
subtype: "survey",
options: {
maxOrder: 9,
imgFormat: "jpg",
minOrder: 3,
}
},*/
};
return ImageSurvey;
})();

View File

@@ -92,12 +92,10 @@ export class Selector {
return;
}
var objList = [];
var cat, sources, s;
var footprints, f;
var objListPerCatalog = [];
if (view.catalogs) {
for (var k = 0; k < view.catalogs.length; k++) {
cat = view.catalogs[k];
@@ -133,6 +131,9 @@ export class Selector {
}
}
console.log(objList)
return objList;
}
}

View File

@@ -50,10 +50,8 @@ import { ObsCore } from "./vo/ObsCore.js";
import { DefaultActionsForContextMenu } from "./DefaultActionsForContextMenu.js";
import { Layout } from "./gui/Layout.js";
import { SAMPActionButton } from "./gui/Button/SAMP.js";
import { Icon } from "./gui/Widgets/Icon.js";
import openerIconUrl from '../../assets/icons/loading.svg'
import { ImageSurvey } from "./ImageSurvey.js";
import { ImageLayer } from "./ImageLayer.js";
import { ImageFITS } from "./ImageFITS.js";
export let View = (function () {
@@ -84,9 +82,6 @@ export let View = (function () {
callback(self.wasm);
});
// Retrieve all the possible colormaps
ColorCfg.COLORMAPS = this.wasm.getAvailableColormapList();
} catch (e) {
// For browsers not supporting WebGL2:
// 1. Print the original exception message in the console
@@ -128,7 +123,6 @@ export let View = (function () {
this.aladinDiv.ondragover = Utils.dragOverHandler;
//this.location = location;
this.mustClearCatalog = true;
this.mode = View.PAN;
@@ -139,18 +133,8 @@ export let View = (function () {
var lon, lat;
lon = lat = 0;
this.projection = ProjectionEnum.SIN;
this.viewCenter = { lon: lon, lat: lat }; // position of center of view
this.cooFrame = CooFrameEnum.fromString(this.options.cooFrame, CooFrameEnum.J2000);
// Frame setting
this.changeFrame(this.cooFrame);
this.selector = new Selector(this);
// Zoom starting setting
// FoV init settings
const si = 500000.0;
const alpha = 40.0;
let initialFov = this.options.fov || 180.0;
@@ -160,7 +144,23 @@ export let View = (function () {
initialDistance: undefined,
initialAccDelta: Math.pow(si / initialFov, 1.0 / alpha)
};
// Projection definition
const projName = (this.options && this.options.projection) || "SIN";
this.setProjection(projName)
// Then set the zoom properly once the projection is defined
this.setZoom(initialFov);
// Target position settings
this.viewCenter = { lon, lat }; // position of center of view
// Coo frame setting
const cooFrame = CooFrameEnum.fromString(this.options.cooFrame, CooFrameEnum.J2000);
this.changeFrame(cooFrame);
this.selector = new Selector(this);
// current reference image survey displayed
this.imageLayers = new Map();
@@ -631,13 +631,9 @@ export let View = (function () {
// Take as start cut values what is inside the properties
// If the cuts are not defined in the metadata of the survey
// then we take what has been defined by the user
if (imageLayer.imgFormat === "fits") {
cutMinInit = imageLayer.properties.minCutout || imageLayer.getColorCfg().minCut || 0.0;
cutMaxInit = imageLayer.properties.maxCutout || imageLayer.getColorCfg().maxCut || 1.0;
} else {
cutMinInit = imageLayer.getColorCfg().minCut || 0.0;
cutMaxInit = imageLayer.getColorCfg().maxCut || 1.0;
}
cutMinInit = imageLayer.getColorCfg().minCut || 0.0;
cutMaxInit = imageLayer.getColorCfg().maxCut || 1.0;
}
}
@@ -1353,6 +1349,7 @@ export let View = (function () {
this.selection = Selector.getObjects(selection, this);
}
if (this.selection.length > 0) {
this.selection.forEach((objListPerCatalog) => {
objListPerCatalog.forEach((obj) => obj.select())
@@ -1535,6 +1532,10 @@ export let View = (function () {
};
View.prototype.setOverlayImageLayer = function (imageLayer, layer = "overlay") {
// set the view to the image layer object
// do the properties query if needed
imageLayer.setView(this);
// register its promise
this.imageLayersBeingQueried.set(layer, imageLayer);
@@ -1604,13 +1605,17 @@ export let View = (function () {
}
// change the view frame in case we have a planetary hips loaded
if (imageLayer.properties.hipsBody) {
if (imageLayer.hipsBody) {
if (this.options.showFrame) {
this.aladin.setFrame('J2000d');
}
}
})
.catch((e) => {
// remove it from the cache
delete ImageSurvey.cache[imageLayer.id]
delete ImageFITS.cache[imageLayer.id]
throw e;
})
.finally(() => {
@@ -1629,9 +1634,7 @@ export let View = (function () {
if (noMoreLayersToWaitFor) {
if (self.empty) {
// no promises to launch!
const dssLayerOptions = ImageLayer.DEFAULT_SURVEY
self.aladin.setBaseImageLayer(ImageSurvey.fromLayerOptions(self, dssLayerOptions));
//self.aladin.setBaseImageLayer(self.aladin.createImageSurvey(ImageSurvey.DEFAULT_SURVEY_ID));
} else {
// there is surveys that have been queried
// rename the first overlay layer to "base"
@@ -1758,7 +1761,7 @@ export let View = (function () {
projName = 'SIN'
}
if (this.projection.id === ProjectionEnum[projName].id) {
if (this.projection && this.projection.id === ProjectionEnum[projName].id) {
return;
}

View File

@@ -248,9 +248,12 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
if (self.box) {
self.box.remove();
}
self.box = new ConeSearchBox(aladin);
// output the resulting cone search in the icrs frame
self.box = new ConeSearchBox(aladin, {frame: 'icrs'});
self.box.attach({
callback: (cs) => {
// the cone search services are asking for
self.fnIdSelected('coneSearch', {
baseURL: self.selectedItem.cs_service_url,
id: self.selectedItem.ID,

View File

@@ -33,7 +33,7 @@ import { Angle } from "../../libs/astro/angle.js";
*****************************************************************************/
export class ConeSearchBox extends Box {
constructor(aladin) {
constructor(aladin, options) {
let self;
let selectorBtn = new ConeSearchActionButton({
tooltip: {content: 'Select the area to query the catalogue with', position: {direction: 'left'}},
@@ -43,8 +43,8 @@ import { Angle } from "../../libs/astro/angle.js";
action(circle) {
// convert to ra, dec and radius in deg
try {
let [ra, dec] = aladin.pix2world(circle.x, circle.y);
let radius = aladin.angularDist(circle.x, circle.y, circle.x + circle.r, circle.y);
let [ra, dec] = aladin.pix2world(circle.x, circle.y, options.frame);
let radius = aladin.angularDist(circle.x, circle.y, circle.x + circle.r, circle.y, options.frame);
//var hlon = this.lon/15.0;
//var strlon = Numbers.toSexagesimal(hlon, this.prec+1, false);
@@ -160,8 +160,6 @@ import { Angle } from "../../libs/astro/angle.js";
aladin.aladinDiv
)
// hide by default
//console.log("hide cone search")
this._hide();
self = this;

View File

@@ -43,8 +43,8 @@ export class ConeSearchActionButton extends ActionButton {
// Constructor
constructor(options, aladin) {
super({
size: 'medium',
icon: {
size: 'medium',
monochrome: true,
url: targetIconUrl
},
@@ -65,7 +65,5 @@ export class ConeSearchActionButton extends ActionButton {
})
}
})
this.addClass('medium-sized-icon')
}
}

View File

@@ -44,10 +44,10 @@ import hideIconUrl from '../../../../assets/icons/hide.svg';
import removeIconUrl from '../../../../assets/icons/remove.svg';
import editIconUrl from '../../../../assets/icons/edit.svg';
import { ImageFITS } from "../../ImageFITS.js";
import { ImageLayer } from "../../ImageLayer.js";
import searchIconImg from '../../../../assets/icons/search.svg';
import { TogglerActionButton } from "../Button/Toggler.js";
import { Icon } from "../Widgets/Icon.js";
import { ImageSurvey } from "../../ImageSurvey.js";
export class OverlayStack extends ContextMenu {
static previewImagesUrl = {
@@ -293,10 +293,11 @@ export class OverlayStack extends ContextMenu {
self._hide();
self.aladin.select('circle', c => {
let [ra, dec] = self.aladin.pix2world(c.x, c.y);
let [ra, dec] = self.aladin.pix2world(c.x, c.y, 'j2000');
let radius = self.aladin.angularDist(c.x, c.y, c.x + c.r, c.y);
if (ra && dec && radius) {
// the moc needs a
let moc = A.MOCFromCircle(
{ra, dec, radius},
{name: 'cone', lineWidth: 3.0},
@@ -321,10 +322,10 @@ export class OverlayStack extends ContextMenu {
self.aladin.select('rect', r => {
try {
let [ra1, dec1] = self.aladin.pix2world(r.x, r.y);
let [ra2, dec2] = self.aladin.pix2world(r.x + r.w, r.y);
let [ra3, dec3] = self.aladin.pix2world(r.x + r.w, r.y + r.h);
let [ra4, dec4] = self.aladin.pix2world(r.x, r.y + r.h);
let [ra1, dec1] = self.aladin.pix2world(r.x, r.y, 'j2000');
let [ra2, dec2] = self.aladin.pix2world(r.x + r.w, r.y, 'j2000');
let [ra3, dec3] = self.aladin.pix2world(r.x + r.w, r.y + r.h, 'j2000');
let [ra4, dec4] = self.aladin.pix2world(r.x, r.y + r.h, 'j2000');
let moc = A.MOCFromPolygon(
{
@@ -356,7 +357,7 @@ export class OverlayStack extends ContextMenu {
let ra = []
let dec = []
for (const v of p.vertices) {
let [lon, lat] = self.aladin.pix2world(v.x, v.y);
let [lon, lat] = self.aladin.pix2world(v.x, v.y, 'j2000');
ra.push(lon)
dec.push(lat)
}
@@ -528,15 +529,19 @@ export class OverlayStack extends ContextMenu {
return;
}*/
const defaultLayers = ImageLayer.LAYERS.sort(function (a, b) {
const defaultLayers = Object.entries(ImageSurvey.cache).sort(function (e1, e2) {
let a = e1[1]
let b = e2[1]
if (!a.order) {
return a.name > b.name ? 1 : -1;
}
return a.maxOrder && a.maxOrder > b.maxOrder ? 1 : -1;
});
for(const layer of layers) {
let backgroundUrl = layer.properties.url + '/preview.jpg';
let backgroundUrl = layer.url + '/preview.jpg';
let cssStyle = {
height: 'fit-content',
};
@@ -597,7 +602,6 @@ export class OverlayStack extends ContextMenu {
self._hide();
console.log("kjkj")
//self.aladin.selectLayer(layer.layer);
//self.attach()
@@ -618,35 +622,35 @@ export class OverlayStack extends ContextMenu {
tooltip: {content: 'Add coverage', position: {direction: 'bottom'}},
toggled: (() => {
let overlays = self.aladin.getOverlays();
let found = overlays.find((o) => o.type === "moc" && o.name === layer.properties.obsTitle);
let found = overlays.find((o) => o.type === "moc" && o.name === layer.name);
return found !== undefined;
})(),
actionOn: (e) => {
let moc = A.MOCFromURL(layer.properties.url + '/Moc.fits', {lineWidth: 3, name: layer.properties.obsTitle});
let moc = A.MOCFromURL(layer.url + '/Moc.fits', {lineWidth: 3, name: layer.name});
self.aladin.addMOC(moc);
self.mocHiPSUrls[layer.properties.url] = moc;
self.mocHiPSUrls[layer.url] = moc;
loadMOCBtn.update({tooltip: {content: 'Remove coverage', position: {direction: 'bottom'}}})
if (self.aladin.statusBar) {
self.aladin.statusBar.appendMessage({
message: 'Coverage of ' + layer.properties.obsTitle + ' loaded',
message: 'Coverage of ' + layer.name + ' loaded',
duration: 2000,
type: 'info'
})
}
},
actionOff: (e) => {
let moc = self.mocHiPSUrls[layer.properties.url];
let moc = self.mocHiPSUrls[layer.url];
self.aladin.removeLayer(moc)
delete self.mocHiPSUrls[layer.properties.url];
delete self.mocHiPSUrls[layer.url];
loadMOCBtn.update({tooltip: {content: 'Add coverage', position: {direction: 'bottom'}}})
if (self.aladin.statusBar) {
self.aladin.statusBar.appendMessage({
message: 'Coverage of ' + layer.properties.obsTitle + ' removed',
message: 'Coverage of ' + layer.name + ' removed',
duration: 2000,
type: 'info'
})
@@ -697,7 +701,7 @@ export class OverlayStack extends ContextMenu {
l.subMenu = [];
for(let ll of defaultLayers) {
for(const [id, ll] of defaultLayers) {
backgroundUrl = OverlayStack.previewImagesUrl[ll.name];
if (!backgroundUrl) {
backgroundUrl = ll.url + '/preview.jpg'
@@ -718,31 +722,7 @@ export class OverlayStack extends ContextMenu {
label: '<div style="background-color: rgba(0, 0, 0, 0.6); padding: 3px; border-radius: 3px">' + ll.name + '</div>',
cssStyle,
action(e) {
let cfg = ImageLayer.LAYERS.find((l) => l.name === ll.name);
let newLayer;
// Max order is specific for surveys
if (cfg.subtype === "fits") {
// FITS
newLayer = self.aladin.createImageFITS(
cfg.url,
cfg.name,
cfg.options,
);
} else {
// HiPS
newLayer = self.aladin.createImageSurvey(
cfg.id,
cfg.name,
cfg.url,
undefined,
cfg.maxOrder,
cfg.options
);
}
self.aladin.setOverlayImageLayer(newLayer, layer.layer);
//self._hide();
self.aladin.setOverlayImageLayer(id, layer.layer);
},
hover(e, item) {
item.style.filter = 'brightness(1.5)';
@@ -806,11 +786,11 @@ export class OverlayStack extends ContextMenu {
return;
}
if (!layer.properties || !layer.properties.creatorDid) {
if (!layer.creatorDid) {
return;
}
const creatorDid = layer.properties.creatorDid;
const creatorDid = layer.creatorDid;
for (const key in Stack.previewImagesUrl) {
if (creatorDid.includes(key)) {
@@ -818,7 +798,7 @@ export class OverlayStack extends ContextMenu {
}
}
// if not found
return layer.properties.url + '/preview.jpg'
return layer.url + '/preview.jpg'
}
_addOverlayIcon(overlay) {

View File

@@ -46,7 +46,7 @@
value: cooFrame.label,
options: [CooFrameEnum.J2000.label, CooFrameEnum.J2000d.label, CooFrameEnum.GAL.label],
change(e) {
self.setFrame(e.target.value)
aladin.setFrame(e.target.value)
},
classList: ['aladin-cooFrame'],
tooltip: {
@@ -67,7 +67,6 @@
let self = this;
ALEvent.FRAME_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
let frame = e.detail.cooFrame;
console.log(frame, e)
self.update({
value: frame.label

View File

@@ -67,10 +67,6 @@ export class Input extends DOMElement {
_show() {
this.el.innerHTML = '';
if (this.options.classList) {
this.addClass(this.options.classList)
}
if (this.options.type === "checkbox") {
this.el.type = this.options.type;
@@ -214,6 +210,10 @@ export class Input extends DOMElement {
Tooltip.add(this.options.tooltip, this)
}
if (this.options.classList) {
this.element().classList.add(this.options.classList)
}
/*// Add padding for inputs except color ones
if (Utils.hasTouchScreen() && this.options.type !== "color") {
// Add a little padding

View File

@@ -75,8 +75,9 @@ export class SelectorButton extends DOMElement {
if (id === 'selected' || this.options.selected === id || id === 'tooltip') {
continue;
}
let optSelect = this.options[id];
console.log(optSelect)
menuOptions.push({
label: new ActionButton(optSelect),
action(e) {
@@ -85,6 +86,8 @@ export class SelectorButton extends DOMElement {
}
self.update({selected: id});
self._show();
self.fsm.dispatch('closeCtxMenu')
}
})
@@ -133,6 +136,7 @@ export class SelectorButton extends DOMElement {
// remove from the DOM tree
const selectedId = this.options.selected;
let {target, position} = this.remove();
this.el = new ActionButton({
...this.options[selectedId],

View File

@@ -1,182 +0,0 @@
// Copyright 2023 - UDS/CNRS
// The Aladin Lite program is distributed under the terms
// of the GNU General Public License version 3.
//
// This file is part of Aladin Lite.
//
// Aladin Lite is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Aladin Lite is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available in COPYING file
// along with Aladin Lite.
//
import { Layout } from "../Layout";
import { Utils } from "../../Utils";
/******************************************************************************
* Aladin Lite project
*
* File gui/Widgets/layout/Horizontal.js
*
* A layout grouping widgets horizontaly
*
*
* Author: Matthieu Baumann[CDS]
*
*****************************************************************************/
/*{
direction: 'vertical' | 'horizontal',
cssStyle: {...}
position: {
top,
left
} \ {
container: NodeElement
anchor: 'left top' |
'left center' |
'left bottom' |
'right top' |
'right center' |
'right bottom' |
'center top' |
'center center' |
'center bottom'
}
}
}*/
export class Toolbar extends Layout {
/**
* Create a layout
* @param {layout: Array.<DOMElement | String>, cssStyle: Object} options - Represents the structure of the Tabs
* @param {DOMElement} target - The parent element.
* @param {String} position - The position of the tabs layout relative to the target.
* For the list of possibilities, see https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
*/
constructor(options) {
options.orientation = options.orientation || 'horizontal';
options.position = options.position || {anchor: 'left top'};
if (!!options.direction === false) {
if (options.orientation === 'horizontal') {
// top or bottom
if (options.position.anchor && options.position.anchor.includes('top')) {
options.direction = 'bottom'
} else {
options.direction = 'top'
}
} else {
// left or right
if (options.position.anchor && options.position.anchor.includes('left')) {
options.direction = 'right'
} else {
options.direction = 'left'
}
}
}
options.layout = options.layout || [];
super(options)
this.addClass(options.direction);
this.tools = {};
}
update(options) {
if (options.direction) {
this.removeClass('left');
this.removeClass('right');
this.removeClass('top');
this.removeClass('bottom');
this.addClass(options.direction)
// search for a tooltip
/*this.el.querySelectorAll(".aladin-tooltip-container")
.forEach((t) => {
t.classList.remove('left');
t.classList.remove('right');
t.classList.remove('top');
t.classList.remove('bottom');
if (options.direction === 'left') {
t.classList.add('bottom')
} else if (options.direction === 'right') {
t.classList.add('bottom', 'left')
} else if (options.direction === 'top') {
t.classList.add('right')
} else {
t.classList.add('left')
}
})*/
}
super.update(options);
}
add(tool, name, position = 'after') {
if (Array.isArray(tool)) {
let tools = tool;
tools.forEach(t => {
this.appendAtLast(t)
});
} else {
if (position === 'begin') {
this.appendAtIndex(tool, name, 0)
} else {
this.appendAtLast(tool, name)
}
}
}
remove(name) {
let tool = this.tools[name];
this.removeItem(tool)
delete this.tools[name];
return tool;
}
appendAtLast(tool, name) {
if (!name) {
name = Utils.uuidv4()
}
this.tools[name] = tool;
this.appendLast(tool);
}
appendAtIndex(tool, name, index) {
this.tools[name] = tool;
this.insertItemAtIndex(tool, index);
}
/* Show a tool */
show(name) {
if (name && this.tools[name]) {
this.tools[name]._show()
}
}
isShown(name) {
return this.tools[name] && !this.tools[name].isHidden
}
/* Hide a tool */
hide(name) {
if (name && this.tools[name]) {
this.tools[name]._hide()
}
}
contains(name) {
return this.tools[name] !== undefined;
}
}

View File

@@ -295,17 +295,12 @@ export class DOMElement {
_show() {
this.el.style.display = ""
//this.el.style.display = 'block';
this.isHidden = false;
}
_hide() {
this.isHidden = true;
this.el.style.display = 'none';
if (this.options && this.options.onHidden) {
this.options.onHidden();
}
}
attachTo(target, position = 'beforeend') {
@@ -324,6 +319,10 @@ export class DOMElement {
this.options = {...this.options, ...options};
}
if (this.isHidden) {
return;
}
this._show();
}
};