mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-01-04 17:18:29 -08:00
* rename J2000 to ICRS as HiPSes are built in ICRS * update the ancient J2000 conversion matrices to ICRS ones.
1197 lines
48 KiB
JavaScript
1197 lines
48 KiB
JavaScript
// 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 gui/Stack/Menu.js
|
|
*
|
|
*
|
|
* Author: Matthieu Baumann [CDS, matthieu.baumann@astro.unistra.fr]
|
|
*
|
|
*****************************************************************************/
|
|
import { CatalogQueryBox } from "./CatalogQueryBox.js";
|
|
import { ALEvent } from "../../events/ALEvent.js";
|
|
import { Layout } from "../Layout.js";
|
|
import { ContextMenu } from "../Widgets/ContextMenu.js";
|
|
import { ActionButton } from "../Widgets/ActionButton.js";
|
|
import A from "../../A.js";
|
|
import { Utils } from "../../Utils";
|
|
import { View } from "../../View.js";
|
|
import { HiPSSettingsBox } from "./HiPSSettingsBox.js";
|
|
import hipsIconUrl from "../../../../assets/icons/hips.svg";
|
|
import showIconUrl from "../../../../assets/icons/show.svg";
|
|
import addIconUrl from "../../../../assets/icons/plus.svg";
|
|
import hideIconUrl from "../../../../assets/icons/hide.svg";
|
|
import removeIconUrl from "../../../../assets/icons/remove.svg";
|
|
import settingsIconUrl from "../../../../assets/icons/settings.svg";
|
|
import searchIconImg from "../../../../assets/icons/search.svg";
|
|
import downloadIconUrl from '../../../../assets/icons/download.svg';
|
|
|
|
|
|
import { TogglerActionButton } from "../Button/Toggler.js";
|
|
import { Icon } from "../Widgets/Icon.js";
|
|
import { Box } from "../Widgets/Box.js";
|
|
import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
|
import { Input } from "../Widgets/Input.js";
|
|
import { Image } from "../../Image.js";
|
|
import { HiPSBrowserBox } from "./HiPSBrowserBox.js";
|
|
|
|
export class OverlayStackBox extends Box {
|
|
/*static previewImagesUrl = {
|
|
'AllWISE color': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_allWISE_color.jpg',
|
|
'DSS colored': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_DSS2_color.jpg',
|
|
'DSS2 Red (F+R)': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_DSS2_red.jpg',
|
|
'Fermi color': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_Fermi_color.jpg',
|
|
'GALEXGR6_7 NUV': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_GALEXGR6_7_color.jpg',
|
|
'GLIMPSE360': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_GLIMPSE360.jpg',
|
|
'Halpha': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_VTSS_Ha.jpg',
|
|
'IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_SPITZER_color.jpg',
|
|
'IRIS colored': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_IRIS_color.jpg',
|
|
'Mellinger colored': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_Mellinger_color.jpg',
|
|
'PanSTARRS DR1 color': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_PanSTARRS_DR1_color-z-zg-g.jpg',
|
|
'2MASS colored': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_2MASS_color.jpg',
|
|
'AKARI colored': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_AKARI_FIS_Color.jpg',
|
|
'SWIFT': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_SWIFT_BAT_FLUX.jpg',
|
|
'VTSS-Ha': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_Finkbeiner.jpg',
|
|
'XMM PN colored': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_XMM_PN_color.jpg',
|
|
'SDSS9 colored': 'https://aladin.cds.unistra.fr/AladinLite/survey-previews/P_SDSS9_color.jpg',
|
|
};*/
|
|
static predefinedCats = {
|
|
simbad: {
|
|
url: "https://axel.u-strasbg.fr/HiPSCatService/SIMBAD",
|
|
options: {
|
|
id: "simbad",
|
|
name: "SIMBAD",
|
|
shape: "circle",
|
|
sourceSize: 8,
|
|
color: "#318d80",
|
|
hoverColor: 'red',
|
|
onClick: "showTable",
|
|
shape: (s) => {
|
|
let galaxy = ["Seyfert","Seyfert_1", "Seyfert_2","LSB_G","PartofG","RadioG","Gin","GinPair","HII_G","LensedG","BClG","BlueCompG","EmG","GinCl","GinGroup","StarburstG","LINER","AGN","Galaxy"].some((n) => s.data.main_type.indexOf(n) >= 0);
|
|
if (!galaxy) return;
|
|
|
|
let a = +s.data.size_maj;
|
|
let b = +s.data.size_min;
|
|
|
|
let theta = +s.data.size_angle || 0.0;
|
|
return A.ellipse(s.ra, s.dec, a / 60, b / 60, theta, { color: "cyan" });
|
|
}
|
|
},
|
|
},
|
|
gaia: {
|
|
url: "https://axel.u-strasbg.fr/HiPSCatService/I/355/gaiadr3",
|
|
options: {
|
|
id: "gaia-dr3",
|
|
name: "Gaia DR3",
|
|
shape: "square",
|
|
sourceSize: 8,
|
|
color: "#6baed6",
|
|
onClick: "showTable",
|
|
},
|
|
},
|
|
twomass: {
|
|
url: "https://axel.u-strasbg.fr/HiPSCatService/II/246/out",
|
|
options: {
|
|
id: "2mass",
|
|
name: "2MASS",
|
|
shape: "plus",
|
|
sourceSize: 8,
|
|
color: "#dd2233",
|
|
onClick: "showTable",
|
|
},
|
|
},
|
|
};
|
|
// Constructor
|
|
constructor(aladin, stackBtn) {
|
|
super(
|
|
{
|
|
close: true,
|
|
header: {
|
|
title: "Stack",
|
|
},
|
|
classList: ["aladin-stack-box"],
|
|
content: [],
|
|
},
|
|
aladin.aladinDiv
|
|
);
|
|
this.stackBtn = stackBtn;
|
|
this.cachedHiPS = {};
|
|
|
|
this.aladin = aladin;
|
|
|
|
this.mode = "stack";
|
|
|
|
this._addListeners();
|
|
|
|
this.mocHiPSUrls = {};
|
|
|
|
this.HiPSui = {};
|
|
let self = this;
|
|
// Add overlay button
|
|
this.addOverlayBtn = new CtxMenuActionButtonOpener(
|
|
{
|
|
icon: {
|
|
url: addIconUrl,
|
|
size: "small",
|
|
monochrome: true,
|
|
},
|
|
tooltip: {
|
|
content: "A catalog, MOC or footprint",
|
|
position: { direction: "top" },
|
|
},
|
|
ctxMenu: [
|
|
{
|
|
label: "Catalogue",
|
|
subMenu: [
|
|
{
|
|
label: {
|
|
icon: {
|
|
url: "https://aladin.cds.unistra.fr/AladinLite/logos/SIMBAD.svg",
|
|
cssStyle: {
|
|
width: "3rem",
|
|
height: "3rem",
|
|
cursor: "help",
|
|
},
|
|
action(o) {
|
|
window.open(
|
|
"https://simbad.cds.unistra.fr/simbad/"
|
|
);
|
|
},
|
|
},
|
|
content: "database",
|
|
tooltip: {
|
|
content:
|
|
"Click to go to the SIMBAD database",
|
|
position: { direction: "bottom" },
|
|
},
|
|
},
|
|
action(o) {
|
|
o.stopPropagation();
|
|
o.preventDefault();
|
|
|
|
//self._hide();
|
|
|
|
const simbadHiPS = A.catalogHiPS(
|
|
OverlayStackBox.predefinedCats.simbad
|
|
.url,
|
|
OverlayStackBox.predefinedCats.simbad
|
|
.options
|
|
);
|
|
self.aladin.addCatalog(simbadHiPS);
|
|
},
|
|
},
|
|
{
|
|
label: "Gaia DR3",
|
|
action(o) {
|
|
o.stopPropagation();
|
|
o.preventDefault();
|
|
|
|
//self._hide();
|
|
|
|
const simbadHiPS = A.catalogHiPS(
|
|
OverlayStackBox.predefinedCats.gaia.url,
|
|
OverlayStackBox.predefinedCats.gaia
|
|
.options
|
|
);
|
|
self.aladin.addCatalog(simbadHiPS);
|
|
},
|
|
},
|
|
{
|
|
label: "2MASS",
|
|
action(o) {
|
|
o.stopPropagation();
|
|
o.preventDefault();
|
|
|
|
//self._hide();
|
|
|
|
const simbadHiPS = A.catalogHiPS(
|
|
OverlayStackBox.predefinedCats.twomass
|
|
.url,
|
|
OverlayStackBox.predefinedCats.twomass
|
|
.options
|
|
);
|
|
self.aladin.addCatalog(simbadHiPS);
|
|
},
|
|
},
|
|
ContextMenu.fileLoaderItem({
|
|
label: "From a VOTable File",
|
|
accept: ".xml,.vot",
|
|
action(file) {
|
|
let url = URL.createObjectURL(file);
|
|
|
|
A.catalogFromURL(
|
|
url,
|
|
{ onClick: "showTable" },
|
|
(catalog) => {
|
|
self.aladin.addCatalog(catalog);
|
|
},
|
|
(e) => alert(e)
|
|
);
|
|
},
|
|
}),
|
|
{
|
|
label: {
|
|
icon: {
|
|
url: searchIconImg,
|
|
monochrome: true,
|
|
tooltip: {
|
|
content:
|
|
"Find a specific catalogue <br /> in our database...",
|
|
position: { direction: "top" },
|
|
},
|
|
cssStyle: {
|
|
cursor: "help",
|
|
},
|
|
},
|
|
content: "Browse...",
|
|
},
|
|
action(o) {
|
|
o.stopPropagation();
|
|
o.preventDefault();
|
|
|
|
if (!self.catBox)
|
|
self.catBox = new CatalogQueryBox(aladin);
|
|
|
|
self.catBox._show({position: {
|
|
anchor: 'center center'
|
|
}});
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: {
|
|
icon: {
|
|
url: Icon.dataURLFromSVG({
|
|
svg: Icon.SVG_ICONS.MOC,
|
|
}),
|
|
size: "small",
|
|
tooltip: {
|
|
content: "Define a selection coverage",
|
|
position: { direction: "bottom" },
|
|
},
|
|
monochrome: true,
|
|
cssStyle: {
|
|
cursor: "pointer",
|
|
},
|
|
},
|
|
content: "MOC",
|
|
},
|
|
subMenu: [
|
|
ContextMenu.fileLoaderItem({
|
|
label: "FITS File",
|
|
accept: ".fits",
|
|
action(file) {
|
|
let url = URL.createObjectURL(file);
|
|
|
|
let moc = A.MOCFromURL(url, {
|
|
name: file.name,
|
|
lineWidth: 3.0,
|
|
});
|
|
self.aladin.addMOC(moc);
|
|
},
|
|
}),
|
|
{
|
|
label: "From selection",
|
|
subMenu: [
|
|
{
|
|
label: "◌ Circle",
|
|
disabled:
|
|
self.aladin.view.mode !== View.PAN
|
|
? {
|
|
reason: "Exit your current mode<br/>(e.g. disable the SIMBAD pointer mode)",
|
|
}
|
|
: false,
|
|
action(o) {
|
|
o.preventDefault();
|
|
o.stopPropagation();
|
|
|
|
self.aladin.select(
|
|
"circle",
|
|
(c) => {
|
|
try {
|
|
let [ra, dec] =
|
|
self.aladin.pix2world(
|
|
c.x,
|
|
c.y,
|
|
"icrs"
|
|
);
|
|
let radius =
|
|
self.aladin.angularDist(
|
|
c.x,
|
|
c.y,
|
|
c.x + c.r,
|
|
c.y
|
|
);
|
|
|
|
// the moc needs a
|
|
let moc = A.MOCFromCone(
|
|
{ ra, dec, radius },
|
|
{
|
|
name: "cone",
|
|
lineWidth: 3.0,
|
|
}
|
|
);
|
|
self.aladin.addMOC(moc);
|
|
} catch {
|
|
console.error(
|
|
"Circle out of projection. Selection canceled"
|
|
);
|
|
}
|
|
}
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: "⬚ Rect",
|
|
disabled:
|
|
self.aladin.view.mode !== View.PAN
|
|
? {
|
|
reason: "Exit your current mode<br/>(e.g. disable the SIMBAD pointer mode)",
|
|
}
|
|
: false,
|
|
action(o) {
|
|
o.stopPropagation();
|
|
o.preventDefault();
|
|
|
|
//self._hide();
|
|
|
|
self.aladin.select("rect", (r) => {
|
|
try {
|
|
let [ra1, dec1] =
|
|
self.aladin.pix2world(
|
|
r.x,
|
|
r.y,
|
|
"icrs"
|
|
);
|
|
let [ra2, dec2] =
|
|
self.aladin.pix2world(
|
|
r.x + r.w,
|
|
r.y,
|
|
"icrs"
|
|
);
|
|
let [ra3, dec3] =
|
|
self.aladin.pix2world(
|
|
r.x + r.w,
|
|
r.y + r.h,
|
|
"icrs"
|
|
);
|
|
let [ra4, dec4] =
|
|
self.aladin.pix2world(
|
|
r.x,
|
|
r.y + r.h,
|
|
"icrs"
|
|
);
|
|
|
|
let moc = A.MOCFromPolygon(
|
|
{
|
|
ra: [
|
|
ra1,
|
|
ra2,
|
|
ra3,
|
|
ra4,
|
|
],
|
|
dec: [
|
|
dec1,
|
|
dec2,
|
|
dec3,
|
|
dec4,
|
|
],
|
|
},
|
|
{
|
|
name: "rect",
|
|
lineWidth: 3.0,
|
|
}
|
|
);
|
|
self.aladin.addMOC(moc);
|
|
} catch (_) {
|
|
alert(
|
|
"Selection covers a region out of the projection definition domain."
|
|
);
|
|
}
|
|
});
|
|
},
|
|
},
|
|
{
|
|
label: "⛉ Polygon",
|
|
disabled:
|
|
self.aladin.view.mode !== View.PAN
|
|
? {
|
|
reason: "Exit your current mode<br/>(e.g. disable the SIMBAD pointer mode)",
|
|
}
|
|
: false,
|
|
action(o) {
|
|
o.stopPropagation();
|
|
o.preventDefault();
|
|
|
|
//self._hide();
|
|
|
|
self.aladin.select("poly", (p) => {
|
|
try {
|
|
let ra = [];
|
|
let dec = [];
|
|
for (const v of p.vertices) {
|
|
let [lon, lat] =
|
|
self.aladin.pix2world(
|
|
v.x,
|
|
v.y,
|
|
"icrs"
|
|
);
|
|
ra.push(lon);
|
|
dec.push(lat);
|
|
}
|
|
|
|
let moc = A.MOCFromPolygon(
|
|
{ ra, dec },
|
|
{
|
|
name: "poly",
|
|
lineWidth: 3.0,
|
|
}
|
|
);
|
|
self.aladin.addMOC(moc);
|
|
} catch (_) {
|
|
alert(
|
|
"Selection covers a region out of the projection definition domain."
|
|
);
|
|
}
|
|
});
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
this.aladin
|
|
);
|
|
|
|
this.addHiPSBtn = new CtxMenuActionButtonOpener(
|
|
{
|
|
icon: {
|
|
url: addIconUrl,
|
|
size: "small",
|
|
monochrome: true,
|
|
},
|
|
ctxMenu: [
|
|
{
|
|
label: {
|
|
icon: {
|
|
url: addIconUrl,
|
|
monochrome: true,
|
|
tooltip: {
|
|
content: "Add a new layer",
|
|
position: { direction: "right" },
|
|
},
|
|
cssStyle: {
|
|
cursor: "help",
|
|
},
|
|
},
|
|
content: "Add new survey",
|
|
},
|
|
action: (e) => {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
/*self._hide();
|
|
|
|
self.hipsSelectorBox = new HiPSSelectorBox(self.aladin);
|
|
// attach a callback
|
|
self.hipsSelectorBox.attach(
|
|
(HiPSId) => {
|
|
let name = Utils.uuidv4()
|
|
self.aladin.setOverlayImageLayer(HiPSId, name)
|
|
|
|
self.show();
|
|
}
|
|
);
|
|
|
|
self.hipsSelectorBox._show({
|
|
position: self.position,
|
|
});*/
|
|
self.aladin.addNewImageLayer(
|
|
A.imageHiPS('P/DSS2/color', {
|
|
errorCallback: (e) => {
|
|
aladin.addStatusBarMessage({
|
|
duration: 2000,
|
|
type: 'info',
|
|
message: 'DSS2 colored HiPS could not plot',
|
|
})
|
|
}
|
|
})
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: {
|
|
icon: {
|
|
url: hipsIconUrl,
|
|
monochrome: true,
|
|
tooltip: {
|
|
content: "From our database...",
|
|
position: { direction: "right" },
|
|
},
|
|
cssStyle: {
|
|
cursor: "help",
|
|
},
|
|
},
|
|
content: "Browse HiPS",
|
|
},
|
|
action: (e) => {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
if (!self.hipsBrowser)
|
|
self.hipsBrowser = new HiPSBrowserBox(aladin);
|
|
|
|
self.hipsBrowser._show({position: {
|
|
anchor: 'center center'
|
|
}});
|
|
},
|
|
},
|
|
ContextMenu.fileLoaderItem({
|
|
label: "FITS image file",
|
|
accept: ".fits",
|
|
action(file) {
|
|
let url = URL.createObjectURL(file);
|
|
|
|
const image = self.aladin.createImageFITS(
|
|
url,
|
|
{name: file.name},
|
|
(ra, dec, fov, _) => {
|
|
// Center the view around the new fits object
|
|
self.aladin.gotoRaDec(ra, dec);
|
|
self.aladin.setFoV(fov * 1.1);
|
|
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
);
|
|
|
|
self.aladin.setOverlayImageLayer(
|
|
image,
|
|
Utils.uuidv4()
|
|
);
|
|
},
|
|
}),
|
|
ContextMenu.webkitDir({
|
|
label: "Load local HiPS",
|
|
action(files) {
|
|
let id = files[0].webkitRelativePath.split("/")[0];
|
|
let name = id;
|
|
|
|
let hips = self.aladin.createImageSurvey(
|
|
id,
|
|
name,
|
|
files,
|
|
null,
|
|
null,
|
|
{
|
|
errorCallback: (e) => {
|
|
aladin.addStatusBarMessage({
|
|
duration: 2000,
|
|
type: 'info',
|
|
message: 'Could not add the local HiPS',
|
|
})
|
|
}
|
|
}
|
|
)
|
|
self.aladin.addNewImageLayer(hips);
|
|
},
|
|
}),
|
|
],
|
|
tooltip: {
|
|
content: "Add a HiPS or an FITS image",
|
|
position: { direction: "top" },
|
|
},
|
|
},
|
|
this.aladin
|
|
);
|
|
|
|
this.update({ content: this.createLayout() });
|
|
}
|
|
|
|
_addListeners() {
|
|
let self = this;
|
|
|
|
let updateOverlayList = () => {
|
|
let wasHidden = self.isHidden;
|
|
self._hide();
|
|
|
|
// recompute the ui
|
|
// If it is shown, update it
|
|
// show will update the content of the stack
|
|
self.update({ content: self.createLayout() });
|
|
|
|
if (!wasHidden) self._show();
|
|
|
|
};
|
|
|
|
ALEvent.GRAPHIC_OVERLAY_LAYER_ADDED.listenedBy(
|
|
this.aladin.aladinDiv,
|
|
function (e) {
|
|
updateOverlayList();
|
|
}
|
|
);
|
|
|
|
ALEvent.GRAPHIC_OVERLAY_LAYER_REMOVED.listenedBy(
|
|
this.aladin.aladinDiv,
|
|
function (e) {
|
|
updateOverlayList();
|
|
}
|
|
);
|
|
|
|
ALEvent.GRAPHIC_OVERLAY_LAYER_CHANGED.listenedBy(
|
|
this.aladin.aladinDiv,
|
|
function (e) {
|
|
updateOverlayList();
|
|
}
|
|
);
|
|
|
|
ALEvent.HIPS_LAYER_ADDED.listenedBy(
|
|
this.aladin.aladinDiv,
|
|
function (e) {
|
|
updateOverlayList();
|
|
}
|
|
);
|
|
|
|
ALEvent.HIPS_LAYER_SWAP.listenedBy(this.aladin.aladinDiv, function (e) {
|
|
updateOverlayList();
|
|
});
|
|
|
|
ALEvent.HIPS_LAYER_REMOVED.listenedBy(
|
|
this.aladin.aladinDiv,
|
|
function (e) {
|
|
updateOverlayList();
|
|
}
|
|
);
|
|
|
|
ALEvent.HIPS_LAYER_CHANGED.listenedBy(
|
|
this.aladin.aladinDiv,
|
|
function (e) {
|
|
const hips = e.detail.layer;
|
|
let ui = self.HiPSui[hips.layer];
|
|
|
|
if (!ui) {
|
|
return;
|
|
}
|
|
|
|
// change the ui from parameter changes
|
|
// show button
|
|
const opacity = hips.getOpacity();
|
|
let showBtn = ui.showBtn;
|
|
let hiddenBtn = showBtn.options.icon.url === hideIconUrl;
|
|
|
|
if (opacity !== 0.0 && hiddenBtn) {
|
|
showBtn.update({
|
|
icon: { monochrome: true, url: showIconUrl },
|
|
tooltip: { content: "Hide" },
|
|
});
|
|
} else if (opacity === 0.0 && !hiddenBtn) {
|
|
showBtn.update({
|
|
icon: { monochrome: true, url: hideIconUrl },
|
|
tooltip: { content: "Show" },
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
updateOverlayList();
|
|
|
|
// Add a listener for HiPS list changes
|
|
ALEvent.FAVORITE_HIPS_LIST_UPDATED.listenedBy(document.body, (event) => {
|
|
let favoritesHips = event.detail;
|
|
self.cachedHiPS = {};
|
|
|
|
for (var hips of favoritesHips) {
|
|
let key = hips.name || hips.id || hips.url;
|
|
self.cachedHiPS[key] = hips;
|
|
}
|
|
// Update the options of the selector
|
|
const favorites = Object.keys(self.cachedHiPS);
|
|
for (var key in self.HiPSui) {
|
|
let hips = self.HiPSui[key];
|
|
let currentHiPS = hips.HiPSSelector.options.value
|
|
|
|
let favoritesCopy = [...favorites];
|
|
|
|
// add the current hips to the selector as well, even if it has been manually
|
|
// removed from the HiPSList
|
|
if (favoritesCopy.indexOf(currentHiPS) < 0) {
|
|
favoritesCopy.push(currentHiPS)
|
|
}
|
|
|
|
// one must add the current HiPS too!
|
|
favoritesCopy.sort();
|
|
|
|
hips.HiPSSelector.update({value: currentHiPS, options: favoritesCopy});
|
|
}
|
|
});
|
|
}
|
|
|
|
_hide() {
|
|
for (var key in this.HiPSui) {
|
|
let hips = this.HiPSui[key];
|
|
if (hips.settingsBtn.toggled) {
|
|
// toggle off
|
|
hips.settingsBtn.toggle();
|
|
}
|
|
}
|
|
|
|
/*if (this.hipsBrowser) {
|
|
this.hipsBrowser._hide();
|
|
}*/
|
|
|
|
/*if (this.catBox) {
|
|
this.catBox._hide();
|
|
}*/
|
|
|
|
if (this.addOverlayBtn) this.addOverlayBtn.hideMenu();
|
|
|
|
if (this.addHiPSBtn) this.addHiPSBtn.hideMenu();
|
|
|
|
// toggle the button because the window is closed
|
|
this.stackBtn.update({toggled: false});
|
|
|
|
super._hide();
|
|
}
|
|
|
|
createLayout() {
|
|
this.HiPSui = {};
|
|
|
|
let layout = [Layout.horizontal([this.addOverlayBtn, "Overlays"])];
|
|
|
|
layout = layout.concat(this._createOverlaysList());
|
|
|
|
layout.push(
|
|
Layout.horizontal({
|
|
layout: [
|
|
this.addHiPSBtn,
|
|
"Surveys",
|
|
this.filterEnabler,
|
|
this.filterBtn,
|
|
],
|
|
})
|
|
);
|
|
layout = layout.concat(this._createSurveysList());
|
|
|
|
return Layout.vertical({ layout });
|
|
}
|
|
|
|
_createOverlaysList() {
|
|
let self = this;
|
|
|
|
let layout = [];
|
|
const overlays = Array.from(this.aladin.getOverlays())
|
|
.reverse()
|
|
.map((overlay) => {
|
|
return overlay;
|
|
});
|
|
// list of overlays
|
|
for (const overlay of overlays) {
|
|
const name = overlay.name;
|
|
let optBtn = [];
|
|
optBtn.push(new ActionButton({
|
|
size: "small",
|
|
icon: {
|
|
url: overlay.isShowing ? showIconUrl : hideIconUrl,
|
|
monochrome: true,
|
|
},
|
|
tooltip: {
|
|
content: overlay.isShowing ? "Hide" : "Show",
|
|
position: { direction: "top" },
|
|
},
|
|
action(e, btn) {
|
|
if (overlay.isShowing) {
|
|
overlay.hide();
|
|
btn.update({
|
|
icon: { monochrome: true, url: hideIconUrl },
|
|
tooltip: { content: "Show" },
|
|
});
|
|
} else {
|
|
overlay.show();
|
|
btn.update({
|
|
icon: { monochrome: true, url: showIconUrl },
|
|
tooltip: { content: "Hide" },
|
|
});
|
|
}
|
|
},
|
|
}));
|
|
|
|
optBtn.push(new ActionButton({
|
|
icon: {
|
|
url: removeIconUrl,
|
|
monochrome: true,
|
|
},
|
|
size: "small",
|
|
/*cssStyle: {
|
|
visibility: Utils.hasTouchScreen() ? 'visible' : 'hidden',
|
|
},*/
|
|
tooltip: {
|
|
content: "Remove",
|
|
position: { direction: "top" },
|
|
},
|
|
action(e) {
|
|
self.aladin.removeLayer(overlay);
|
|
},
|
|
}));
|
|
|
|
if (overlay.serialize) {
|
|
optBtn.push(new ActionButton({
|
|
icon: {
|
|
url: downloadIconUrl,
|
|
monochrome: true,
|
|
},
|
|
size: "small",
|
|
tooltip: {
|
|
content: "Download JSON MOC",
|
|
position: { direction: "top" },
|
|
},
|
|
action(e) {
|
|
let json = overlay.serialize('json');
|
|
let blob = new Blob([json]);
|
|
Utils.download(URL.createObjectURL(blob), overlay.name + '.json');
|
|
},
|
|
}));
|
|
}
|
|
|
|
|
|
let item = Layout.horizontal({
|
|
layout: [
|
|
this._addOverlayIcon(overlay),
|
|
'<div style="background-color: rgba(0, 0, 0, 0.6); padding: 3px; border-radius: 3px; word-break: break-word;">' +
|
|
name +
|
|
"</div>",
|
|
Layout.horizontal({ layout: optBtn }),
|
|
],
|
|
cssStyle: {
|
|
textAlign: "center",
|
|
display: "flex",
|
|
alignItems: "center",
|
|
listStyle: "none",
|
|
justifyContent: "space-between",
|
|
width: "100%",
|
|
},
|
|
});
|
|
|
|
/*if(!Utils.hasTouchScreen()) {
|
|
layout.push({
|
|
label: item,
|
|
cssStyle,
|
|
hover(e) {
|
|
showBtn.el.style.visibility = 'visible'
|
|
deleteBtn.el.style.visibility = 'visible'
|
|
},
|
|
unhover(e) {
|
|
showBtn.el.style.visibility = 'hidden'
|
|
deleteBtn.el.style.visibility = 'hidden'
|
|
},
|
|
})
|
|
} else {
|
|
layout.push({
|
|
label: item,
|
|
cssStyle
|
|
})
|
|
}*/
|
|
layout.push(item);
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
|
|
_createSurveysList() {
|
|
let self = this;
|
|
|
|
const layers = Array.from(self.aladin.getStackLayers())
|
|
.reverse()
|
|
.map((name) => {
|
|
let overlay = self.aladin.getOverlayImageLayer(name);
|
|
return overlay;
|
|
});
|
|
|
|
// survey list
|
|
let layout = [];
|
|
|
|
let hipsOptions = Object.keys(self.cachedHiPS);
|
|
hipsOptions.sort()
|
|
|
|
for (const layer of layers) {
|
|
let options = Array.from([...hipsOptions])
|
|
let value = layer.name || layer.id
|
|
|
|
if (options.indexOf(value) < 0) {
|
|
options.push(value)
|
|
}
|
|
|
|
let HiPSSelector = Input.select({
|
|
value,
|
|
options,
|
|
title: layer.name,
|
|
change: (e) => {
|
|
let name = e.target.value;
|
|
// search for the
|
|
let overlayLayer;
|
|
if (name in self.cachedHiPS) {
|
|
// it is an hips
|
|
let HiPSOptions = self.cachedHiPS[name];
|
|
|
|
overlayLayer = A.HiPS(HiPSOptions.id || HiPSOptions.url, HiPSOptions);
|
|
} else {
|
|
overlayLayer = layer
|
|
}
|
|
|
|
self.aladin.setOverlayImageLayer(overlayLayer, layer.layer);
|
|
}
|
|
});
|
|
|
|
let deleteBtn = ActionButton.createSmallSizedIconBtn({
|
|
icon: { url: removeIconUrl, monochrome: true },
|
|
|
|
disable: layer.layer === "base",
|
|
tooltip: { content: "Remove", position: { direction: "top" } },
|
|
action(e) {
|
|
self.aladin.removeImageLayer(layer.layer);
|
|
// remove HiPS cube player if any
|
|
self.aladin.removeUIByName("cube_displayer" + layer.layer)
|
|
},
|
|
});
|
|
|
|
let showBtn = ActionButton.createSmallSizedIconBtn({
|
|
icon: {
|
|
url: layer.getOpacity() === 0.0 ? hideIconUrl : showIconUrl,
|
|
monochrome: true,
|
|
},
|
|
tooltip: {
|
|
content: layer.getOpacity() === 0.0 ? "Show" : "Hide",
|
|
position: { direction: "top" },
|
|
},
|
|
action(e, btn) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
let opacity = layer.getOpacity();
|
|
if (opacity === 0.0) {
|
|
layer.setOpacity(1.0);
|
|
btn.update({
|
|
icon: { monochrome: true, url: showIconUrl },
|
|
tooltip: { content: "Hide" },
|
|
});
|
|
} else {
|
|
layer.setOpacity(0.0);
|
|
btn.update({
|
|
icon: { monochrome: true, url: hideIconUrl },
|
|
tooltip: { content: "Show" },
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
let settingsBox = new HiPSSettingsBox(self.aladin);
|
|
settingsBox.update({ layer });
|
|
settingsBox._hide();
|
|
|
|
let settingsBtn = new TogglerActionButton({
|
|
icon: { url: settingsIconUrl, monochrome: true },
|
|
size: "small",
|
|
tooltip: {
|
|
content: "Settings",
|
|
position: { direction: "top" },
|
|
},
|
|
toggled: false,
|
|
actionOn: (e) => {
|
|
// toggle off the other settings if opened
|
|
for (var l in self.HiPSui) {
|
|
let ui = self.HiPSui[l]
|
|
|
|
if (l != layer.layer) {
|
|
ui.settingsBtn.close();
|
|
}
|
|
}
|
|
|
|
settingsBox._show({
|
|
position: {
|
|
nextTo: settingsBtn,
|
|
direction: "right",
|
|
aladin: self.aladin,
|
|
},
|
|
});
|
|
},
|
|
actionOff: (e) => {
|
|
settingsBox._hide();
|
|
},
|
|
});
|
|
|
|
let loadMOCBtn = new ActionButton({
|
|
size: "small",
|
|
|
|
icon: {
|
|
url: Icon.dataURLFromSVG({ svg: Icon.SVG_ICONS.MOC }),
|
|
size: "small",
|
|
monochrome: true,
|
|
},
|
|
tooltip: {
|
|
content: "Add coverage",
|
|
position: { direction: "top" },
|
|
},
|
|
toggled: (() => {
|
|
let overlays = self.aladin.getOverlays();
|
|
let found = overlays.find(
|
|
(o) => o.type === "moc" && o.name === layer.name
|
|
);
|
|
return found !== undefined;
|
|
})(),
|
|
action: (e) => {
|
|
if (!loadMOCBtn.options.toggled) {
|
|
// load the moc
|
|
let moc = A.MOCFromURL(
|
|
layer.url + "/Moc.fits",
|
|
{ name: layer.name },
|
|
() => {
|
|
self.mocHiPSUrls[layer.url] = moc;
|
|
|
|
if (self.aladin.statusBar) {
|
|
self.aladin.statusBar.appendMessage({
|
|
message:
|
|
"Coverage of " +
|
|
layer.name +
|
|
" loaded",
|
|
duration: 2000,
|
|
type: "info",
|
|
});
|
|
}
|
|
|
|
loadMOCBtn.update({
|
|
toggled: true,
|
|
tooltip: {
|
|
content: "Remove coverage",
|
|
position: { direction: "top" },
|
|
},
|
|
});
|
|
}
|
|
);
|
|
self.aladin.addMOC(moc);
|
|
} else {
|
|
// unload the moc
|
|
let moc = self.mocHiPSUrls[layer.url];
|
|
self.aladin.removeLayer(moc);
|
|
|
|
delete self.mocHiPSUrls[layer.url];
|
|
|
|
if (self.aladin.statusBar) {
|
|
self.aladin.statusBar.appendMessage({
|
|
message:
|
|
"Coverage of " + layer.name + " removed",
|
|
duration: 2000,
|
|
type: "info",
|
|
});
|
|
}
|
|
|
|
loadMOCBtn.update({
|
|
toggled: false,
|
|
tooltip: {
|
|
content: "Add coverage",
|
|
position: { direction: "top" },
|
|
},
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
let btns = [showBtn, settingsBtn];
|
|
|
|
if (!(layer instanceof Image)) {
|
|
btns.push(loadMOCBtn);
|
|
}
|
|
btns.push(deleteBtn);
|
|
|
|
let item = Layout.horizontal({
|
|
layout: [HiPSSelector, Layout.horizontal(btns)],
|
|
});
|
|
|
|
layout.push(item);
|
|
|
|
if (!(layer.layer in self.HiPSui)) {
|
|
self.HiPSui[layer.layer] = {
|
|
HiPSSelector,
|
|
settingsBox,
|
|
settingsBtn,
|
|
showBtn,
|
|
};
|
|
}
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
|
|
_addOverlayIcon(overlay) {
|
|
var tooltipText;
|
|
var svg = "";
|
|
if (overlay.type == "catalog" || overlay.type == "progressivecat") {
|
|
var nbSources = overlay.getSources().length;
|
|
tooltipText = nbSources + " source" + (nbSources > 1 ? "s" : "");
|
|
|
|
svg = Icon.SVG_ICONS.CATALOG;
|
|
} else if (overlay.type == "moc") {
|
|
tooltipText =
|
|
"Coverage: " +
|
|
(100 * overlay.skyFraction()).toFixed(2) +
|
|
" % of sky";
|
|
|
|
svg = Icon.SVG_ICONS.MOC;
|
|
} else if (overlay.type == "overlay") {
|
|
svg = Icon.SVG_ICONS.OVERLAY;
|
|
}
|
|
|
|
let tooltip;
|
|
if (tooltipText) {
|
|
tooltip = {
|
|
content: tooltipText,
|
|
position: { direction: "bottom" },
|
|
};
|
|
}
|
|
|
|
// retrieve SVG icon, and apply the layer color
|
|
return new Icon({
|
|
size: "small",
|
|
url: Icon.dataURLFromSVG({ svg, color: overlay.color }),
|
|
tooltip,
|
|
});
|
|
}
|
|
|
|
_show(options) {
|
|
if (!this.aladin) {
|
|
return;
|
|
}
|
|
|
|
this.position = (options && options.position) || this.position;
|
|
|
|
if (!this.position) return;
|
|
|
|
this.position.aladin = this.aladin;
|
|
|
|
super._show({
|
|
...options,
|
|
...{ position: this.position },
|
|
});
|
|
|
|
this.stackBtn.update({toggled: true});
|
|
}
|
|
}
|