mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-12 07:40:26 -08:00
new UI StackBox
This commit is contained in:
committed by
Matthieu Baumann
parent
116ba0d2e3
commit
63aebf738a
@@ -2,6 +2,7 @@
|
||||
|
||||
## 3.3.3
|
||||
|
||||
* [feat] New `hipsList` option parameter when instancing a new Aladin object.
|
||||
* [feat] Zoom smoothing using hermite cubic interpolation functions
|
||||
* [feat] shape option of Catalog and ProgressiveCat accepts a function returning a Footprint. This allow user to
|
||||
associate a footprint to a specific source
|
||||
|
||||
5
assets/icons/add.svg
Normal file
5
assets/icons/add.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 8C11 7.44772 11.4477 7 12 7C12.5523 7 13 7.44771 13 8V11H16C16.5523 11 17 11.4477 17 12C17 12.5523 16.5523 13 16 13H13V16C13 16.5523 12.5523 17 12 17C11.4477 17 11 16.5523 11 16V13H8C7.44772 13 7 12.5523 7 12C7 11.4477 7.44771 11 8 11H11V8Z" fill="#0F0F0F"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23 4C23 2.34315 21.6569 1 20 1H4C2.34315 1 1 2.34315 1 4V20C1 21.6569 2.34315 23 4 23H20C21.6569 23 23 21.6569 23 20V4ZM21 4C21 3.44772 20.5523 3 20 3H4C3.44772 3 3 3.44772 3 4V20C3 20.5523 3.44772 21 4 21H20C20.5523 21 21 20.5523 21 20V4Z" fill="#0F0F0F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 811 B |
@@ -10,26 +10,8 @@
|
||||
import A from '../src/js/A.js';
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {target: '12 25 41.512 +12 48 47.2', fov: 1, showContextMenu: true});
|
||||
aladin = A.aladin('#aladin-lite-div', {target: '12 25 41.512 +12 48 47.2', inertia: false, fov: 1, showContextMenu: true});
|
||||
// define custom draw function
|
||||
var drawFunction = function(source, canvasCtx, viewParams) {
|
||||
canvasCtx.beginPath();
|
||||
canvasCtx.arc(source.x, source.y, source.data['coo_err_min'] * 5, 0, 2 * Math.PI, false);
|
||||
canvasCtx.closePath();
|
||||
canvasCtx.strokeStyle = '#c38';
|
||||
canvasCtx.lineWidth = 3;
|
||||
canvasCtx.globalAlpha = 0.7,
|
||||
canvasCtx.stroke();
|
||||
var fov = Math.max(viewParams['fov'][0], viewParams['fov'][1]);
|
||||
|
||||
// object name is displayed only if fov<10°
|
||||
if (fov>10) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvasCtx.globalAlpha = 0.9;
|
||||
canvasCtx.globalAlpha = 1;
|
||||
};
|
||||
|
||||
var drawFunctionFootprint = function(s) {
|
||||
let a = +s.data.size_maj;
|
||||
@@ -39,8 +21,8 @@
|
||||
if (!galaxy)
|
||||
return;
|
||||
|
||||
let angle = +s.data.size_angle || 0.0;
|
||||
return A.ellipse(s.ra, s.dec, a / 60, b / 60, angle, {color: 'cyan'});
|
||||
let theta = +s.data.size_angle || 0.0;
|
||||
return A.ellipse(s.ra, s.dec, a / 60, b / 60, theta, {color: 'cyan'});
|
||||
};
|
||||
|
||||
var hips = A.catalogHiPS('https://axel.u-strasbg.fr/HiPSCatService/Simbad', {onClick: 'showTable', name: 'Simbad', color: 'cyan', hoverColor: 'red', shape: drawFunctionFootprint});
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
|
||||
A.init.then(() => {
|
||||
var hipsDir="http://alasky.u-strasbg.fr/CDS_P_Coronelli";
|
||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, expandLayersControl: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||
aladin.createImageSurvey('illenoroC', 'illenoroC', hipsDir, 'equatorial', 4, {imgFormat: 'jpg', longitudeReversed: false});
|
||||
aladin.createImageSurvey('Coronelli', 'Coronelli', hipsDir, 'equatorial', 4, {imgFormat: 'jpg', longitudeReversed: true});
|
||||
aladin.setImageSurvey('Coronelli');
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
console.log("Object hovered stopped: ", object, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
|
||||
})
|
||||
|
||||
const cat = A.catalogFromVizieR('B/assocdata/obscore', 'M 1', 100, {onClick: 'showTable', hoverColor: 'purple', limit: 1000});
|
||||
const cat = A.catalogFromVizieR('B/assocdata/obscore', 'M 1', 10, {onClick: 'showTable', hoverColor: 'purple', limit: 10000});
|
||||
aladin.addCatalog(cat);
|
||||
});
|
||||
</script>
|
||||
|
||||
32
examples/al-save-colormap.html
Normal file
32
examples/al-save-colormap.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<!--<link rel="stylesheet" href="./layers.css" />-->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
|
||||
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
var aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, cooFrame: "ICRSd", showSimbadPointerControl: true, showShareControl: true, showShareControl: true, survey: 'https://alasky.cds.unistra.fr/DSS/DSSColor/', fov: 180, showContextMenu: true});
|
||||
// manage URL parameters
|
||||
let survey1 = aladin.getBaseImageLayer();
|
||||
survey1.setColormap('magma', {stretch: 'linear'});
|
||||
|
||||
let survey2 = aladin.newImageSurvey("CSIRO/P/RACS/low/I");
|
||||
aladin.setImageLayer(survey2)
|
||||
survey2.setColormap('rdbu', {stretch: 'linear'});
|
||||
|
||||
let survey3 = aladin.newImageSurvey("CSIRO/P/RACS/mid/I");
|
||||
aladin.setImageLayer(survey3)
|
||||
survey3.setColormap('cubehelix', {stretch: 'asinh'});
|
||||
|
||||
aladin.setImageLayer(survey2);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -429,7 +429,7 @@ canvas {
|
||||
}
|
||||
|
||||
.aladin-input-text.aladin-dark-theme.search {
|
||||
width: 14rem;
|
||||
width: 15rem;
|
||||
text-shadow: 0px 0px 2px #000;
|
||||
}
|
||||
|
||||
@@ -824,6 +824,7 @@ canvas {
|
||||
border-radius: 5px;
|
||||
font-family: monospace;
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.aladin-input-text.aladin-dark-theme, .aladin-input-number.aladin-dark-theme {
|
||||
@@ -853,18 +854,20 @@ canvas {
|
||||
/* Remove focus outline */
|
||||
/* Remove IE arrow */
|
||||
}
|
||||
|
||||
.aladin-input-select option {
|
||||
color: inherit;
|
||||
background-color: #320a28;
|
||||
}
|
||||
|
||||
.aladin-input-select:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.aladin-input-select::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* Frames */
|
||||
.aladin-input-color {
|
||||
appearance: none;
|
||||
@@ -1104,6 +1107,19 @@ canvas {
|
||||
height: 1.7rem;
|
||||
}
|
||||
|
||||
.aladin-input-text.aladin-dark-theme.search.aladin-HiPS-search {
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
.aladin-stack-box {
|
||||
width: 17rem;
|
||||
}
|
||||
|
||||
.aladin-stack-box .content > * {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.aladin-location {
|
||||
position: absolute;
|
||||
top: 0.2rem;
|
||||
@@ -1122,6 +1138,8 @@ canvas {
|
||||
bottom: 0.2rem;
|
||||
left: 0.2rem;
|
||||
|
||||
background-color: red;
|
||||
|
||||
font-family: monospace;
|
||||
|
||||
font-size: 1rem;
|
||||
@@ -1129,6 +1147,16 @@ canvas {
|
||||
line-height: 1.7rem;
|
||||
}
|
||||
|
||||
.aladin-fov .aladin-zoom-in {
|
||||
margin-right: 0;
|
||||
border-right: none;
|
||||
border-radius: 5px 0px 0px 5px;
|
||||
}
|
||||
|
||||
.aladin-fov .aladin-zoom-out {
|
||||
border-radius: 0px 5px 5px 0px;
|
||||
}
|
||||
|
||||
.aladin-status-bar {
|
||||
border-radius: 3px;
|
||||
padding: 0.4rem;
|
||||
|
||||
172
src/js/Aladin.js
172
src/js/Aladin.js
@@ -40,6 +40,7 @@ import { MeasurementTable } from "./MeasurementTable.js";
|
||||
import { ImageSurvey } from "./ImageSurvey.js";
|
||||
import { Coo } from "./libs/astro/coo.js";
|
||||
import { CooConversion } from "./CooConversion.js";
|
||||
import { MocServer } from './MocServer';
|
||||
|
||||
import { ProjectionEnum } from "./ProjectionEnum.js";
|
||||
|
||||
@@ -77,6 +78,10 @@ import { CooFrame } from './gui/Input/CooFrame';
|
||||
* @property {string} [survey="CDS/P/DSS2/color"] URL or ID of the survey to use
|
||||
* @property {string[]} [surveyUrl]
|
||||
* Array of URLs for the survey images. This replaces the survey parameter.
|
||||
* @property {Object[]|string[]} [hipsList] A list of predefined HiPS for the Aladin instance.
|
||||
* This option is used for searching for a HiPS in a list of surveys
|
||||
* This list can have string item (either a CDS ID or an HiPS url) or an object that describes the HiPS
|
||||
* more exhaustively. See the example below to see the different form that this item can have to describe a HiPS.
|
||||
* @property {string} [target="0 +0"] - Target coordinates for the initial view.
|
||||
* @property {CooFrame} [cooFrame="J2000"] - Coordinate frame.
|
||||
* @property {number} [fov=60] - Field of view in degrees.
|
||||
@@ -86,6 +91,8 @@ import { CooFrame } from './gui/Input/CooFrame';
|
||||
* This element belongs to the FoV UI thus its CSS class is `aladin-fov`
|
||||
* @property {boolean} [showLayersControl=true] - Whether to show the layers control toolbar.
|
||||
* CSS class for that button is `aladin-stack-control`
|
||||
* @property {boolean} [expandLayersControl=false] - Whether to show the stack box at starting
|
||||
* CSS class for the stack box is `aladin-stack-box`
|
||||
* @property {boolean} [showFullscreenControl=true] - Whether to show the fullscreen control toolbar.
|
||||
* CSS class for that button is `aladin-fullScreen-control`
|
||||
* @property {boolean} [showSimbadPointerControl=false] - Whether to show the Simbad pointer control toolbar.
|
||||
@@ -133,7 +140,53 @@ import { CooFrame } from './gui/Input/CooFrame';
|
||||
* @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.
|
||||
*/
|
||||
* @example
|
||||
* let aladin = A.aladin({
|
||||
target: 'galactic center',
|
||||
fov: 10,
|
||||
hipsList: [
|
||||
// url
|
||||
"https://alaskybis.unistra.fr/DSS/DSSColor",
|
||||
// ID from HiPS list
|
||||
"CDS/P/2MASS/color",
|
||||
// Not full HiPS described
|
||||
{
|
||||
name: 'DESI Legacy Surveys color (g, r, i, z)',
|
||||
id: 'CDS/P/DESI-Legacy-Surveys/DR10/color',
|
||||
},
|
||||
// Fully described HiPS
|
||||
{
|
||||
name: "DECaPS DR2 color",
|
||||
url: "https://alasky.cds.unistra.fr/DECaPS/DR2/CDS_P_DECaPS_DR2_color/",
|
||||
properties: {
|
||||
creatorDid: "ivo://CDS/P/DECaPS/DR2/color",
|
||||
maxOrder: 11,
|
||||
cooFrame: "equatorial",
|
||||
tileSize: 512,
|
||||
imgFormat: 'png',
|
||||
},
|
||||
},
|
||||
// HiPS with options
|
||||
{
|
||||
name: "SDSS9 band-g",
|
||||
id: "P/SDSS9/g",
|
||||
properties: {
|
||||
creatorDid: "ivo://CDS/P/SDSS9/g",
|
||||
maxOrder: 10,
|
||||
tileSize: 512,
|
||||
numBitsPerPixel: 16,
|
||||
imgFormat: 'fits',
|
||||
cooFrame: 'equatorial',
|
||||
},
|
||||
options: {
|
||||
minCut: 0,
|
||||
maxCut: 1.8,
|
||||
stretch: 'linear',
|
||||
colormap: "redtemperature",
|
||||
}
|
||||
}
|
||||
]
|
||||
})*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CircleSelection
|
||||
@@ -335,6 +388,84 @@ export let Aladin = (function () {
|
||||
this.setBaseImageLayer(url);
|
||||
}
|
||||
|
||||
let hipsList = [].concat(options.hipsList);
|
||||
|
||||
const fillHiPSCache = () => {
|
||||
for (var survey of hipsList) {
|
||||
let id, url, name;
|
||||
let cachedSurvey = {};
|
||||
|
||||
if (typeof survey === "string") {
|
||||
try {
|
||||
url = new URL(survey).href;
|
||||
} catch(e) {
|
||||
id = survey;
|
||||
}
|
||||
|
||||
name = url || id;
|
||||
} else if (survey instanceof Object) {
|
||||
if (survey.id) {
|
||||
id = survey.id;
|
||||
}
|
||||
if (survey.url) {
|
||||
url = survey.url;
|
||||
}
|
||||
|
||||
name = survey.name || survey.id || survey.url;
|
||||
|
||||
if (id && url) {
|
||||
console.warn('Both "CDS ID" and url are given for ', survey, '. ID is chosen.')
|
||||
url = null;
|
||||
}
|
||||
|
||||
if (survey.properties) {
|
||||
cachedSurvey = {...cachedSurvey, ...survey.properties}
|
||||
}
|
||||
if (survey.options) {
|
||||
cachedSurvey = {...cachedSurvey, ...survey.options}
|
||||
}
|
||||
} else {
|
||||
console.warn('unable to parse the survey list item: ', survey)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (id) {
|
||||
cachedSurvey['id'] = id;
|
||||
}
|
||||
if (url) {
|
||||
cachedSurvey['url'] = url;
|
||||
}
|
||||
if (name) {
|
||||
cachedSurvey['name'] = name;
|
||||
}
|
||||
|
||||
// at least id or url is defined
|
||||
let key = id || url;
|
||||
|
||||
if (!(key in ImageSurvey.cache)) {
|
||||
ImageSurvey.cache[key] = cachedSurvey
|
||||
}
|
||||
}
|
||||
|
||||
ALEvent.HIPS_LIST_UPDATED.dispatchedTo(this.aladinDiv);
|
||||
}
|
||||
|
||||
if (hipsList.length === 0) {
|
||||
MocServer.getAllHiPSes()
|
||||
.then((HiPSes) => {
|
||||
HiPSes.forEach((h) => {
|
||||
hipsList.push({
|
||||
id: h.ID,
|
||||
name: h.obs_title
|
||||
})
|
||||
});
|
||||
|
||||
fillHiPSCache();
|
||||
});
|
||||
} else {
|
||||
fillHiPSCache();
|
||||
}
|
||||
|
||||
this.view.showCatalog(options.showCatalog);
|
||||
|
||||
// FullScreen toolbar icon
|
||||
@@ -412,6 +543,7 @@ export let Aladin = (function () {
|
||||
if (!options.showLayersControl) {
|
||||
stack._hide();
|
||||
}
|
||||
|
||||
// Add the simbad pointer control
|
||||
if (!options.showSimbadPointerControl) {
|
||||
simbad._hide();
|
||||
@@ -443,6 +575,10 @@ export let Aladin = (function () {
|
||||
this.addUI(new FullScreenActionButton(self))
|
||||
}
|
||||
|
||||
if (options.expandLayersControl) {
|
||||
stack.toggle();
|
||||
}
|
||||
|
||||
this._applyMediaQueriesUI();
|
||||
}
|
||||
|
||||
@@ -494,6 +630,8 @@ export let Aladin = (function () {
|
||||
Aladin.wasmLibs = {};
|
||||
Aladin.DEFAULT_OPTIONS = {
|
||||
survey: ImageSurvey.DEFAULT_SURVEY_ID,
|
||||
// surveys suggestion list
|
||||
hipsList: [],
|
||||
//surveyUrl: ["https://alaskybis.unistra.fr/DSS/DSSColor", "https://alasky.unistra.fr/DSS/DSSColor"],
|
||||
target: "0 +0",
|
||||
cooFrame: "J2000",
|
||||
@@ -504,6 +642,7 @@ export let Aladin = (function () {
|
||||
showZoomControl: false,
|
||||
// Menu toolbar
|
||||
showLayersControl: true,
|
||||
expandLayersControl: false,
|
||||
showFullscreenControl: true,
|
||||
showSimbadPointerControl: false,
|
||||
showCooGridControl: false,
|
||||
@@ -539,7 +678,7 @@ export let Aladin = (function () {
|
||||
log: true,
|
||||
samp: false,
|
||||
realFullscreen: false,
|
||||
pixelateCanvas: true
|
||||
pixelateCanvas: true,
|
||||
};
|
||||
|
||||
// realFullscreen: AL div expands not only to the size of its parent, but takes the whole available screen estate
|
||||
@@ -851,10 +990,11 @@ export let Aladin = (function () {
|
||||
// try to parse as a position
|
||||
if (!isObjectName) {
|
||||
var coo = new Coo();
|
||||
|
||||
coo.parse(targetName);
|
||||
// Convert from view coo sys to icrs
|
||||
|
||||
const [ra, dec] = this.wasm.viewToICRSCooSys(coo.lon, coo.lat);
|
||||
|
||||
this.view.pointTo(ra, dec);
|
||||
|
||||
(typeof successCallback === 'function') && successCallback(this.getRaDec());
|
||||
@@ -914,14 +1054,14 @@ export let Aladin = (function () {
|
||||
* @memberof Aladin
|
||||
* @param {number} lon - longitude in degrees
|
||||
* @param {number} lat - latitude in degrees
|
||||
* @param {string} frame - Optional callback options.
|
||||
* @param {string} [frame] - The name of the coordinate frame. Possible values: 'j2000d', 'j2000', 'gal', 'icrs'. The given string is case insensitive.
|
||||
*
|
||||
* @example
|
||||
* // Move to position
|
||||
* const aladin = A.aladin('#aladin-lite-div');
|
||||
* aladin.gotoPosition(20, 10, "galactic");
|
||||
*/
|
||||
Aladin.prototype.gotoPosition = function (lon, lat, frame = undefined) {
|
||||
Aladin.prototype.gotoPosition = function (lon, lat, frame) {
|
||||
var radec;
|
||||
// convert the frame from string to CooFrameEnum
|
||||
if (frame) {
|
||||
@@ -936,7 +1076,7 @@ export let Aladin = (function () {
|
||||
radec = [lon, lat];
|
||||
}
|
||||
|
||||
this.view.pointTo(radec[0], radec[1]);
|
||||
this.gotoRaDec(radec[0], radec[1]);
|
||||
};
|
||||
|
||||
var idTimeoutAnim;
|
||||
@@ -1140,9 +1280,15 @@ export let Aladin = (function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* point to a given position, expressed as a ra,dec coordinate
|
||||
* Moves the Aladin instance to the specified position given in ICRS frame
|
||||
*
|
||||
* @API
|
||||
* @memberof Aladin
|
||||
* @param {number} ra - Right-ascension in degrees
|
||||
* @param {number} dec - Declination in degrees
|
||||
*
|
||||
* @example
|
||||
* const aladin = A.aladin('#aladin-lite-div');
|
||||
* aladin.gotoRaDec(20, 10);
|
||||
*/
|
||||
Aladin.prototype.gotoRaDec = function (ra, dec) {
|
||||
this.view.pointTo(ra, dec);
|
||||
@@ -1239,7 +1385,15 @@ export let Aladin = (function () {
|
||||
let surveyOptions = ImageSurvey.cache[id];
|
||||
|
||||
if (!surveyOptions) {
|
||||
surveyOptions = {url, name, maxOrder, cooFrame, ...options};
|
||||
surveyOptions = {name, maxOrder, cooFrame, ...options};
|
||||
|
||||
// differenciate url from CDS Id in the url param given
|
||||
if (!Utils.isUrl(url)) {
|
||||
surveyOptions.id = url;
|
||||
} else {
|
||||
surveyOptions.url = url;
|
||||
}
|
||||
|
||||
ImageSurvey.cache[id] = surveyOptions;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,14 +214,15 @@ HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
|
||||
newUrlResp = validResponses[0];
|
||||
} else {
|
||||
// no valid response => we return an error
|
||||
return Promise.reject('Survey not found. All mirrors urls have been tested:' + urls)
|
||||
return Promise.reject('All mirrors urls have been tested:' + urls)
|
||||
}
|
||||
|
||||
// check if there is a big difference from the current one
|
||||
let currUrlResp = validResponses.find((r) => r.baseUrl === currUrl)
|
||||
|
||||
// it may happen that the url requested by the user is too slow hence discarded
|
||||
// for these cases, we automatically switch to the new fastest url.
|
||||
let urlChosen;
|
||||
if (Math.abs(currUrlResp.duration - newUrlResp.duration) / Math.min(currUrlResp.duration, newUrlResp.duration) < 0.10) {
|
||||
if (currUrlResp && Math.abs(currUrlResp.duration - newUrlResp.duration) / Math.min(currUrlResp.duration, newUrlResp.duration) < 0.10) {
|
||||
// there is not enough difference => do not switch
|
||||
urlChosen = currUrlResp.baseUrl;
|
||||
} else {
|
||||
|
||||
@@ -144,8 +144,7 @@ export let ImageSurvey = (function () {
|
||||
* @class
|
||||
* @constructs ImageSurvey
|
||||
*
|
||||
* @param {string} id - Mandatory unique identifier for the layer.
|
||||
* Can be an arbitrary name
|
||||
* @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
|
||||
*
|
||||
@@ -193,32 +192,29 @@ export let ImageSurvey = (function () {
|
||||
|
||||
self.query = (async () => {
|
||||
if (isMOCServerToBeQueried) {
|
||||
let properties;
|
||||
let isCDSId = false;
|
||||
try {
|
||||
properties = await HiPSProperties.fetchFromUrl(self.url)
|
||||
/*.catch((e) => {
|
||||
// try with the proxy
|
||||
url = Utils.handleCORSNotSameOrigin(url).href;
|
||||
|
||||
return HiPSProperties.fetchFromUrl(url);
|
||||
})*/
|
||||
.catch(async (e) => {
|
||||
// url not valid so we try with the id
|
||||
try {
|
||||
isCDSId = true;
|
||||
// the url stores a "CDS ID" we take it prioritaly
|
||||
// if the url is null, take the id, this is for some tests
|
||||
// to pass because some users might just give null as url param and a "CDS ID" as id param
|
||||
let id = self.url || self.id;
|
||||
return await HiPSProperties.fetchFromID(id);
|
||||
} catch(e) {
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
} catch(e) {
|
||||
throw e;
|
||||
}
|
||||
let properties = await HiPSProperties.fetchFromUrl(self.url)
|
||||
/*.catch((e) => {
|
||||
// try with the proxy
|
||||
url = Utils.handleCORSNotSameOrigin(url).href;
|
||||
|
||||
return HiPSProperties.fetchFromUrl(url);
|
||||
})*/
|
||||
.catch(async (e) => {
|
||||
// url not valid so we try with the id
|
||||
try {
|
||||
isCDSId = true;
|
||||
// the url stores a "CDS ID" we take it prioritaly
|
||||
// if the url is null, take the id, this is for some tests
|
||||
// to pass because some users might just give null as url param and a "CDS ID" as id param
|
||||
let id = self.url || self.id;
|
||||
return await HiPSProperties.fetchFromID(id);
|
||||
} catch(e) {
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
//obsTitle = properties.obs_title;
|
||||
self.creatorDid = properties.creator_did || self.creatorDid;
|
||||
@@ -238,24 +234,25 @@ export let ImageSurvey = (function () {
|
||||
if (self.url !== url) {
|
||||
console.info("Change url of ", self.id, " from ", self.url, " to ", url)
|
||||
|
||||
self.url = url;
|
||||
|
||||
// save the new url to the cache
|
||||
self._saveInCache();
|
||||
|
||||
// If added to the backend, then we need to tell it the url has changed
|
||||
if (self.added) {
|
||||
self.view.wasm.setHiPSUrl(self.creatorDid, url);
|
||||
}
|
||||
|
||||
self.url = url;
|
||||
|
||||
// save the new url to the cache
|
||||
ImageSurvey.cache[self.id].url = self.url;
|
||||
}
|
||||
})
|
||||
/*.catch(e => {
|
||||
.catch(e => {
|
||||
//alert(e);
|
||||
console.error(self)
|
||||
console.error(e);
|
||||
// the survey has been added so we remove it from the stack
|
||||
self.view.removeImageLayer(self.layer)
|
||||
//self.view.removeImageLayer(self.layer)
|
||||
//throw e;
|
||||
})*/
|
||||
})
|
||||
}
|
||||
|
||||
// Max order
|
||||
@@ -402,7 +399,13 @@ export let ImageSurvey = (function () {
|
||||
// append new important infos from the properties queried
|
||||
...surveyOpt,
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('new CACHE', ImageSurvey.cache, self.id, surveyOpt, ImageSurvey.cache[self.id], ImageSurvey.cache["CSIRO/P/RACS/mid/I"])
|
||||
|
||||
// Tell that the HiPS List has been updated
|
||||
ALEvent.HIPS_LIST_UPDATED.dispatchedTo(this.view.aladin.aladinDiv);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the ImageSurvey represents a planetary body.
|
||||
@@ -704,7 +707,7 @@ export let ImageSurvey = (function () {
|
||||
},
|
||||
});
|
||||
|
||||
this.added = true;
|
||||
//this.added = true;
|
||||
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
@@ -748,7 +751,7 @@ export let ImageSurvey = (function () {
|
||||
|
||||
// A cache storing directly surveys important information to not query for the properties each time
|
||||
ImageSurvey.cache = {
|
||||
DSS2_color: {
|
||||
/*DSS2_color: {
|
||||
creatorDid: "ivo://CDS/P/DSS2/color",
|
||||
name: "DSS colored",
|
||||
url: "https://alasky.cds.unistra.fr/DSS/DSSColor",
|
||||
@@ -913,6 +916,7 @@ export let ImageSurvey = (function () {
|
||||
stretch: 'linear',
|
||||
colormap: "redtemperature",
|
||||
}
|
||||
*/
|
||||
/*
|
||||
{
|
||||
id: "P/Finkbeiner",
|
||||
|
||||
@@ -110,7 +110,7 @@ export let MOC = (function() {
|
||||
* set MOC data by parsing a MOC serialized in JSON
|
||||
* (as defined in IVOA MOC document, section 3.1.1)
|
||||
*/
|
||||
MOC.prototype.parse = function(data, successCallback) {
|
||||
MOC.prototype.parse = function(data, successCallback, errorCallback) {
|
||||
if (typeof data === 'string' || data instanceof String) {
|
||||
let url = data;
|
||||
this.promiseFetchData = fetch(url)
|
||||
@@ -120,7 +120,7 @@ export let MOC = (function() {
|
||||
}
|
||||
|
||||
this.successCallback = successCallback;
|
||||
this.errorCallback = this.errorCallback;
|
||||
this.errorCallback = errorCallback;
|
||||
};
|
||||
|
||||
MOC.prototype.setView = function(view) {
|
||||
@@ -166,7 +166,11 @@ export let MOC = (function() {
|
||||
|
||||
self.view.requestRedraw();
|
||||
})
|
||||
.catch(e => alert('MOC load error:' + e))
|
||||
.catch(e => {
|
||||
console.error('MOC load error:' + e)
|
||||
if (self.errorCallback)
|
||||
self.errorCallback(self);
|
||||
})
|
||||
};
|
||||
|
||||
MOC.prototype.reportChange = function() {
|
||||
|
||||
@@ -469,6 +469,14 @@ Utils.fixURLForHTTPS = function (url) {
|
||||
return url
|
||||
}
|
||||
|
||||
Utils.isUrl = function(url) {
|
||||
try {
|
||||
return new URL(url).href;
|
||||
} catch(e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// generate an absolute URL from a relative URL
|
||||
// example: getAbsoluteURL('foo/bar/toto') return http://cds.unistra.fr/AL/foo/bar/toto if executed from page http://cds.unistra.fr/AL/
|
||||
Utils.getAbsoluteURL = function (url) {
|
||||
|
||||
@@ -488,8 +488,10 @@ export let View = (function () {
|
||||
|
||||
View.prototype.selectLayer = function (layer) {
|
||||
if (!this.imageLayers.has(layer)) {
|
||||
throw layer + ' does not exists. So cannot be selected';
|
||||
console.warn(layer + ' does not exists. So cannot be selected');
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedLayer = layer;
|
||||
};
|
||||
|
||||
@@ -1167,7 +1169,7 @@ export let View = (function () {
|
||||
}
|
||||
//requestAnimFrame(moveTo)
|
||||
}*/
|
||||
}, 30);
|
||||
}, 40);
|
||||
}
|
||||
|
||||
view.throttledTouchPadZoom();
|
||||
@@ -1578,10 +1580,20 @@ export let View = (function () {
|
||||
if (idxOverlayLayer == -1) {
|
||||
// it does not exist so we add it to the stack
|
||||
this.overlayLayers.push(layerName);
|
||||
} else {
|
||||
// it exists
|
||||
let alreadyPresentImageLayer = this.imageLayers.get(layerName);
|
||||
alreadyPresentImageLayer.added = false;
|
||||
}
|
||||
|
||||
imageLayer.added = true;
|
||||
this.imageLayers.set(layerName, imageLayer);
|
||||
|
||||
// select the layer if he is on top
|
||||
if (idxOverlayLayer == -1) {
|
||||
this.selectLayer(layerName);
|
||||
}
|
||||
|
||||
ALEvent.HIPS_LAYER_ADDED.dispatchedTo(this.aladinDiv, { layer: imageLayer });
|
||||
}
|
||||
|
||||
@@ -1678,11 +1690,6 @@ export let View = (function () {
|
||||
this.imageLayers.delete(layer);
|
||||
this.imageLayers.set(newLayer, imageLayer);
|
||||
|
||||
// Change the selected layer if this is the one renamed
|
||||
/*if (this.selectedLayer === layer) {
|
||||
this.selectedLayer = newLayer;
|
||||
}*/
|
||||
|
||||
// Tell the layer hierarchy has changed
|
||||
ALEvent.HIPS_LAYER_RENAMED.dispatchedTo(this.aladinDiv, { layer, newLayer });
|
||||
}
|
||||
@@ -1734,7 +1741,7 @@ export let View = (function () {
|
||||
this.empty = true;
|
||||
} else if (this.selectedLayer === layer) {
|
||||
// If the layer removed was selected then we select the base layer
|
||||
this.selectedLayer = 'base';
|
||||
this.selectLayer(this.overlayLayers[this.overlayLayers.length - 1]);
|
||||
}
|
||||
|
||||
ALEvent.HIPS_LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer });
|
||||
@@ -1857,11 +1864,11 @@ export let View = (function () {
|
||||
ra = parseFloat(ra);
|
||||
dec = parseFloat(dec);
|
||||
|
||||
if (isNaN(ra) || isNaN(dec)) {
|
||||
if (!ra || !dec) {
|
||||
return;
|
||||
}
|
||||
this.viewCenter.lon = ra;
|
||||
this.viewCenter.lat = dec;
|
||||
this.viewCenter.lat = dec;
|
||||
//this.updateLocation({lon: this.viewCenter.lon, lat: this.viewCenter.lat});
|
||||
|
||||
// Put a javascript code here to do some animation
|
||||
@@ -1905,7 +1912,13 @@ export let View = (function () {
|
||||
this.catalogs = [];
|
||||
this.overlays = [];
|
||||
this.mocs = [];
|
||||
|
||||
this.allOverlayLayers.forEach((overlay) => {
|
||||
ALEvent.GRAPHIC_OVERLAY_LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer: overlay });
|
||||
})
|
||||
this.allOverlayLayers = [];
|
||||
|
||||
this.mustClearCatalog = true;
|
||||
this.requestRedraw();
|
||||
};
|
||||
|
||||
@@ -1929,7 +1942,7 @@ export let View = (function () {
|
||||
this.overlays.splice(indexToDelete, 1);
|
||||
}
|
||||
|
||||
ALEvent.GRAPHIC_OVERLAY_LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer: layer });
|
||||
ALEvent.GRAPHIC_OVERLAY_LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer });
|
||||
|
||||
this.mustClearCatalog = true;
|
||||
this.requestRedraw();
|
||||
@@ -2000,7 +2013,7 @@ export let View = (function () {
|
||||
let closest = null;
|
||||
|
||||
footprints.forEach((footprint) => {
|
||||
if (!footprint.source.tooSmallFootprint) {
|
||||
if (!footprint.source || !footprint.source.tooSmallFootprint) {
|
||||
// Hidden footprints are not considered
|
||||
let lineWidth = footprint.getLineWidth();
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ export class ALEvent {
|
||||
static HIPS_LAYER_RENAMED = new ALEvent("AL:HiPSLayer.renamed");
|
||||
static HIPS_LAYER_SWAP = new ALEvent("AL:HiPSLayer.swap");
|
||||
|
||||
static HIPS_LIST_UPDATED = new ALEvent("AL:HiPSList.updated");
|
||||
|
||||
static HIPS_LAYER_CHANGED = new ALEvent("AL:HiPSLayer.changed");
|
||||
|
||||
static GRAPHIC_OVERLAY_LAYER_ADDED = new ALEvent("AL:GraphicOverlayLayer.added");
|
||||
|
||||
@@ -131,6 +131,7 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
}, aladin)
|
||||
|
||||
super({
|
||||
close: false,
|
||||
content: Layout.horizontal({
|
||||
layout: [inputText, loadBtn]
|
||||
}),
|
||||
@@ -238,10 +239,10 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
this.loadBtn.update({disable: true}, aladin)
|
||||
} else {
|
||||
let self = this;
|
||||
let layout = [];
|
||||
let ctxMenu = [];
|
||||
|
||||
if (item && item.cs_service_url) {
|
||||
layout.push({
|
||||
ctxMenu.push({
|
||||
label: 'Cone search',
|
||||
disable: !item.cs_service_url,
|
||||
action(o) {
|
||||
@@ -263,6 +264,8 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
})
|
||||
|
||||
self._hide();
|
||||
|
||||
self.callback && self.callback();
|
||||
},
|
||||
position: {
|
||||
anchor: 'center center',
|
||||
@@ -270,13 +273,12 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
})
|
||||
self.box._show();
|
||||
self.loadBtn.hideMenu()
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (item && item.hips_service_url) {
|
||||
layout.push({
|
||||
ctxMenu.push({
|
||||
label: 'HiPS catalogue',
|
||||
disable: !item.hips_service_url,
|
||||
action(o) {
|
||||
@@ -286,15 +288,22 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
})
|
||||
|
||||
self._hide();
|
||||
|
||||
self.callback && self.callback();
|
||||
}
|
||||
})
|
||||
}
|
||||
this.loadBtn.update({ctxMenu: layout, disable: false}, aladin)
|
||||
this.loadBtn.update({ctxMenu, disable: false}, aladin)
|
||||
}
|
||||
|
||||
this.loadBtn.hideMenu()
|
||||
}
|
||||
|
||||
attach(options) {
|
||||
this.callback = options.callback;
|
||||
super.update(options)
|
||||
}
|
||||
|
||||
_hide() {
|
||||
if (this.box) {
|
||||
this.box.remove();
|
||||
|
||||
@@ -79,6 +79,7 @@ import { Input } from "../Widgets/Input.js";
|
||||
|
||||
super(
|
||||
{
|
||||
close: false,
|
||||
content: Layout.horizontal({
|
||||
layout: [
|
||||
inputText,
|
||||
|
||||
@@ -40,15 +40,15 @@ import { ColorCfg } from "../../ColorCfg.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
|
||||
export class LayerEditBox extends Box {
|
||||
export class HiPSSettingsBox extends Box {
|
||||
// Constructor
|
||||
constructor(aladin, options) {
|
||||
super(
|
||||
{
|
||||
super({
|
||||
cssStyle: {
|
||||
padding: '4px',
|
||||
backgroundColor: 'black',
|
||||
},
|
||||
close: false,
|
||||
...options
|
||||
},
|
||||
aladin.aladinDiv
|
||||
@@ -162,21 +162,19 @@ import { ColorCfg } from "../../ColorCfg.js";
|
||||
|
||||
let layerOpacity = layer.getOpacity()
|
||||
|
||||
self.opacitySettingsContent = Layout.horizontal([
|
||||
Input.slider({
|
||||
tooltip: {content: layerOpacity, position: {direction: 'bottom'}},
|
||||
name: 'opacitySlider',
|
||||
type: 'range',
|
||||
min: 0.0,
|
||||
max: 1.0,
|
||||
value: layerOpacity,
|
||||
change(e, slider) {
|
||||
const opacity = +e.target.value;
|
||||
layer.setOpacity(opacity)
|
||||
slider.update({value: opacity, tooltip: {content: opacity.toFixed(2), position: {direction: 'bottom'}}})
|
||||
}
|
||||
}),
|
||||
]);
|
||||
self.opacitySettingsContent = Input.slider({
|
||||
tooltip: {content: layerOpacity, position: {direction: 'bottom'}},
|
||||
name: 'opacitySlider',
|
||||
type: 'range',
|
||||
min: 0.0,
|
||||
max: 1.0,
|
||||
value: layerOpacity,
|
||||
change(e, slider) {
|
||||
const opacity = +e.target.value;
|
||||
layer.setOpacity(opacity)
|
||||
slider.update({value: opacity, tooltip: {content: opacity.toFixed(2), position: {direction: 'bottom'}}})
|
||||
}
|
||||
})
|
||||
|
||||
let brightness = layer.getColorCfg().getBrightness()
|
||||
let saturation = layer.getColorCfg().getSaturation()
|
||||
@@ -311,10 +309,10 @@ import { ColorCfg } from "../../ColorCfg.js";
|
||||
|
||||
_addListeners() {
|
||||
ALEvent.HIPS_LAYER_CHANGED.listenedBy(this.aladin.aladinDiv, (e) => {
|
||||
const layerChanged = e.detail.layer;
|
||||
const hips = e.detail.layer;
|
||||
let selectedLayer = this.options.layer;
|
||||
if (selectedLayer && layerChanged.layer === selectedLayer.layer) {
|
||||
let colorCfg = layerChanged.getColorCfg();
|
||||
if (selectedLayer && hips.layer === selectedLayer.layer) {
|
||||
let colorCfg = hips.getColorCfg();
|
||||
|
||||
let cmap = colorCfg.getColormap();
|
||||
let reversed = colorCfg.getReversed();
|
||||
@@ -323,7 +321,9 @@ import { ColorCfg } from "../../ColorCfg.js";
|
||||
let [minCut, maxCut] = colorCfg.getCuts();
|
||||
this.minCutInput.set(+minCut.toFixed(2));
|
||||
this.maxCutInput.set(+maxCut.toFixed(2));
|
||||
this.stretchSelector.update({value: stretch})
|
||||
this.stretchSelector.update({value: stretch});
|
||||
|
||||
this.opacitySettingsContent.set(hips.getOpacity())
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -35,6 +35,7 @@ export class ShortLivedBox extends Box {
|
||||
constructor(aladin) {
|
||||
super(
|
||||
{
|
||||
close: false,
|
||||
cssStyle: {
|
||||
color: 'white',
|
||||
backgroundColor: 'black',
|
||||
|
||||
874
src/js/gui/Box/StackBox.js
Normal file
874
src/js/gui/Box/StackBox.js
Normal file
@@ -0,0 +1,874 @@
|
||||
// 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 searchIconUrl from '../../../../assets/icons/search.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 { ImageFITS } from "../../ImageFITS.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";
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
import { HiPSSearch } from "../Input/HiPSSearch.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', onClick: 'showTable'}},
|
||||
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) {
|
||||
super({
|
||||
close: false,
|
||||
header: {
|
||||
title: 'Stack',
|
||||
},
|
||||
classList: ['aladin-stack-box'],
|
||||
content: []
|
||||
},
|
||||
aladin.aladinDiv);
|
||||
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: 'More...'
|
||||
},
|
||||
action(o) {
|
||||
o.stopPropagation();
|
||||
o.preventDefault();
|
||||
|
||||
self._hide();
|
||||
|
||||
if (!self.catBox) {
|
||||
self.catBox = new CatalogQueryBox(self.aladin);
|
||||
self.catBox.attach({callback: () => {
|
||||
self._show();
|
||||
}});
|
||||
}
|
||||
|
||||
self.catBox._show({position: self.position});
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
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._hide();
|
||||
|
||||
self.aladin.select('circle', c => {
|
||||
try {
|
||||
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);
|
||||
|
||||
// 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, '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(
|
||||
{
|
||||
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, 'j2000');
|
||||
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: searchIconUrl,
|
||||
monochrome: true,
|
||||
tooltip: {content: 'From our database...', 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()
|
||||
}
|
||||
},
|
||||
ContextMenu.fileLoaderItem({
|
||||
label: 'FITS image file',
|
||||
accept: '.fits',
|
||||
action(file) {
|
||||
let url = URL.createObjectURL(file);
|
||||
|
||||
const image = self.aladin.createImageFITS(
|
||||
url,
|
||||
file.name,
|
||||
undefined,
|
||||
(ra, dec, fov, _) => {
|
||||
// Center the view around the new fits object
|
||||
self.aladin.gotoRaDec(ra, dec);
|
||||
self.aladin.setFoV(fov * 1.1);
|
||||
//self.aladin.selectLayer(image.layer);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
self.aladin.setOverlayImageLayer(image, Utils.uuidv4())
|
||||
}
|
||||
}),
|
||||
],
|
||||
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_RENAMED.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];
|
||||
|
||||
// change the ui from parameter changes
|
||||
// show button
|
||||
const opacity = hips.getOpacity();
|
||||
if (opacity !== 0.0) {
|
||||
ui.showBtn.update({icon: {monochrome: true, url: showIconUrl}, tooltip: {content: 'Hide'}});
|
||||
} else {
|
||||
ui.showBtn.update({icon: {monochrome: true, url: hideIconUrl}, tooltip: {content: 'Show'}});
|
||||
}
|
||||
});
|
||||
|
||||
updateOverlayList();
|
||||
|
||||
// Add a listener for HiPS list changes
|
||||
ALEvent.HIPS_LIST_UPDATED.listenedBy(this.aladin.aladinDiv, () => {
|
||||
// Recompute the autocompletion as the cache has changed
|
||||
HiPSSearch.HiPSList = {};
|
||||
for (var key in ImageSurvey.cache) {
|
||||
let HiPS = ImageSurvey.cache[key];
|
||||
// search with the name or id
|
||||
HiPSSearch.HiPSList[HiPS.name] = HiPS;
|
||||
}
|
||||
|
||||
let keys = Object.keys(HiPSSearch.HiPSList)
|
||||
// change the autocomplete of all the search input text
|
||||
for (var key in this.HiPSui) {
|
||||
let hips = this.HiPSui[key];
|
||||
hips.searchInput.setAutocompletionList(keys)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_hide() {
|
||||
for (var key in this.HiPSui) {
|
||||
let hips = this.HiPSui[key];
|
||||
if (hips.settingsBtn.toggled) {
|
||||
// toggle off
|
||||
hips.settingsBtn.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.catBox) {
|
||||
this.catBox._hide();
|
||||
}
|
||||
|
||||
if (this.addOverlayBtn)
|
||||
this.addOverlayBtn.hideMenu();
|
||||
|
||||
if (this.addHiPSBtn)
|
||||
this.addHiPSBtn.hideMenu();
|
||||
|
||||
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'],
|
||||
}))
|
||||
layout = layout.concat(this._createSurveysList());
|
||||
|
||||
return new Layout({layout, classList: ['content']});
|
||||
}
|
||||
|
||||
_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 showBtn = new ActionButton({
|
||||
size: 'small',
|
||||
icon: {
|
||||
url: overlay.isShowing ? showIconUrl : hideIconUrl,
|
||||
monochrome: true,
|
||||
},
|
||||
/*cssStyle: {
|
||||
visibility: Utils.hasTouchScreen() ? 'visible' : 'hidden',
|
||||
},*/
|
||||
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'}});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let deleteBtn = 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)
|
||||
}
|
||||
});
|
||||
|
||||
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: [showBtn, deleteBtn]})
|
||||
],
|
||||
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.getImageOverlays()).reverse().map((name) => {
|
||||
let overlay = self.aladin.getOverlayImageLayer(name);
|
||||
return overlay;
|
||||
});
|
||||
// survey list
|
||||
let selectedLayer = self.aladin.getSelectedLayer();
|
||||
|
||||
/*if (!layers) {
|
||||
super.attach(layout);
|
||||
return;
|
||||
}*/
|
||||
|
||||
let layout = [];
|
||||
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 searchInput = new HiPSSearch(self.aladin, {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);
|
||||
}
|
||||
});
|
||||
|
||||
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) => {
|
||||
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}), 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, btn) => {
|
||||
if (!btn.options.toggled) {
|
||||
// load the moc
|
||||
let moc = A.MOCFromURL(
|
||||
layer.url + '/Moc.fits',
|
||||
{lineWidth: 3, 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'
|
||||
})
|
||||
}
|
||||
|
||||
btn.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'
|
||||
})
|
||||
}
|
||||
|
||||
btn.update({
|
||||
toggled: false,
|
||||
tooltip: {content: 'Add coverage', position: {direction: 'top'}}
|
||||
})
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let layerClassName = 'a' + layer.layer.replace(/[.\/ ]/g, '')
|
||||
|
||||
let btns = [showBtn, settingsBtn];
|
||||
|
||||
if (layer.subtype !== 'fits') {
|
||||
btns.push(loadMOCBtn)
|
||||
}
|
||||
btns.push(deleteBtn)
|
||||
|
||||
let item = Layout.horizontal({
|
||||
layout: [
|
||||
searchInput,
|
||||
//'<div class="' + layerClassName + '" style="background-color: rgba(0, 0, 0, 0.6); line-height: 1rem; padding: 3px; border-radius: 3px; word-break: break-word;' + (selectedLayer === layer.layer ? 'border: 1px solid white;' : '') + '">' + (layer.name) + '</div>',
|
||||
Layout.horizontal(btns)
|
||||
],
|
||||
cssStyle: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
listStyle: 'none',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
}
|
||||
});
|
||||
|
||||
layout.push(item);
|
||||
|
||||
if (!(layer.layer in self.HiPSui)) {
|
||||
self.HiPSui[layer.layer] = {
|
||||
searchInput,
|
||||
settingsBox,
|
||||
settingsBtn,
|
||||
showBtn,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
/*_findPreviewImageUrl(layer) {
|
||||
if (layer instanceof ImageFITS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!layer.creatorDid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const creatorDid = layer.creatorDid;
|
||||
|
||||
for (const key in Stack.previewImagesUrl) {
|
||||
if (creatorDid.includes(key)) {
|
||||
return Stack.previewImagesUrl[key];
|
||||
}
|
||||
}
|
||||
// if not found
|
||||
return layer.url + '/preview.jpg'
|
||||
}*/
|
||||
|
||||
_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},
|
||||
})
|
||||
|
||||
const innerHeight = this.aladin.aladinDiv.offsetHeight;
|
||||
this.element().querySelectorAll(".surveyItem")
|
||||
.forEach((surveyItem) => {
|
||||
surveyItem.querySelectorAll(".aladin-context-sub-menu")
|
||||
// skip the first menu
|
||||
.forEach((subMenu) => {
|
||||
subMenu.style.display = 'block'
|
||||
|
||||
let Y = innerHeight - (subMenu.getBoundingClientRect().y - this.aladin.aladinDiv.getBoundingClientRect().y);
|
||||
subMenu.style.display = 'none'
|
||||
|
||||
subMenu.style.maxHeight = Y + 'px';
|
||||
subMenu.style.overflowY = 'scroll';
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ import { Icon } from "../Widgets/Icon";
|
||||
|
||||
export class StatusBarBox extends Box {
|
||||
constructor(aladin, options) {
|
||||
super(options, aladin.aladinDiv)
|
||||
super({...options, close: false}, aladin.aladinDiv)
|
||||
|
||||
this.addClass("aladin-status-bar");
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
import { CtxMenuActionButtonOpener } from "./CtxMenuOpener";
|
||||
import stackOverlayIconUrl from './../../../../assets/icons/stack.svg';
|
||||
import { OverlayStack } from "../CtxMenu/OverlayStack";
|
||||
import { OverlayStackBox } from "../Box/StackBox";
|
||||
import { TogglerActionButton } from "./Toggler";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -35,14 +37,15 @@ import { OverlayStack } from "../CtxMenu/OverlayStack";
|
||||
* Class representing a Tabs layout
|
||||
* @extends CtxMenuActionButtonOpener
|
||||
*/
|
||||
export class OverlayStackButton extends CtxMenuActionButtonOpener {
|
||||
export class OverlayStackButton extends TogglerActionButton {
|
||||
/**
|
||||
* UI responsible for displaying the viewport infos
|
||||
* @param {Aladin} aladin - The aladin instance.
|
||||
*/
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
let stack = new OverlayStack(aladin);
|
||||
let stack = new OverlayStackBox(aladin);
|
||||
|
||||
super({
|
||||
icon: {
|
||||
size: 'medium',
|
||||
@@ -56,7 +59,18 @@ import { OverlayStack } from "../CtxMenu/OverlayStack";
|
||||
direction: 'top right'
|
||||
}
|
||||
},
|
||||
ctxMenu: stack,
|
||||
toggled: false,
|
||||
actionOn: (e) => {
|
||||
stack._show({
|
||||
position: {
|
||||
nextTo: self,
|
||||
direction: 'right'
|
||||
}
|
||||
})
|
||||
},
|
||||
actionOff: (e) => {
|
||||
stack._hide()
|
||||
},
|
||||
...options
|
||||
}, aladin);
|
||||
|
||||
|
||||
@@ -43,20 +43,26 @@ export class TogglerActionButton extends ActionButton {
|
||||
...options,
|
||||
toggled,
|
||||
action(o) {
|
||||
toggled = !toggled;
|
||||
|
||||
self.update({toggled, tooltip: toggled ? options.tooltipOn : options.tooltipOff})
|
||||
if (toggled && options.actionOn) {
|
||||
options.actionOn(o)
|
||||
}
|
||||
|
||||
if (!toggled && options.actionOff) {
|
||||
options.actionOff(o)
|
||||
}
|
||||
|
||||
options.action && options.action(o)
|
||||
self.toggle(o);
|
||||
}
|
||||
})
|
||||
this.toggled = toggled;
|
||||
|
||||
self = this;
|
||||
}
|
||||
|
||||
toggle(o) {
|
||||
this.toggled = !this.toggled;
|
||||
|
||||
if (this.toggled && this.options.actionOn) {
|
||||
this.options.actionOn(o)
|
||||
}
|
||||
|
||||
if (!this.toggled && this.options.actionOff) {
|
||||
this.options.actionOff(o)
|
||||
}
|
||||
|
||||
// once the actions has been executed, modify the styling
|
||||
this.update({toggled: this.toggled, tooltip: this.toggled ? this.options.tooltipOn : this.options.tooltipOff})
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ import { CatalogQueryBox } from "../Box/CatalogQueryBox.js";
|
||||
import A from "../../A.js";
|
||||
import { Utils } from "../../../js/Utils";
|
||||
import { View } from "../../View.js";
|
||||
import { LayerEditBox } from "../Box/SurveyEditBox.js";
|
||||
import { HiPSSettingsBox } from "../Box/HiPSSettingsBox.js";
|
||||
import { HiPSSelectorBox } from "../Box/HiPSSelectorBox.js";
|
||||
import searchIconUrl from '../../../../assets/icons/search.svg';
|
||||
import showIconUrl from '../../../../assets/icons/show.svg';
|
||||
@@ -456,70 +456,6 @@ export class OverlayStack extends ContextMenu {
|
||||
}
|
||||
}
|
||||
|
||||
layout.push({
|
||||
label: 'Add survey',
|
||||
subMenu: [
|
||||
{
|
||||
label: {
|
||||
icon: {
|
||||
url: searchIconUrl,
|
||||
monochrome: true,
|
||||
tooltip: {content: 'From our database...', position: { direction: 'right' }},
|
||||
cssStyle: {
|
||||
cursor: 'help',
|
||||
},
|
||||
},
|
||||
content: 'Search for a 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.mode = 'hips';
|
||||
}
|
||||
},
|
||||
ContextMenu.fileLoaderItem({
|
||||
label: 'FITS image file',
|
||||
accept: '.fits',
|
||||
action(file) {
|
||||
let url = URL.createObjectURL(file);
|
||||
|
||||
const image = self.aladin.createImageFITS(
|
||||
url,
|
||||
file.name,
|
||||
undefined,
|
||||
(ra, dec, fov, _) => {
|
||||
// Center the view around the new fits object
|
||||
self.aladin.gotoRaDec(ra, dec);
|
||||
self.aladin.setFoV(fov * 1.1);
|
||||
//self.aladin.selectLayer(image.layer);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
|
||||
self.aladin.setOverlayImageLayer(image, Utils.uuidv4())
|
||||
}
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
// survey list
|
||||
let selectedLayer = self.aladin.getSelectedLayer();
|
||||
|
||||
@@ -669,7 +605,7 @@ export class OverlayStack extends ContextMenu {
|
||||
let item = Layout.horizontal({
|
||||
layout: [
|
||||
'<div class="' + layerClassName + '" style="background-color: rgba(0, 0, 0, 0.6); line-height: 1rem; padding: 3px; border-radius: 3px; word-break: break-word;' + (selectedLayer === layer.layer ? 'border: 1px solid white;' : '') + '">' + (layer.name) + '</div>',
|
||||
Layout.horizontal({layout: btns})
|
||||
Layout.horizontal(btns)
|
||||
],
|
||||
/*cssStyle: {
|
||||
display: 'flex',
|
||||
|
||||
@@ -42,29 +42,25 @@ export class FoV extends DOMElement {
|
||||
// constructor
|
||||
constructor(aladin, options) {
|
||||
let layout = [];
|
||||
|
||||
|
||||
if (options.showZoomControl) {
|
||||
layout.push(new ActionButton({
|
||||
let zoomIn = new ActionButton({
|
||||
classList: 'aladin-zoom-in',
|
||||
size: 'small',
|
||||
tooltip: {content: 'zoom in', position: {direction: 'top'}},
|
||||
icon: {
|
||||
monochrome: true,
|
||||
size: 'small',
|
||||
url: plusIconUrl,
|
||||
},
|
||||
cssStyle: {
|
||||
marginRight: 0,
|
||||
borderRight: 'none',
|
||||
borderRadius: '5px 0px 0px 5px'
|
||||
},
|
||||
action(o) {
|
||||
aladin.increaseZoom();
|
||||
}
|
||||
}))
|
||||
layout.push(new ActionButton({
|
||||
})
|
||||
let zoomOut = new ActionButton({
|
||||
size: 'small',
|
||||
cssStyle: {
|
||||
borderRadius: '0px 5px 5px 0px'
|
||||
},
|
||||
classList: 'aladin-zoom-out',
|
||||
tooltip: {content: 'zoom out', position: {direction: 'top'}},
|
||||
icon: {
|
||||
monochrome: true,
|
||||
size: 'small',
|
||||
@@ -73,7 +69,12 @@ export class FoV extends DOMElement {
|
||||
action(o) {
|
||||
aladin.decreaseZoom();
|
||||
}
|
||||
}))
|
||||
});
|
||||
zoomIn.el.classList.add('aladin-zoom-in');
|
||||
zoomOut.el.classList.add('aladin-zoom-out');
|
||||
|
||||
layout.push(zoomIn)
|
||||
layout.push(zoomOut)
|
||||
}
|
||||
|
||||
if (options.showFov) {
|
||||
@@ -82,10 +83,10 @@ export class FoV extends DOMElement {
|
||||
'<div class="aladin-monospace-text"></div>'])
|
||||
}
|
||||
|
||||
let el = Layout.horizontal({layout, tooltip: { content: 'FoV', position: {direction: "top"}}});
|
||||
if (el.tooltip) {
|
||||
el.tooltip.addClass('aladin-fov');
|
||||
el.tooltip.addClass('aladin-dark-theme')
|
||||
let el = Layout.horizontal({layout});
|
||||
if (el) {
|
||||
el.addClass('aladin-fov');
|
||||
el.addClass('aladin-dark-theme')
|
||||
}
|
||||
|
||||
super(el)
|
||||
|
||||
149
src/js/gui/Input/HiPSSearch.js
Normal file
149
src/js/gui/Input/HiPSSearch.js
Normal file
@@ -0,0 +1,149 @@
|
||||
// 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.
|
||||
//
|
||||
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/HiPSSelector.js
|
||||
*
|
||||
*
|
||||
* Author: Thomas Boch, Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// 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 Location.js
|
||||
*
|
||||
* Author: Thomas Boch[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Input } from "./../Widgets/Input.js";
|
||||
|
||||
export class HiPSSearch extends Input {
|
||||
static HiPSList = {};
|
||||
|
||||
// constructor
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
let layer = options && options.layer;
|
||||
|
||||
aladin.view.catalogCanvas.addEventListener('click', (e) => {
|
||||
self.el.blur();
|
||||
});
|
||||
|
||||
let prevKey = layer.name;
|
||||
super({
|
||||
name: 'HiPS search',
|
||||
type: 'text',
|
||||
classList: ['search'],
|
||||
name: 'survey',
|
||||
placeholder: "Survey keywords or url",
|
||||
autocomplete: {options: Object.keys(HiPSSearch.HiPSList)},
|
||||
title: layer.name,
|
||||
actions: {
|
||||
change(e) {
|
||||
const key = e.target.value;
|
||||
if (!key) {
|
||||
self.update({value: prevKey, title: prevKey});
|
||||
return;
|
||||
}
|
||||
|
||||
let image;
|
||||
// A user can put an url
|
||||
try {
|
||||
image = new URL(key).href;
|
||||
} catch(e) {
|
||||
// Or he can select a HiPS from the list given
|
||||
let hips = HiPSSearch.HiPSList[key]
|
||||
//console.log("HIPS", key, hips)
|
||||
if (hips) {
|
||||
image = hips.id || hips.url || undefined;
|
||||
} else {
|
||||
// Finally if not found, interpret the input text value as the HiPS (e.g. ID)
|
||||
image = key;
|
||||
}
|
||||
}
|
||||
|
||||
self.el.blur();
|
||||
|
||||
if (image) {
|
||||
prevKey = key;
|
||||
aladin.setOverlayImageLayer(image, layer.layer);
|
||||
}
|
||||
},
|
||||
/*input(e) {
|
||||
let value = e.target.value;
|
||||
|
||||
self.update({value, title: value})
|
||||
}*/
|
||||
},
|
||||
value: layer.name,
|
||||
...options
|
||||
})
|
||||
this.addClass('aladin-HiPS-search')
|
||||
|
||||
self = this;
|
||||
this.layer = layer;
|
||||
|
||||
this._addEventListeners(aladin);
|
||||
}
|
||||
|
||||
setAutocompletionList(options) {
|
||||
this.update({autocomplete: {options}})
|
||||
}
|
||||
|
||||
_addEventListeners(aladin) {
|
||||
let self = this;
|
||||
ALEvent.HIPS_LAYER_ADDED.listenedBy(aladin.aladinDiv, (e) => {
|
||||
const layer = e.detail.layer;
|
||||
if (layer.layer === self.layer.layer) {
|
||||
let value = layer.name
|
||||
self.update({value, title: value})
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
import { CooConversion } from "../CooConversion.js";
|
||||
import { Coo } from "../libs/astro/coo.js";
|
||||
import { CooFrameEnum } from "../CooFrameEnum.js";
|
||||
|
||||
@@ -146,7 +146,15 @@ export class Location extends DOMElement {
|
||||
let param = e.detail;
|
||||
|
||||
if (param.type === 'mouseout') {
|
||||
let [lon, lat] = aladin.getRaDec();
|
||||
let radec = aladin.getRaDec();
|
||||
// convert to the view frame
|
||||
let lonlat = radec;
|
||||
if (aladin.getFrame() === "Galactic") {
|
||||
lonlat = CooConversion.J2000ToGalactic(radec)
|
||||
}
|
||||
|
||||
let [lon, lat] = lonlat;
|
||||
|
||||
self.update({
|
||||
lon, lat,
|
||||
frame: aladin.view.cooFrame,
|
||||
|
||||
@@ -67,6 +67,25 @@ export class Box extends DOMElement {
|
||||
|
||||
let self = this;
|
||||
|
||||
let close = this.options.close === false ? false : true;
|
||||
if (close) {
|
||||
new ActionButton({
|
||||
size: 'small',
|
||||
content: '❌',
|
||||
//tooltip: {content: 'Close the window', position: {direction: 'bottom'}},
|
||||
action(e) {
|
||||
self._hide();
|
||||
},
|
||||
cssStyle: {
|
||||
position: 'absolute',
|
||||
},
|
||||
position: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
}
|
||||
}, this.el);
|
||||
}
|
||||
|
||||
// Check for the title
|
||||
if (this.options.header) {
|
||||
let header = this.options.header;
|
||||
@@ -98,23 +117,11 @@ export class Box extends DOMElement {
|
||||
titleEl.style.cursor = 'move'
|
||||
}
|
||||
|
||||
let closedEl = new ActionButton({
|
||||
size: 'small',
|
||||
content: '❌',
|
||||
tooltip: {content: 'Close the window', position: {direction: 'bottom'}},
|
||||
cssStyle: {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
action(e) {
|
||||
self._hide();
|
||||
}
|
||||
});
|
||||
|
||||
Layout.horizontal({
|
||||
cssStyle: {
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
layout: [draggableEl, titleEl, closedEl]
|
||||
layout: [draggableEl, titleEl]
|
||||
}, this.el);
|
||||
|
||||
let separatorEl = document.createElement('div')
|
||||
|
||||
@@ -135,7 +135,7 @@ export class Input extends DOMElement {
|
||||
}
|
||||
this.el.appendChild(datalist);
|
||||
|
||||
this.el.autocomplete = 'on';
|
||||
this.el.autocomplete = 'off';
|
||||
} else {
|
||||
this.el.autocomplete = autocomplete;
|
||||
}
|
||||
@@ -199,6 +199,10 @@ export class Input extends DOMElement {
|
||||
this.el.name = this.options.name;
|
||||
}
|
||||
|
||||
if (this.options.title) {
|
||||
this.el.title = this.options.title;
|
||||
}
|
||||
|
||||
this.el.classList.add('aladin-input');
|
||||
this.el.classList.add('aladin-dark-theme');
|
||||
|
||||
|
||||
@@ -146,9 +146,9 @@ export class DOMElement {
|
||||
}
|
||||
|
||||
const aladinDiv = options && options.aladin && options.aladin.aladinDiv;
|
||||
if (!aladinDiv) {
|
||||
return;
|
||||
}
|
||||
let innerWidth = aladinDiv && aladinDiv.offsetWidth;
|
||||
let innerHeight = aladinDiv && aladinDiv.offsetHeight;
|
||||
|
||||
|
||||
let left, top, bottom, right;
|
||||
let x, y;
|
||||
@@ -156,11 +156,8 @@ export class DOMElement {
|
||||
// handle the anchor/dir case with higher priority
|
||||
const {offsetWidth, offsetHeight} = el;
|
||||
|
||||
const innerWidth = aladinDiv.offsetWidth;
|
||||
const innerHeight = aladinDiv.offsetHeight;
|
||||
|
||||
// take on less priority the left and top
|
||||
if (options && (options.left || options.top || options.right || options.bottom)) {
|
||||
if (options && (options.left !== undefined || options.top !== undefined || options.right !== undefined || options.bottom !== undefined)) {
|
||||
el.style.position = 'absolute';
|
||||
|
||||
if (options.top !== undefined) {
|
||||
@@ -177,7 +174,7 @@ export class DOMElement {
|
||||
}
|
||||
|
||||
if (typeof top === 'number') {
|
||||
if (top + offsetHeight >= innerHeight) {
|
||||
if (innerHeight && top + offsetHeight >= innerHeight) {
|
||||
y = '-' + (top + offsetHeight - innerHeight) + 'px';
|
||||
} else if (top < 0) {
|
||||
y = Math.abs(top) + 'px';
|
||||
@@ -189,7 +186,7 @@ export class DOMElement {
|
||||
bottom = bottom + 'px';
|
||||
}
|
||||
if (typeof left === 'number') {
|
||||
if (left + offsetWidth > innerWidth) {
|
||||
if (innerWidth && left + offsetWidth > innerWidth) {
|
||||
x = '-' + (left + offsetWidth - innerWidth) + 'px';
|
||||
} else if (left < 0) {
|
||||
x = Math.abs(left) + 'px';
|
||||
|
||||
Reference in New Issue
Block a user