Compare commits

..

4 Commits
3.3.1 ... cssUI

Author SHA1 Message Date
Matthieu Baumann
3affe8c062 fix bug vscode jupyter on text input: suppr delete the widget 2024-03-11 13:44:27 +01:00
Matthieu Baumann
ce9644d83f fix and add doc concerning UI A.button and A.box methods 2024-03-11 11:46:28 +01:00
Matthieu Baumann
36b0f9392c add css classes for status bar, fullscreen, projection, share view button, location and FoV 2024-03-11 10:11:12 +01:00
Matthieu Baumann
dda9f07cb4 fix edit box and simplify the stack control 2024-03-09 09:55:06 +01:00
102 changed files with 2028 additions and 2327 deletions

View File

@@ -4,8 +4,7 @@ name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
tags:
- '*'
branches: ["develop"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

View File

@@ -6,9 +6,6 @@ name: Publish to NPM
on:
release:
types: [created]
push:
tags:
- '*'
workflow_dispatch:
jobs:

View File

@@ -2,19 +2,6 @@
## 3.3.0
* [fixed] multiple calls to setImageSurvey with the same survey object led to strange behaviour.
* [perf] Display the first tile received instantly with no blending. Should enhance the slow reported in issue #88.
* [fixed] A.on('select') (debugged from ipyaladin)
* [fixed] Simbad pointer in galactical frame, cone search of simbad/vizier cats/other cone search services in galactical frame and MOC creation from selection in galactical frame => there is now a new `frame` optional param to Aladin.pix2world. If not given, the coo returned are in the frame of the view.
* [doc] Add doc for image survey definition
* [deprecation] A.createImageSurvey/A.newImageSurvey are now deprecated (but still in the API). Please use `A.imageHiPS` instead by providing a valid url or CDS ID conformed to <https://aladin.cds.unistra.fr/hips/list>
* [refac] Simplify the instanciation of an imageHiPS/ imageFITS. Add a `A.imageHiPS` method for defining a HiPS object
* [fixed] At initialisation, giving a fov > 180 was clamped back to 180 even if we specify allsky projection (i.e. accepting fov > 180). This is now fixed.
* [fixed] MeasurementTable now display the full cell values (no ellipsis anymore)
* [fixed] aladin.on('select') has been implemented. Callback is triggered on a circle and rect selections for not on polygonal selection.
* [fixed] the cooFrame UI selector is updated if the user calls `aladin.setFrame`
* [fixed] `reticleColor` and `reticleSize` options in the public API
* Restore setFoVRange
* Add CSS class for positioning the UI elements as the user wants. See the API doc aladin options for the class names to use.
* [style] The default grid color is now `rgb(178, 50, 178)` to fit the classic Aladin color palette
* [feat] The object of grid options `gridOptions` is now available in the public API

View File

@@ -11,7 +11,6 @@ Aladin Lite is built to be easily embeddable in any web page. It powers astronom
More details on [Aladin Lite documentation page](http://aladin.u-strasbg.fr/AladinLite/doc/).
[![Run tests](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml/badge.svg)](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml)
[![API Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://cds-astro.github.io/aladin-lite)
# How to test it ?
@@ -143,53 +142,33 @@ to compile the core project into WebAssembly.
Follow the steps from the Rust official website [here](https://www.rust-lang.org/learn/get-started)
You will also need [wasm-pack](https://rustwasm.github.io/wasm-pack/), a tool helping compiling rust into a proper .wasm file.
Once it's installed you will need to switch to the nightly rust version:
```bash
rustup default nightly
```
Then you can build the project:
Once it's installed you can only build the project:
```bash
npm run build
```
:warning: **If you are experimenting rust error compilations**:
- Make sure you have your **wasm-pack** version updated. To do so:
```bash
cargo install wasm-pack --version ~0.12
```
- Make sure you are using the rust **nightly** toolchain
- Remove your `src/core/Cargo.lock` file and `src/core/target` directory -- this ensures that you'd escape any bad compilation state:
```bash
git clean -di
```
- then recompile with `npm run build`.
It will generate the aladin lite compiled code into a `dist/` directory located at the root of the repository. This directory contains two javascript files. `aladin.umd.cjs` follows the UMD module export convention and it is the one you can use for your project.
To run the examples, you can start a localhost server with the following command:
Or build it and launch a localhost server (usually starting on port 8080 but it can be another one if 8080 is occupied):
```bash
npm run serve
```
For just compiling the rust core, from the root location do:
For just compiling the rust core from the root location (it is faster to do so)
```bash
cd src/core
cargo check --features webgl2
```
and run the tests:
and run the tests
```bash
cd src/core
cargo test --features webgl2
```
To generate the Rust backend API documentation
```bash
cd src/core
cargo doc --no-deps --open
```

View File

@@ -1,2 +0,0 @@
<?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 32 32" xmlns="http://www.w3.org/2000/svg"><title>file_type_jupyter</title><path d="M26.233,3.588A1.69,1.69,0,1,1,24.473,2a1.67,1.67,0,0,1,1.76,1.585Z" style="fill:#767677"/><path d="M16.375,23.111c-4.487,0-8.43-1.61-10.469-3.988a11.162,11.162,0,0,0,20.938,0C24.81,21.5,20.882,23.111,16.375,23.111Z" style="fill:#f37726"/><path d="M16.375,7.648c4.487,0,8.43,1.61,10.469,3.988a11.162,11.162,0,0,0-20.938,0C7.945,9.253,11.869,7.648,16.375,7.648Z" style="fill:#f37726"/><path d="M10.2,27.739a2.109,2.109,0,1,1-.2-.8,2.129,2.129,0,0,1,.2.8Z" style="fill:#9e9e9e"/><path d="M6.416,7.106A1.226,1.226,0,1,1,7.608,5.83,1.241,1.241,0,0,1,6.416,7.106Z" style="fill:#616262"/></svg>

Before

Width:  |  Height:  |  Size: 836 B

View File

@@ -1,5 +0,0 @@
<?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="M15.197 3.35462C16.8703 1.67483 19.4476 1.53865 20.9536 3.05046C22.4596 4.56228 22.3239 7.14956 20.6506 8.82935L18.2268 11.2626M10.0464 14C8.54044 12.4882 8.67609 9.90087 10.3494 8.22108L12.5 6.06212" stroke="#1C274C" stroke-width="1.5" stroke-linecap="round"/>
<path d="M13.9536 10C15.4596 11.5118 15.3239 14.0991 13.6506 15.7789L11.2268 18.2121L8.80299 20.6454C7.12969 22.3252 4.55237 22.4613 3.0464 20.9495C1.54043 19.4377 1.67609 16.8504 3.34939 15.1706L5.77323 12.7373" stroke="#1C274C" stroke-width="1.5" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 776 B

View File

@@ -20,12 +20,14 @@
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {projection: 'MOL', cooFrame: 'galactic', fov: 360, fullScreen: true, showCooGrid: false, showReticle: false})
aladin = A.aladin('#aladin-lite-div', {cooFrame: 'galactic', fov: 400, fullScreen: true, showCooGrid: false, showReticle: false})
aladin.gotoRaDec(79.9525321, -69.2742586)
const gaiaFlux = aladin.createImageSurvey('P/DM/flux-G/I/355/gaiadr3', "GaiaDR3GFlux", null, null, null, {imgFormat: 'fits', stretch: 'log'})
aladin.setBaseImageLayer(gaiaFlux)
gaiaFlux.setCuts(3e5, 1e8)
aladin.setProjection('MOL')
function notify(title, sub, delay) {

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,14 +16,22 @@
showContextMenu: true,
fullScreen: true,
showSimbadPointerControl: true,
showSimbadPointerControl: false,
showShareControl: true,
showSettingsControl: true,
showStatusBar: {
position: {
bottom: 0,
left: '3rem'
},
},
showStackLayerControl: true,
samp: true,
});
aladin.addCatalog(A.catalogFromSimbad('M 82', 0.1, {onClick: 'showTable'}));
aladin.addCatalog(A.catalogFromNED('09 55 52.4 +69 40 47', 0.1, {onClick: 'showPopup', shape: 'plus'}));
A.catalogFromSimbad('09 55 52.4 +69 40 47', 0.1, {onClick: 'showTable', limit: 1000}, (cat) => {
aladin.addCatalog(cat)
});
aladin.addCatalog(A.catalogFromNED('09 55 52.4 +69 40 47', 0.1, {onClick: 'showPopup', shape: 'plus'}));
});
</script>

View File

@@ -36,8 +36,6 @@ A.init.then(() => {
console.log(objs, "are selected");
})
aladin.select();
});
</script>
</body>

View File

@@ -1,42 +0,0 @@
<!doctype html>
<html>
<head>
</head>
<body>
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
<script type="module">
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
var aladin = A.aladin(
'#aladin-lite-div',
{
survey: 'P/allWISE/color', // set initial image survey
projection: 'AIT', // set a projection
fov: 1.5, // initial field of view in degrees
target: 'NGC 2175', // initial target
cooFrame: 'galactic', // set galactic frame
reticleColor: '#00ff00', // change reticle color
reticleSize: 40, // change reticle size
gridOptions: {color: 'pink'},
showCooGrid: true, // set the grid
fullScreen: true,
showShareControl: true,
showSettingsControl: true,
showLayersControl: true,
showZoomControl: true,
showContextMenu: true,
showCooGridControl: true,
showSimbadPointerControl: true,
showFullscreenControl: true,
}
);
aladin.setFoVRange(1, 60)
});
</script>
</body>
</html>

View File

@@ -1,26 +0,0 @@
<!doctype html>
<html>
<head>
</head>
<body>
<div>
<div id="offset" style="display: inline-block; width: 200px; height: 100px"></div>
<div id="aladin-lite-div" style="display: inline-block; width: 50%"></div>
</div>
<!--<script type="text/javascript" src="https://aladin.cds.unistra.fr/AladinLite/api/v3/latest/aladin.js" charset="utf-8"></script>-->
<script>let aladin, hips</script>
<script type="module">
import A from '../src/js/A.js';
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {projection: 'TAN', cooFrame: 'galactic', showSettingsControl: true, showSimbadPointerControl: true, showContextMenu: true, target: 'galactic center', survey: 'P/Finkbeiner'});
// possible values are 'blues', 'cividis', 'cubehelix', 'eosb', 'grayscale', 'inferno', 'magma', 'native', 'parula', 'plasma', 'rainbow',
// 'rdbu', 'rdylbu', 'redtemperature', 'sinebow', 'spectral', 'summer', 'viridis', 'ylgnbu' and 'ylorbr'
//aladin.getBaseImageLayer().setColor([1.0, 0.0, 1.0, 1.0], { tf: 'Linear'} );
});
</script>
</body>
</html>

View File

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

View File

@@ -1,34 +0,0 @@
<!doctype html>
<html>
<head>
</head>
<body>
<div id="aladin-lite-div" style="width: 500px; height: 400px"></div>
<script type="module">
import A from '../src/js/A.js';
A.init.then(() => {
// Start up Aladin Lite
let aladin = A.aladin('#aladin-lite-div', {target: 'Sgr a*', fov: 0.5, showContextMenu: true});
let survey1 = aladin.getBaseImageLayer();
survey1.setColormap('magma', {stretch: 'linear'});
let survey2 = aladin.newImageSurvey("CDS/P/2MASS6X/H");
aladin.setImageLayer(survey2)
survey2.setColormap('rdbu', {stretch: 'asinh'});
let survey3 = aladin.newImageSurvey("https://alasky.cds.unistra.fr/CFHTLS-T0007b/Deep/UALLSKY/");
aladin.setImageLayer(survey3)
survey3.setColormap('cubehelix', {stretch: 'linear'});
aladin.setImageLayer(survey2);
aladin.setImageLayer(survey3);
aladin.setImageLayer(survey3);
//aladin.setOverlayImageLayer(survey2);
});
</script>
</body>
</html>

View File

@@ -10,7 +10,8 @@
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {survey: 'P/allWISE/color', target: 'galactic center'});
aladin = A.aladin('#aladin-lite-div', {target: 'galactic center'});
aladin.setImageSurvey('P/allWISE/color');
});
</script>

View File

@@ -8,10 +8,9 @@
<script type="module">
import A from '../src/js/A.js';
var aladin;
let aladin;
A.init.then(() => {
aladin = A.aladin(
var aladin = A.aladin(
'#aladin-lite-div',
{
survey: 'P/allWISE/color', // set initial image survey
@@ -24,14 +23,13 @@
gridOptions: {color: 'pink'},
showCooGrid: true, // set the grid
fullScreen: true,
showStatusBar: false,
showShareControl: true,
showSettingsControl: true,
showLayersControl: true,
showZoomControl: true,
showContextMenu: true,
showCooGridControl: true,
//showSimbadPointerControl: true,
showSimbadPointerControl: true,
showFullscreenControl: true,
}
);

View File

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

View File

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

View File

@@ -14,14 +14,13 @@
// Start up Aladin Lite
aladin = A.aladin('#aladin-lite-div', {
fov: 360,
projection: 'MER',
target: '0 0',
fullScreen: true,
survey: "CDS/P/Mars/Pan-Perseverance-PIA24422",
showCooGrid: true,
showCooGridControl: true,
});
aladin.setProjection('MER');
});
</script>

View File

@@ -6,18 +6,14 @@
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
<div id='aladin-statsDiv'></div>
<script>let aladin, hips</script>
<script type="module">
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {cooFrame: 'galactic', target: 'galactic center', survey: 'P/Finkbeiner'});
// possible values are 'blues', 'cividis', 'cubehelix', 'eosb', 'grayscale', 'inferno', 'magma', 'native', 'parula', 'plasma', 'rainbow',
// 'rdbu', 'rdylbu', 'redtemperature', 'sinebow', 'spectral', 'summer', 'viridis', 'ylgnbu' and 'ylorbr'
hips = aladin.getBaseImageLayer()
hips.setColormap("cubehelix");
aladin.setImageSurvey('astron.nl/P/lotss_dr2_high')
aladin.getBaseImageLayer().setColormap("cubehelix");
//aladin.getBaseImageLayer().setColor([1.0, 0.0, 1.0, 1.0], { tf: 'Linear'} );
});
</script>

View File

@@ -1,45 +0,0 @@
<!doctype html>
<html>
<head>
</head>
<body>
<script src="https://code.jquery.com/jquery-1.10.1.min.js"></script>
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
Show sources with proper motion greater than:
<input id='slider' style='vertical-align:middle;width:60vw;' step='1' min='0' max='10' type='range' value='0'>
<span id='pmVal' >0 mas/yr</span><br><br><div id='aladin-lite-div' style='width: 500px;height: 500px;'></div>
<script type="module">
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
var colorThreshold = 0;
var slider = document.getElementById('slider');
slider.oninput = function() {
colorThreshold = this.value;
$('#colorVal').html(colorThreshold);
cat.reportChange();
}
var myFilterFunction = function(source) {
const magB = parseFloat(source.data['B']);
const magV = parseFloat(source.data['V']);
if (isNaN(magB) || isNaN(magV) ) {
return false;
}
const color = magB - magV;
return color>colorThreshold;
}
aladin = A.aladin('#aladin-lite-div', {target: 'M 81', fov: 0.5, survey: 'CDS/P/SDSS9/color'});
var cat = A.catalogFromSimbad('M 81', 0.25, {onClick: 'showTable', verbosity: 3, filter: myFilterFunction});
aladin.addCatalog(cat);
});
</script>
</body>
</html>

View File

@@ -10,9 +10,9 @@
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, target: "Abell 194", fov: 180, projection: 'AIT', showContextMenu: true});
aladin.setImageSurvey('astron.nl/P/lotss_dr2_high')
A.catalogFromSKAORucio("Abell 194", 90, {onClick: 'showTable'}, (cat) => {
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, target: "Abell 194", fov: 180, projection: 'SIN', showContextMenu: true});
A.catalogFromSKAORucio("m51", 90, {onClick: 'showTable'}, (cat) => {
aladin.addCatalog(cat);
});

View File

@@ -5,6 +5,8 @@
<body>
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
<div id='aladin-statsDiv'></div>
<script type="module">
import A from '../src/js/A.js';

View File

@@ -2,7 +2,7 @@
"homepage": "https://aladin.u-strasbg.fr/",
"name": "aladin-lite",
"type": "module",
"version": "3.3.1",
"version": "3.3.1-beta",
"description": "An astronomical HiPS visualizer in the browser",
"author": "Thomas Boch and Matthieu Baumann",
"license": "GPL-3",
@@ -33,7 +33,7 @@
],
"scripts": {
"wasm": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2 -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort ",
"predeploy": "npm run build && rm -rf aladin-lite*.tgz && npm pack",
"predeploy": "npm run build && rm -rf aladin-lite.tgz && npm pack",
"deploy": "python3 deploy/deploy.py",
"build": "npm run wasm && vite build && cp examples/index.html dist/index.html",
"dev": "npm run build && vite",

View File

@@ -3,7 +3,7 @@ name = "aladin-lite"
description = "Aladin Lite v3 introduces a new graphical engine written in Rust with the use of WebGL"
license = "BSD-3-Clause"
repository = "https://github.com/cds-astro/aladin-lite"
version = "3.3.1"
version = "3.3.0"
authors = [ "baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr",]
edition = "2018"

View File

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

View File

@@ -60,14 +60,14 @@ pub struct Texture2D {
pub enum SamplerType {
Float,
Integer,
Unsigned,
Unsigned
}
use crate::image::format::ImageFormat;
//use super::pixel::PixelType;
use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use std::cell::RefCell;
impl Texture2D {
pub fn create_from_path<P: AsRef<Path>, F: ImageFormat>(
gl: &WebGlContext,
@@ -145,6 +145,7 @@ impl Texture2D {
onload.forget();
onerror.forget();
let gl = gl.clone();
Ok(Texture2D {
texture,
@@ -162,12 +163,16 @@ impl Texture2D {
tex_params: &'static [(u32, u32)],
data: Option<&[<F::P as Pixel>::Item]>,
) -> Result<Texture2D, JsValue> {
let texture = Texture2D::create_empty_with_format::<F>(gl, width, height, tex_params)?;
let texture = Texture2D::create_empty_with_format::<F>(
gl,
width,
height,
tex_params
)?;
if let Some(data) = data {
let buf_data = unsafe { F::view(data) };
texture
.bind()
texture.bind()
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
0,
0,
@@ -230,6 +235,7 @@ impl Texture2D {
None,
)
.expect("Texture 2D");
//gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D);
let gl = gl.clone();
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
@@ -323,8 +329,7 @@ impl Texture2D {
} else {
// set the viewport as the FBO won't be the same dimension as the screen
let metadata = self.metadata.as_ref().unwrap_abort().borrow();
self.gl
.viewport(x, y, metadata.width as i32, metadata.height as i32);
self.gl.viewport(x, y, metadata.width as i32, metadata.height as i32);
#[cfg(feature = "webgl2")]
let value = match (metadata.format, metadata.type_) {
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::UNSIGNED_BYTE) => {
@@ -645,4 +650,4 @@ impl<'a> Texture2DBoundMut<'a> {
)
.expect("Sub texture 2d");
}
}
}

View File

@@ -115,7 +115,7 @@ use cgmath::{Vector2, Vector3};
use futures::{io::BufReader, stream::StreamExt}; // for `next`
use crate::math::projection::*;
pub const BLENDING_ANIM_DURATION: DeltaTime = DeltaTime::from_millis(200.0); // in ms
pub const BLENDING_ANIM_DURATION: DeltaTime = DeltaTime::from_millis(400.0); // in ms
//use crate::buffer::Tile;
use crate::time::Time;
use cgmath::InnerSpace;
@@ -605,7 +605,7 @@ impl App {
Resource::Tile(tile) => {
if !has_camera_moved {
if let Some(survey) =
self.layers.get_mut_hips_from_cdid(&tile.get_hips_cdid())
self.layers.get_mut_hips_from_url(&tile.get_hips_url())
{
let cfg = survey.get_config();
@@ -620,10 +620,10 @@ impl App {
fov_coverage.intersects_cell(&neighbor_tile_cell)
});
//let is_tile_root = tile.cell().depth() == delta_depth;
//let _depth = tile.cell().depth();
let is_tile_root = tile.cell().depth() == delta_depth;
let _depth = tile.cell().depth();
// do not perform tex_sub costly GPU calls while the camera is zooming
if included_or_near_coverage {
if is_tile_root || included_or_near_coverage {
let is_missing = tile.missing();
/*self.tile_fetcher.notify_tile(
&tile,
@@ -648,6 +648,7 @@ impl App {
};
survey.add_tile(&cell, image, time_req)?;
self.request_redraw = true;
self.time_start_blending = Time::now();
@@ -659,9 +660,9 @@ impl App {
}
}
Resource::Allsky(allsky) => {
let hips_cdid = allsky.get_hips_cdid();
let hips_url = allsky.get_hips_url();
if let Some(survey) = self.layers.get_mut_hips_from_cdid(hips_cdid) {
if let Some(survey) = self.layers.get_mut_hips_from_url(hips_url) {
let is_missing = allsky.missing();
if is_missing {
// The allsky image is missing so we donwload all the tiles contained into
@@ -690,8 +691,7 @@ impl App {
}
}
Resource::PixelMetadata(metadata) => {
if let Some(hips) = self.layers.get_mut_hips_from_cdid(&metadata.hips_cdid)
{
if let Some(hips) = self.layers.get_mut_hips_from_url(&metadata.hips_url) {
let mut cfg = hips.get_config_mut();
if let Some(metadata) = *metadata.value.lock().unwrap_abort() {
@@ -702,9 +702,9 @@ impl App {
}
}
Resource::Moc(moc) => {
let moc_hips_cdid = moc.get_hips_cdid();
//let url = &moc_url[..moc_url.find("/Moc.fits").unwrap_abort()];
if let Some(hips) = self.layers.get_mut_hips_from_cdid(moc_hips_cdid) {
let moc_url = moc.get_url();
let url = &moc_url[..moc_url.find("/Moc.fits").unwrap_abort()];
if let Some(hips) = self.layers.get_mut_hips_from_url(url) {
let request::moc::Moc { moc, .. } = moc;
if let Some(moc) = &*moc.lock().unwrap_abort() {
@@ -756,13 +756,14 @@ impl App {
// - there is at least one tile in its blending phase
let blending_anim_occuring =
(Time::now() - self.time_start_blending) < BLENDING_ANIM_DURATION;
/*let start_fading = self.layers.values_hips().any(|hips| {
let start_fading = self.layers.values_hips().any(|hips| {
if let Some(start_time) = hips.get_ready_time() {
Time::now() - *start_time < BLENDING_ANIM_DURATION
} else {
false
}
});*/
});
// Finally update the camera that reset the flag camera changed
//if has_camera_moved {
@@ -786,7 +787,8 @@ impl App {
})
}
self.rendering = blending_anim_occuring | has_camera_moved | self.request_redraw /*| start_fading*/;
self.rendering =
blending_anim_occuring | has_camera_moved | self.request_redraw | start_fading;
self.request_redraw = false;
self.draw(false)?;
@@ -1187,13 +1189,17 @@ impl App {
self.layers.get_layer_cfg(layer)
}
pub(crate) fn set_hips_url(&mut self, cdid: &String, new_url: String) -> Result<(), JsValue> {
self.layers.set_survey_url(cdid, new_url.clone())?;
pub(crate) fn set_hips_url(
&mut self,
past_url: String,
new_url: String,
) -> Result<(), JsValue> {
self.layers.set_survey_url(past_url, new_url.clone())?;
//let hips = self.layers.get_hips_from_url(&new_url).unwrap_abort();
let hips = self.layers.get_hips_from_url(&new_url).unwrap_abort();
// Relaunch the base tiles for the survey to be ready with the new url
//self.tile_fetcher
// .launch_starting_hips_requests(hips, &mut self.downloader);
self.tile_fetcher
.launch_starting_hips_requests(hips, &mut self.downloader);
Ok(())
}
@@ -1296,8 +1302,12 @@ impl App {
self.request_redraw = true;
}
pub(crate) fn set_survey_url(&mut self, cdid: &String, new_url: String) -> Result<(), JsValue> {
self.layers.set_survey_url(cdid, new_url)
pub(crate) fn set_survey_url(
&mut self,
past_url: String,
new_url: String,
) -> Result<(), JsValue> {
self.layers.set_survey_url(past_url, new_url)
}
pub(crate) fn set_catalog_opacity(

View File

@@ -253,6 +253,41 @@ impl CameraViewPort {
);
}
fn set_canvas_size(&self, width: f32, height: f32) {
let canvas = self
.gl
.canvas()
.unwrap_abort()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap_abort();
canvas
.style()
.set_property("width", &format!("{}px", width))
.unwrap_abort();
canvas
.style()
.set_property("height", &format!("{}px", height))
.unwrap_abort();
/*grid_canvas
.style()
.set_property("width", &format!("{}px", width))
.unwrap_abort();
grid_canvas
.style()
.set_property("height", &format!("{}px", height))
.unwrap_abort();*/
canvas.set_width(self.width as u32);
canvas.set_height(self.height as u32);
//grid_canvas.set_width(self.width as u32);
//grid_canvas.set_height(self.height as u32);
// Once the canvas size is changed, we have to set the viewport as well
self.gl
.viewport(0, 0, self.width as i32, self.height as i32);
}
pub fn set_screen_size(&mut self, width: f32, height: f32, projection: &ProjectionType) {
self.width = (width as f32) * self.dpi;
self.height = (height as f32) * self.dpi;
@@ -275,18 +310,7 @@ impl CameraViewPort {
));
// Update the size of the canvas
let canvas = self
.gl
.canvas()
.unwrap_abort()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap_abort();
canvas.set_width(self.width as u32);
canvas.set_height(self.height as u32);
// Once the canvas size is changed, we have to set the viewport as well
self.gl
.viewport(0, 0, self.width as i32, self.height as i32);
self.set_canvas_size(width, height);
// Once it is done, recompute the scissor
self.recompute_scissor();
}

View File

@@ -11,8 +11,8 @@ pub struct Downloader {
requests: Vec<RequestType>,
queried_list: HashSet<QueryId>,
cache: Cache<QueryId, Resource>,
queried_cached_ids: Vec<QueryId>,
cache: Cache<Url, Resource>,
queried_cached_urls: Vec<Url>,
}
use crate::fifo_cache::Cache;
@@ -25,12 +25,12 @@ impl Downloader {
let requests = Vec::with_capacity(32);
let queried_list = HashSet::with_capacity(64);
let cache = Cache::new();
let queried_cached_ids = Vec::with_capacity(64);
let queried_cached_urls = Vec::with_capacity(64);
Self {
requests,
queried_list,
cache,
queried_cached_ids,
queried_cached_urls,
}
}
// Returns true if the fetch has been done
@@ -39,8 +39,8 @@ impl Downloader {
where
T: Query,
{
let id = query.id();
if self.cache.contains(id) {
let url = query.url();
if self.cache.contains(url) {
//self.queried_cached_urls.push(url.clone());
false
} else {
@@ -85,8 +85,8 @@ impl Downloader {
self.queried_list.remove(&query_id);
}
while let Some(id) = self.queried_cached_ids.pop() {
if let Some(rsc) = self.cache.extract(&id) {
while let Some(url) = self.queried_cached_urls.pop() {
if let Some(rsc) = self.cache.extract(&url) {
rscs.push(rsc);
}
}
@@ -105,7 +105,7 @@ impl Downloader {
}*/
pub fn delay_rsc(&mut self, rsc: Resource) {
self.queried_cached_ids.push(rsc.id().clone());
self.cache.insert(rsc.id().clone(), rsc);
self.queried_cached_urls.push(rsc.url().clone());
self.cache.insert(rsc.url().clone(), rsc);
}
}

View File

@@ -4,7 +4,7 @@ use super::request::RequestType;
pub trait Query: Sized {
type Request: From<Self> + Into<RequestType>;
fn hips_cdid(&self) -> &CreatorDid;
fn url(&self) -> &Url;
fn id(&self) -> &QueryId;
}
@@ -17,18 +17,17 @@ pub struct Tile {
pub cell: HEALPixCell,
pub format: ImageFormatType,
// The root url of the HiPS
pub hips_cdid: CreatorDid,
pub hips_url: Url,
// The total url of the query
pub url: Url,
pub id: QueryId,
}
use crate::renderable::CreatorDid;
use crate::{healpix::cell::HEALPixCell, survey::config::HiPSConfig};
impl Tile {
pub fn new(
cell: &HEALPixCell,
hips_cdid: String,
hips_id: String,
hips_url: String,
format: ImageFormatType,
) -> Self {
@@ -43,10 +42,10 @@ impl Tile {
hips_url, depth, dir_idx, idx, ext
);
let id = format!("{}{}{}{}", hips_cdid, depth, idx, ext);
let id = format!("{}{}{}{}", hips_id, depth, idx, ext);
Tile {
hips_cdid,
hips_url,
url,
cell: *cell,
format,
@@ -59,8 +58,8 @@ use super::request::tile::TileRequest;
impl Query for Tile {
type Request = TileRequest;
fn hips_cdid(&self) -> &CreatorDid {
&self.hips_cdid
fn url(&self) -> &Url {
&self.url
}
fn id(&self) -> &QueryId {
@@ -74,7 +73,7 @@ pub struct Allsky {
pub tile_size: i32,
pub texture_size: i32,
// The root url of the HiPS
pub hips_cdid: CreatorDid,
pub hips_url: Url,
// The total url of the query
pub url: Url,
pub id: QueryId,
@@ -82,20 +81,20 @@ pub struct Allsky {
impl Allsky {
pub fn new(cfg: &HiPSConfig) -> Self {
let hips_cdid = cfg.get_creator_did().to_string();
let hips_url = cfg.get_root_url().to_string();
let tile_size = cfg.get_tile_size();
let texture_size = cfg.get_texture_size();
let format = cfg.get_format();
let ext = format.get_ext_file();
let url = format!("{}/Norder3/Allsky.{}", cfg.get_root_url(), ext);
let url = format!("{}/Norder3/Allsky.{}", hips_url, ext);
let id = format!("{}Allsky{}", cfg.get_creator_did(), ext);
Allsky {
tile_size,
texture_size,
hips_cdid,
hips_url,
url,
format,
id,
@@ -107,8 +106,8 @@ use super::request::allsky::AllskyRequest;
impl Query for Allsky {
type Request = AllskyRequest;
fn hips_cdid(&self) -> &CreatorDid {
&self.hips_cdid
fn url(&self) -> &Url {
&self.url
}
fn id(&self) -> &QueryId {
@@ -120,7 +119,7 @@ impl Query for Allsky {
pub struct PixelMetadata {
pub format: ImageFormatType,
// The root url of the HiPS
pub hips_cdid: CreatorDid,
pub hips_url: Url,
// The total url of the query
pub url: Url,
pub id: QueryId,
@@ -128,15 +127,15 @@ pub struct PixelMetadata {
impl PixelMetadata {
pub fn new(cfg: &HiPSConfig) -> Self {
let hips_cdid = cfg.get_creator_did().to_string();
let hips_url = cfg.get_root_url().to_string();
let format = cfg.get_format();
let ext = format.get_ext_file();
let url = format!("{}/Norder3/Allsky.{}", cfg.get_root_url(), ext);
let url = format!("{}/Norder3/Allsky.{}", hips_url, ext);
let id = format!("{}Allsky{}", hips_cdid, ext);
let id = format!("{}Allsky{}", cfg.get_creator_did(), ext);
PixelMetadata {
hips_cdid,
hips_url,
url,
format,
id,
@@ -148,8 +147,8 @@ use super::request::blank::PixelMetadataRequest;
impl Query for PixelMetadata {
type Request = PixelMetadataRequest;
fn hips_cdid(&self) -> &CreatorDid {
&self.hips_cdid
fn url(&self) -> &Url {
&self.url
}
fn id(&self) -> &QueryId {
@@ -162,15 +161,10 @@ pub struct Moc {
// The total url of the query
pub url: Url,
pub params: al_api::moc::MOC,
pub hips_cdid: CreatorDid,
}
impl Moc {
pub fn new(url: String, hips_cdid: CreatorDid, params: al_api::moc::MOC) -> Self {
Moc {
url,
params,
hips_cdid,
}
pub fn new(url: String, params: al_api::moc::MOC) -> Self {
Moc { url, params }
}
}
@@ -178,8 +172,8 @@ use super::request::moc::MOCRequest;
impl Query for Moc {
type Request = MOCRequest;
fn hips_cdid(&self) -> &CreatorDid {
&self.hips_cdid
fn url(&self) -> &Url {
&self.url
}
fn id(&self) -> &QueryId {

View File

@@ -1,7 +1,6 @@
use std::io::Cursor;
use crate::downloader::query;
use crate::renderable::CreatorDid;
use al_core::image::format::ChannelType;
use al_core::image::ImageType;
@@ -10,7 +9,7 @@ use fitsrs::{fits::Fits, hdu::data::InMemData};
use super::{Request, RequestType};
use crate::downloader::QueryId;
pub struct AllskyRequest {
pub hips_cdid: CreatorDid,
pub hips_url: Url,
pub url: Url,
pub depth_tile: u8,
pub id: QueryId,
@@ -77,7 +76,7 @@ impl From<query::Allsky> for AllskyRequest {
format,
tile_size,
url,
hips_cdid,
hips_url,
texture_size,
id,
} = query;
@@ -208,7 +207,7 @@ impl From<query::Allsky> for AllskyRequest {
Self {
id,
hips_cdid,
hips_url,
depth_tile,
url,
request,
@@ -310,7 +309,7 @@ pub struct Allsky {
pub time_req: Time,
pub depth_tile: u8,
pub hips_cdid: CreatorDid,
pub hips_url: Url,
url: Url,
}
@@ -321,8 +320,8 @@ impl Allsky {
self.image.lock().unwrap_abort().is_none()
}
pub fn get_hips_cdid(&self) -> &CreatorDid {
&self.hips_cdid
pub fn get_hips_url(&self) -> &Url {
&self.hips_url
}
pub fn get_url(&self) -> &Url {
@@ -334,7 +333,7 @@ impl<'a> From<&'a AllskyRequest> for Option<Allsky> {
fn from(request: &'a AllskyRequest) -> Self {
let AllskyRequest {
request,
hips_cdid,
hips_url,
depth_tile,
url,
..
@@ -347,7 +346,7 @@ impl<'a> From<&'a AllskyRequest> for Option<Allsky> {
time_req: *time_request,
// This is a clone on a Arc, it is supposed to be fast
image: data.clone(),
hips_cdid: hips_cdid.clone(),
hips_url: hips_url.clone(),
url: url.clone(),
depth_tile: *depth_tile,
})

View File

@@ -2,7 +2,6 @@ use al_core::image::format::ChannelType;
use std::io::Cursor;
use crate::downloader::query;
use crate::renderable::CreatorDid;
use fitsrs::fits::Fits;
#[derive(Debug, Clone, Copy)]
@@ -28,7 +27,7 @@ use crate::downloader::QueryId;
pub struct PixelMetadataRequest {
pub id: QueryId,
pub url: Url,
pub hips_cdid: CreatorDid,
pub hips_url: Url,
request: Request<Metadata>,
}
@@ -50,7 +49,7 @@ impl From<query::PixelMetadata> for PixelMetadataRequest {
let query::PixelMetadata {
format,
url,
hips_cdid,
hips_url,
id,
} = query;
@@ -127,7 +126,7 @@ impl From<query::PixelMetadata> for PixelMetadataRequest {
Self {
id,
url,
hips_cdid,
hips_url,
request,
}
}
@@ -137,7 +136,7 @@ use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub struct PixelMetadata {
pub value: Arc<Mutex<Option<Metadata>>>,
pub hips_cdid: CreatorDid,
pub hips_url: String,
pub url: String,
}
use crate::Abort;
@@ -145,7 +144,7 @@ impl<'a> From<&'a PixelMetadataRequest> for Option<PixelMetadata> {
fn from(request: &'a PixelMetadataRequest) -> Self {
let PixelMetadataRequest {
request,
hips_cdid,
hips_url,
url,
..
} = request;
@@ -153,7 +152,7 @@ impl<'a> From<&'a PixelMetadataRequest> for Option<PixelMetadata> {
let Request::<Metadata> { data, .. } = request;
// It will always be resolved and found as we will request a well know tile (Norder0/Tile0)
Some(PixelMetadata {
hips_cdid: hips_cdid.clone(),
hips_url: hips_url.clone(),
url: url.to_string(),
value: data.clone(),
})

View File

@@ -1,5 +1,4 @@
use crate::downloader::query;
use crate::renderable::CreatorDid;
use super::{Request, RequestType};
use crate::downloader::QueryId;
@@ -9,7 +8,7 @@ use moclib::qty::Hpx;
pub struct MOCRequest {
//pub id: QueryId,
pub hips_cdid: CreatorDid,
pub url: Url,
pub params: al_api::moc::MOC,
request: Request<HEALPixCoverage>,
}
@@ -49,11 +48,7 @@ use wasm_bindgen::JsValue;
impl From<query::Moc> for MOCRequest {
// Create a tile request associated to a HiPS
fn from(query: query::Moc) -> Self {
let query::Moc {
url,
params,
hips_cdid,
} = query;
let query::Moc { url, params } = query;
let url_clone = url.clone();
@@ -93,8 +88,7 @@ impl From<query::Moc> for MOCRequest {
Self {
//id,
//url,
hips_cdid,
url,
request,
params,
}
@@ -105,12 +99,12 @@ use std::sync::{Arc, Mutex};
pub struct Moc {
pub moc: Arc<Mutex<Option<HEALPixCoverage>>>,
pub params: al_api::moc::MOC,
pub hips_cdid: Url,
pub url: Url,
}
impl Moc {
pub fn get_hips_cdid(&self) -> &Url {
&self.hips_cdid
pub fn get_url(&self) -> &Url {
&self.url
}
}
@@ -118,7 +112,7 @@ impl<'a> From<&'a MOCRequest> for Option<Moc> {
fn from(request: &'a MOCRequest) -> Self {
let MOCRequest {
request,
hips_cdid,
url,
params,
..
} = request;
@@ -127,7 +121,7 @@ impl<'a> From<&'a MOCRequest> for Option<Moc> {
Some(Moc {
// This is a clone on a Arc, it is supposed to be fast
moc: data.clone(),
hips_cdid: hips_cdid.clone(),
url: url.clone(),
params: params.clone(),
})
} else {

View File

@@ -95,7 +95,7 @@ impl RequestType {
RequestType::Tile(request) => &request.id,
RequestType::Allsky(request) => &request.id,
RequestType::PixelMetadata(request) => &request.id,
RequestType::Moc(request) => &request.hips_cdid,
RequestType::Moc(request) => &request.url,
}
}
}
@@ -125,12 +125,12 @@ pub enum Resource {
}
impl Resource {
pub fn id(&self) -> &String {
pub fn url(&self) -> &Url {
match self {
Resource::Tile(tile) => tile.get_hips_cdid(),
Resource::Allsky(allsky) => allsky.get_hips_cdid(),
Resource::PixelMetadata(PixelMetadata { hips_cdid, .. }) => hips_cdid,
Resource::Moc(moc) => moc.get_hips_cdid(),
Resource::Tile(tile) => tile.get_url(),
Resource::Allsky(allsky) => allsky.get_url(),
Resource::PixelMetadata(PixelMetadata { url, .. }) => url,
Resource::Moc(moc) => moc.get_url(),
}
}
}

View File

@@ -1,5 +1,4 @@
use crate::healpix::cell::HEALPixCell;
use crate::renderable::CreatorDid;
use al_core::image::format::{ChannelType, ImageFormatType, RGB8U, RGBA8U};
use crate::downloader::query;
@@ -13,7 +12,7 @@ pub struct TileRequest {
pub id: QueryId,
cell: HEALPixCell,
hips_cdid: CreatorDid,
hips_url: Url,
url: Url,
format: ImageFormatType,
@@ -58,7 +57,7 @@ impl From<query::Tile> for TileRequest {
format,
cell,
url,
hips_cdid,
hips_url,
id,
} = query;
@@ -178,7 +177,7 @@ impl From<query::Tile> for TileRequest {
cell,
format,
id,
hips_cdid,
hips_url,
url,
request,
}
@@ -192,7 +191,7 @@ pub struct Tile {
pub time_req: Time,
pub cell: HEALPixCell,
pub format: ImageFormatType,
hips_cdid: CreatorDid,
hips_url: Url,
url: Url,
}
@@ -204,8 +203,8 @@ impl Tile {
}
#[inline(always)]
pub fn get_hips_cdid(&self) -> &CreatorDid {
&self.hips_cdid
pub fn get_hips_url(&self) -> &Url {
&self.hips_url
}
#[inline(always)]
@@ -229,7 +228,7 @@ impl<'a> From<&'a TileRequest> for Option<Tile> {
let TileRequest {
cell,
request,
hips_cdid,
hips_url,
url,
format,
..
@@ -243,7 +242,7 @@ impl<'a> From<&'a TileRequest> for Option<Tile> {
time_req: *time_request,
// This is a clone on a Arc, it is supposed to be fast
image: data.clone(),
hips_cdid: hips_cdid.clone(),
hips_url: hips_url.clone(),
url: url.clone(),
format: *format,
})

View File

@@ -404,8 +404,8 @@ impl WebClient {
}
#[wasm_bindgen(js_name = setHiPSUrl)]
pub fn set_hips_url(&mut self, cdid: String, new_url: String) -> Result<(), JsValue> {
self.app.set_hips_url(&cdid, new_url)
pub fn set_hips_url(&mut self, past_url: String, new_url: String) -> Result<(), JsValue> {
self.app.set_hips_url(past_url, new_url)
}
#[wasm_bindgen(js_name = getImageMetadata)]
@@ -422,8 +422,8 @@ impl WebClient {
}
#[wasm_bindgen(js_name = setImageSurveyUrl)]
pub fn set_survey_url(&mut self, cdid: String, new_url: String) -> Result<(), JsValue> {
self.app.set_survey_url(&cdid, new_url)
pub fn set_survey_url(&mut self, past_url: String, new_url: String) -> Result<(), JsValue> {
self.app.set_survey_url(past_url, new_url)
}
#[wasm_bindgen(js_name = setBackgroundColor)]

View File

@@ -4,10 +4,10 @@ pub mod uv;
use al_api::hips::ImageExt;
use al_api::hips::ImageMetadata;
use al_core::colormap::Colormap;
use al_core::colormap::Colormaps;
use al_core::image::format::ChannelType;
use al_core::image::format::ImageFormatType;
use al_core::image::Image;
use al_core::log::console_log;
use al_core::shader::Shader;
@@ -30,7 +30,6 @@ use crate::math::angle::ToAngle;
use crate::math::lonlat::LonLat;
use crate::time::Time;
use al_core::log;
use std::collections::HashSet;
// Recursively compute the number of subdivision needed for a cell
// to not be too much skewed
@@ -283,7 +282,9 @@ pub fn get_raster_shader<'a>(
shaders: &'a mut ShaderManager,
config: &HiPSConfig,
) -> Result<&'a Shader, JsValue> {
if config.get_format().is_colored() && cmap.label() == "native" {
let colored_hips = config.is_colored();
if colored_hips && cmap.label() == "native" {
crate::shader::get_shader(gl, shaders, "RasterizerVS", "RasterizerColorFS")
} else {
if config.tex_storing_unsigned_int {
@@ -317,8 +318,8 @@ pub fn get_raytracer_shader<'a>(
shaders: &'a mut ShaderManager,
config: &HiPSConfig,
) -> Result<&'a Shader, JsValue> {
//let colored_hips = config.is_colored();
if config.get_format().is_colored() && cmap.label() == "native" {
let colored_hips = config.is_colored();
if colored_hips && cmap.label() == "native" {
crate::shader::get_shader(gl, shaders, "RayTracerVS", "RayTracerColorFS")
} else {
if config.tex_storing_unsigned_int {
@@ -529,12 +530,11 @@ impl HiPS {
pub fn look_for_new_tiles<'a>(
&'a mut self,
camera: &'a mut CameraViewPort,
) -> Option<impl Iterator<Item = HEALPixCell> + 'a> {
) -> Option<impl Iterator<Item = &'a HEALPixCell> + 'a> {
// do not add tiles if the view is already at depth 0
let depth_tile = (camera.get_texture_depth() + self.get_config().delta_depth())
.min(self.get_config().get_max_depth_tile())
.max(self.get_config().get_min_depth_tile());
let dd = self.get_config().delta_depth();
//let min_depth_tile = self.get_min_depth_tile();
//let delta_depth = self.get_config().delta_depth();
@@ -549,25 +549,13 @@ impl HiPS {
//if depth_tile >= min_bound_depth {
//let depth_tile = depth_tile.max(min_bound_depth);
let survey_frame = self.get_config().get_frame();
let mut already_considered_tiles = HashSet::new();
let tile_cells_iter = camera
.get_hpx_cells(depth_tile, survey_frame)
//.flat_map(move |cell| {
// let texture_cell = cell.get_texture_cell(delta_depth);
// texture_cell.get_tile_cells(delta_depth)
//})
.flat_map(move |tile_cell| {
let tex_cell = tile_cell.get_texture_cell(dd);
//console_log(&format!("{:?}, dd:{:?}", tex_cell, dd));
tex_cell.get_tile_cells(dd)
})
.filter(move |tile_cell| {
if already_considered_tiles.contains(tile_cell) {
return false;
}
already_considered_tiles.insert(*tile_cell);
if let Some(moc) = self.footprint_moc.as_ref() {
moc.intersects_cell(tile_cell) && !self.update_priority_tile(tile_cell)
} else {
@@ -630,7 +618,7 @@ impl HiPS {
self.textures.set_format(&self.gl, ext)
}
/*pub fn get_fading_factor(&self) -> f32 {
pub fn get_fading_factor(&self) -> f32 {
self.textures
.start_time
.map(|start_time| {
@@ -638,7 +626,7 @@ impl HiPS {
fading.clamp(0.0, 1.0)
})
.unwrap_or(0.0)
}*/
}
pub fn is_allsky(&self) -> bool {
self.textures.config().is_allsky
@@ -730,22 +718,15 @@ impl HiPS {
if let Some(cell) = cell {
let texture_to_draw = if self.textures.contains(cell) {
let parent_cell = self.textures.get_nearest_parent(cell);
if let Some(ending_cell_in_tex) = self.textures.get(cell) {
if let Some(parent_cell) = self.textures.get_nearest_parent(cell) {
if let Some(starting_cell_in_tex) = self.textures.get(&parent_cell) {
Some(TextureToDraw::new(
starting_cell_in_tex,
ending_cell_in_tex,
cell,
))
} else {
// no blending here
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
if let Some(starting_cell_in_tex) = self.textures.get(&parent_cell) {
Some(TextureToDraw::new(
starting_cell_in_tex,
ending_cell_in_tex,
cell,
))
} else {
Some(TextureToDraw::new(
ending_cell_in_tex,
@@ -757,36 +738,22 @@ impl HiPS {
None
}
} else {
if let Some(parent_cell) = self.textures.get_nearest_parent(cell) {
if let Some(ending_cell_in_tex) = self.textures.get(&parent_cell) {
if let Some(grand_parent_cell) =
self.textures.get_nearest_parent(&parent_cell)
{
if let Some(starting_cell_in_tex) =
self.textures.get(&grand_parent_cell)
{
Some(TextureToDraw::new(
starting_cell_in_tex,
ending_cell_in_tex,
cell,
))
} else {
// no blending
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
} else {
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
let parent_cell = self.textures.get_nearest_parent(cell);
let grand_parent_cell = self.textures.get_nearest_parent(&parent_cell);
if let Some(ending_cell_in_tex) = self.textures.get(&parent_cell) {
if let Some(starting_cell_in_tex) = self.textures.get(&grand_parent_cell) {
Some(TextureToDraw::new(
starting_cell_in_tex,
ending_cell_in_tex,
cell,
))
} else {
None
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
} else {
None
@@ -1035,8 +1002,8 @@ impl HiPS {
} = cfg;
// Add starting fading
//let fading = self.get_fading_factor();
//let opacity = opacity * fading;
let fading = self.get_fading_factor();
let opacity = opacity * fading;
// Get the colormap from the color
let cmap = colormaps.get(color.cmap_name.as_ref());
@@ -1054,7 +1021,7 @@ impl HiPS {
.attach_uniform("model", &w2v)
.attach_uniform("inv_model", &v2w)
.attach_uniform("current_time", &utils::get_current_time())
.attach_uniform("opacity", opacity)
.attach_uniform("opacity", &opacity)
.attach_uniforms_from(colormaps);
raytracer.draw(&shader);
@@ -1082,7 +1049,7 @@ impl HiPS {
.attach_uniform("model", &w2v)
.attach_uniform("inv_model", &v2w)
.attach_uniform("current_time", &utils::get_current_time())
.attach_uniform("opacity", opacity)
.attach_uniform("opacity", &opacity)
.attach_uniforms_from(colormaps)
.bind_vertex_array_object_ref(&self.vao)
.draw_elements_with_i32(

View File

@@ -47,17 +47,15 @@ pub trait Renderer {
}
pub(crate) type Url = String;
pub(crate) type CreatorDid = String;
type LayerId = String;
pub struct Layers {
// Surveys to query
surveys: HashMap<CreatorDid, HiPS>,
surveys: HashMap<Url, HiPS>,
images: HashMap<Url, Image>,
// The meta data associated with a layer
meta: HashMap<LayerId, ImageMetadata>,
// Hashmap between FITS image urls/HiPS creatorDid and layers
ids: HashMap<LayerId, String>,
// Hashmap between urls and layers
urls: HashMap<LayerId, Url>,
// Layers given in a specific order to draw
layers: Vec<LayerId>,
@@ -114,7 +112,7 @@ impl Layers {
let surveys = HashMap::new();
let images = HashMap::new();
let meta = HashMap::new();
let ids = HashMap::new();
let urls = HashMap::new();
let layers = Vec::new();
// - The raytracer is a mesh covering the view. Each pixel of this mesh
@@ -166,7 +164,7 @@ impl Layers {
images,
meta,
ids,
urls,
layers,
raytracer,
@@ -178,19 +176,19 @@ impl Layers {
})
}
pub fn set_survey_url(&mut self, cdid: &CreatorDid, new_url: String) -> Result<(), JsValue> {
if let Some(mut survey) = self.surveys.get_mut(cdid) {
pub fn set_survey_url(&mut self, past_url: String, new_url: String) -> Result<(), JsValue> {
if let Some(mut survey) = self.surveys.remove(&past_url) {
// update the root_url
survey.get_config_mut().set_root_url(new_url.clone());
//self.surveys.insert(new_url.clone(), survey);
self.surveys.insert(new_url.clone(), survey);
// update all the layer urls
/*for id in self.ids.values_mut() {
if *id == past_url {
*id = new_url.clone();
for url in self.urls.values_mut() {
if *url == past_url {
*url = new_url.clone();
}
}*/
}
Ok(())
} else {
@@ -229,8 +227,8 @@ impl Layers {
// if there are, we do not draw nothing
let render_background_color = !self.layers.iter().any(|layer| {
let meta = self.meta.get(layer).unwrap_abort();
let cdid = self.ids.get(layer).unwrap_abort();
if let Some(survey) = self.surveys.get(cdid) {
let url = self.urls.get(layer).unwrap_abort();
if let Some(survey) = self.surveys.get(url) {
let hips_cfg = survey.get_config();
(survey.is_allsky() || hips_cfg.get_format().get_channel() == ChannelType::RGB8U)
&& meta.opacity == 1.0
@@ -272,8 +270,8 @@ impl Layers {
for (idx_layer, layer) in self.layers.iter().enumerate().skip(1) {
let meta = self.meta.get(layer).expect("Meta should be found");
let id = self.ids.get(layer).expect("Url should be found");
if let Some(survey) = self.surveys.get_mut(id) {
let url = self.urls.get(layer).expect("Url should be found");
if let Some(survey) = self.surveys.get_mut(url) {
let hips_cfg = survey.get_config();
let fully_covering_survey = (survey.is_allsky()
@@ -290,13 +288,13 @@ impl Layers {
let draw_opt = self.meta.get(layer).expect("Meta should be found");
if draw_opt.visible() {
// 1. Update the survey if necessary
let id = self.ids.get(layer).expect("Url should be found");
if let Some(survey) = self.surveys.get_mut(id) {
let url = self.urls.get(layer).expect("Url should be found");
if let Some(survey) = self.surveys.get_mut(url) {
survey.update(&self.raytracer, camera, projection);
// 2. Draw it if its opacity is not null
survey.draw(shaders, colormaps, camera, raytracer, draw_opt)?;
} else if let Some(image) = self.images.get_mut(id) {
} else if let Some(image) = self.images.get_mut(url) {
image.update(camera, projection)?;
// 2. Draw it if its opacity is not null
@@ -328,7 +326,7 @@ impl Layers {
));
// Color configs, and urls are indexed by layer
self.meta.remove(layer).ok_or(err_layer_not_found.clone())?;
let id = self.ids.remove(layer).ok_or(err_layer_not_found.clone())?;
let url = self.urls.remove(layer).ok_or(err_layer_not_found.clone())?;
// layer from layers does also need to be removed
let id_layer = self
.layers
@@ -344,26 +342,26 @@ impl Layers {
camera.set_longitude_reversed(longitude_reversed, proj);
// Check if the url is still used
let id_still_used = self.ids.values().any(|rem_id| rem_id == &id);
if id_still_used {
let url_still_used = self.urls.values().any(|rem_url| rem_url == &url);
if url_still_used {
// Keep the resource whether it is a HiPS or a FITS
Ok(id_layer)
} else {
// Resource not needed anymore
if let Some(s) = self.surveys.remove(&id) {
if let Some(s) = self.surveys.remove(&url) {
// A HiPS has been found and removed
let hips_frame = s.get_config().get_frame();
// remove the frame
camera.unregister_view_frame(hips_frame, proj);
Ok(id_layer)
} else if let Some(_) = self.images.remove(&id) {
} else if let Some(_) = self.images.remove(&url) {
// A FITS image has been found and removed
Ok(id_layer)
} else {
Err(JsValue::from_str(&format!(
"Url found {:?} is associated to no surveys.",
id
url
)))
}
}
@@ -385,11 +383,11 @@ impl Layers {
self.layers[id_layer] = new_layer.to_string();
let meta = self.meta.remove(layer).ok_or(err_layer_not_found.clone())?;
let id = self.ids.remove(layer).ok_or(err_layer_not_found)?;
let url = self.urls.remove(layer).ok_or(err_layer_not_found)?;
// Add the new
self.meta.insert(new_layer.to_string(), meta);
self.ids.insert(new_layer.to_string(), id);
self.urls.insert(new_layer.to_string(), url);
Ok(())
}
@@ -453,16 +451,13 @@ impl Layers {
camera.set_longitude_reversed(longitude_reversed, proj);
// 3. Add the image survey
let creator_did = String::from(properties.get_creator_did());
let url = String::from(properties.get_url());
// The layer does not already exist
// Let's check if no other hipses points to the
// same url than `hips`
let cdid_already_found = self
.surveys
.keys()
.any(|hips_cdid| hips_cdid == &creator_did);
let url_already_found = self.surveys.keys().any(|hips_url| hips_url == &url);
if !cdid_already_found {
if !url_already_found {
// The url is not processed yet
let cfg = HiPSConfig::new(&properties, img_ext)?;
@@ -480,14 +475,14 @@ impl Layers {
let hips = HiPS::new(cfg, gl, camera)?;
// add the frame to the camera
self.surveys.insert(creator_did.clone(), hips);
self.surveys.insert(url.clone(), hips);
}
self.ids.insert(layer.clone(), creator_did.clone());
self.urls.insert(layer.clone(), url.clone());
let hips = self
.surveys
.get(&creator_did)
.get(&url)
.ok_or(JsValue::from_str("HiPS not found"))?;
Ok(hips)
}
@@ -546,7 +541,7 @@ impl Layers {
self.images.insert(url.clone(), image);
}
self.ids.insert(layer.clone(), url.clone());
self.urls.insert(layer.clone(), url.clone());
let fits = self
.images
@@ -622,26 +617,26 @@ impl Layers {
// Accessors
// HiPSes getters
pub fn get_hips_from_layer(&self, layer: &str) -> Option<&HiPS> {
self.ids
self.urls
.get(layer)
.map(|cdid| self.surveys.get(cdid))
.map(|url| self.surveys.get(url))
.flatten()
}
pub fn get_mut_hips_from_layer(&mut self, layer: &str) -> Option<&mut HiPS> {
if let Some(cdid) = self.ids.get_mut(layer) {
self.surveys.get_mut(cdid)
if let Some(url) = self.urls.get_mut(layer) {
self.surveys.get_mut(url)
} else {
None
}
}
pub fn get_mut_hips_from_cdid(&mut self, cdid: &str) -> Option<&mut HiPS> {
self.surveys.get_mut(cdid)
pub fn get_mut_hips_from_url(&mut self, root_url: &str) -> Option<&mut HiPS> {
self.surveys.get_mut(root_url)
}
pub fn get_hips_from_cdid(&mut self, cdid: &str) -> Option<&HiPS> {
self.surveys.get(cdid)
pub fn get_hips_from_url(&mut self, root_url: &str) -> Option<&HiPS> {
self.surveys.get(root_url)
}
pub fn values_hips(&self) -> impl Iterator<Item = &HiPS> {
@@ -654,7 +649,7 @@ impl Layers {
// Fits images getters
pub fn get_mut_image_from_layer(&mut self, layer: &str) -> Option<&mut Image> {
if let Some(url) = self.ids.get(layer) {
if let Some(url) = self.urls.get(layer) {
self.images.get_mut(url)
} else {
None
@@ -662,7 +657,7 @@ impl Layers {
}
pub fn get_image_from_layer(&self, layer: &str) -> Option<&Image> {
self.ids
self.urls
.get(layer)
.map(|url| self.images.get(url))
.flatten()

View File

@@ -134,11 +134,11 @@ pub struct ImageSurveyTextures {
size: usize,
pub textures: HashMap<HEALPixCell, Texture>,
//pub base_textures: [Texture; NUM_HPX_TILES_DEPTH_ZERO],
pub base_textures: [Texture; NUM_HPX_TILES_DEPTH_ZERO],
//pub cutoff_values_tile: Rc<RefCell<HashMap<HEALPixCell, (f32, f32)>>>,
// Array of 2D textures
texture_2d_array: Texture2DArray,
texture_2d_array: Rc<Texture2DArray>,
// A boolean ensuring the root textures
// have already been loaded
@@ -146,7 +146,6 @@ pub struct ImageSurveyTextures {
pub start_time: Option<Time>,
available_tiles_during_frame: bool,
//num_base_textures: usize,
//exec: Rc<RefCell<TaskExecutor>>,
}
@@ -177,11 +176,11 @@ impl ImageSurveyTextures {
// Ensures there is at least space for the 12
// root textures
debug_assert!(size >= NUM_HPX_TILES_DEPTH_ZERO);
let heap = HEALPixCellHeap::with_capacity(size);
let heap = HEALPixCellHeap::with_capacity(size - NUM_HPX_TILES_DEPTH_ZERO);
let textures = HashMap::with_capacity(size);
let now = Time::now();
/*let base_textures = [
let base_textures = [
Texture::new(&HEALPixCell(0, 0), 0, now),
Texture::new(&HEALPixCell(0, 1), 1, now),
Texture::new(&HEALPixCell(0, 2), 2, now),
@@ -194,31 +193,34 @@ impl ImageSurveyTextures {
Texture::new(&HEALPixCell(0, 9), 9, now),
Texture::new(&HEALPixCell(0, 10), 10, now),
Texture::new(&HEALPixCell(0, 11), 11, now),
];*/
];
let channel = config.get_format().get_channel();
#[cfg(feature = "webgl2")]
let texture_2d_array = match channel {
ChannelType::RGBA32F => unimplemented!(),
ChannelType::RGB32F => unimplemented!(),
ChannelType::RGBA8U => create_texture_array::<RGBA8U>(gl, &config)?,
ChannelType::RGB8U => create_texture_array::<RGB8U>(gl, &config)?,
ChannelType::R32F => create_texture_array::<R32F>(gl, &config)?,
#[cfg(feature = "webgl2")]
ChannelType::R8UI => create_texture_array::<R8UI>(gl, &config)?,
#[cfg(feature = "webgl2")]
ChannelType::R16I => create_texture_array::<R16I>(gl, &config)?,
#[cfg(feature = "webgl2")]
ChannelType::R32I => create_texture_array::<R32I>(gl, &config)?,
#[cfg(feature = "webgl2")]
ChannelType::R64F => create_texture_array::<R64F>(gl, &config)?,
ChannelType::RGBA8U => Rc::new(create_texture_array::<RGBA8U>(gl, &config)?),
ChannelType::RGB8U => Rc::new(create_texture_array::<RGB8U>(gl, &config)?),
ChannelType::R8UI => Rc::new(create_texture_array::<R8UI>(gl, &config)?),
ChannelType::R16I => Rc::new(create_texture_array::<R16I>(gl, &config)?),
ChannelType::R32I => Rc::new(create_texture_array::<R32I>(gl, &config)?),
ChannelType::R32F => Rc::new(create_texture_array::<R32F>(gl, &config)?),
ChannelType::R64F => Rc::new(create_texture_array::<R64F>(gl, &config)?),
};
#[cfg(feature = "webgl1")]
let texture_2d_array = match config.get_format() {
ChannelType::RGBA32F => unimplemented!(),
ChannelType::RGB32F => unimplemented!(),
ChannelType::RGBA8U => Rc::new(create_texture_array::<RGBA8U>(gl, &config)?),
ChannelType::RGB8U => Rc::new(create_texture_array::<RGB8U>(gl, &config)?),
ChannelType::R32F => Rc::new(create_texture_array::<R32F>(gl, &config)?),
};
// The root textures have not been loaded
//let ready = false;
//let num_root_textures_available = 0;
let available_tiles_during_frame = false;
let start_time = None;
//let num_base_textures = 0;
Ok(ImageSurveyTextures {
config,
heap,
@@ -226,8 +228,8 @@ impl ImageSurveyTextures {
size,
//num_root_textures_available,
textures,
//base_textures,
//num_base_textures,
base_textures,
texture_2d_array,
available_tiles_during_frame,
@@ -244,21 +246,21 @@ impl ImageSurveyTextures {
self.texture_2d_array = match channel {
ChannelType::RGBA32F => unimplemented!(),
ChannelType::RGB32F => unimplemented!(),
ChannelType::RGBA8U => create_texture_array::<RGBA8U>(gl, &self.config)?,
ChannelType::RGB8U => create_texture_array::<RGB8U>(gl, &self.config)?,
ChannelType::R32F => create_texture_array::<R32F>(gl, &self.config)?,
ChannelType::RGBA8U => Rc::new(create_texture_array::<RGBA8U>(gl, &self.config)?),
ChannelType::RGB8U => Rc::new(create_texture_array::<RGB8U>(gl, &self.config)?),
ChannelType::R32F => Rc::new(create_texture_array::<R32F>(gl, &self.config)?),
#[cfg(feature = "webgl2")]
ChannelType::R8UI => create_texture_array::<R8UI>(gl, &self.config)?,
ChannelType::R8UI => Rc::new(create_texture_array::<R8UI>(gl, &self.config)?),
#[cfg(feature = "webgl2")]
ChannelType::R16I => create_texture_array::<R16I>(gl, &self.config)?,
ChannelType::R16I => Rc::new(create_texture_array::<R16I>(gl, &self.config)?),
#[cfg(feature = "webgl2")]
ChannelType::R32I => create_texture_array::<R32I>(gl, &self.config)?,
ChannelType::R32I => Rc::new(create_texture_array::<R32I>(gl, &self.config)?),
#[cfg(feature = "webgl2")]
ChannelType::R64F => create_texture_array::<R64F>(gl, &self.config)?,
ChannelType::R64F => Rc::new(create_texture_array::<R64F>(gl, &self.config)?),
};
let now = Time::now();
/*self.base_textures = [
self.base_textures = [
Texture::new(&HEALPixCell(0, 0), 0, now),
Texture::new(&HEALPixCell(0, 1), 1, now),
Texture::new(&HEALPixCell(0, 2), 2, now),
@@ -271,7 +273,7 @@ impl ImageSurveyTextures {
Texture::new(&HEALPixCell(0, 9), 9, now),
Texture::new(&HEALPixCell(0, 10), 10, now),
Texture::new(&HEALPixCell(0, 11), 11, now),
];*/
];
self.heap.clear();
self.textures.clear();
@@ -324,7 +326,7 @@ impl ImageSurveyTextures {
let tex_cell = cell.get_texture_cell(self.config.delta_depth());
let tex_cell_is_root = tex_cell.is_root(self.config.delta_depth());
if !self.textures.contains_key(&tex_cell) {
if !tex_cell_is_root && !self.textures.contains_key(&tex_cell) {
// The texture is not among the essential ones
// (i.e. is not a root texture)
let texture = if self.is_heap_full() {
@@ -338,12 +340,6 @@ impl ImageSurveyTextures {
"Texture (oldest one) has not been found in the buffer of textures",
);
// Clear and assign it to tex_cell
/*let idx = if tex_cell_is_root {
self.num_base_textures += 1;
Some(tex_cell.idx() as i32)
} else {
None
};*/
texture.replace(&tex_cell, time_request);
texture
@@ -351,18 +347,10 @@ impl ImageSurveyTextures {
// The heap buffer is not full, let's create a new
// texture with an unique idx
// The idx is computed based on the current size of the buffer
/*let idx = if tex_cell_is_root {
self.num_base_textures += 1;
tex_cell.idx() as usize
} else {
//NUM_HPX_TILES_DEPTH_ZERO + (self.heap.len() - self.num_base_textures)
self.heap.len()
};*/
let idx = self.heap.len();
let idx = NUM_HPX_TILES_DEPTH_ZERO + self.heap.len();
Texture::new(&tex_cell, idx as i32, time_request)
};
// Push it to the buffer
self.heap.push(&texture);
@@ -375,17 +363,23 @@ impl ImageSurveyTextures {
// We can safely push it
// First get the texture
let texture = //if !tex_cell_is_root {
let texture = if !tex_cell_is_root {
self.textures
.get_mut(&tex_cell)
.expect("the cell has to be in the tile buffer");
/* } else {
.expect("the cell has to be in the tile buffer")
} else {
let HEALPixCell(_, idx) = tex_cell;
&mut self.base_textures[idx as usize]
};*/
};
if let Some(image) = image {
send_to_gpu(cell, texture, image, &self.texture_2d_array, &self.config)?;
send_to_gpu(
cell,
texture,
image,
self.texture_2d_array.clone(),
&self.config,
)?;
// Once the texture has been received in the GPU
texture.append(
cell, // The tile cell
@@ -397,7 +391,7 @@ impl ImageSurveyTextures {
cell,
texture,
self.config.get_default_image(),
&self.texture_2d_array,
self.texture_2d_array.clone(),
&self.config,
)?;
// Once the texture has been received in the GPU
@@ -410,9 +404,9 @@ impl ImageSurveyTextures {
self.available_tiles_during_frame = true;
//self.ready = true;
/*if self.start_time.is_none() {
if self.start_time.is_none() {
self.start_time = Some(Time::now());
}*/
}
/*if tex_cell.is_root(self.config.delta_depth()) && texture.is_available() {
self.num_root_textures_available += 1;
@@ -442,15 +436,23 @@ impl ImageSurveyTextures {
// textures in the buffer
let num_textures_heap = self.heap.len();
num_textures_heap == self.size
num_textures_heap == (self.size - NUM_HPX_TILES_DEPTH_ZERO)
}
// Tell if a texture is available meaning all its sub tiles
// must have been written for the GPU
pub fn contains(&self, texture_cell: &HEALPixCell) -> bool {
if let Some(t) = self.get(texture_cell) {
t.is_full()
if let Some(texture) = self.textures.get(texture_cell) {
// The texture is in the buffer i.e. there is at least one
// sub tile received
// It is possible that it is not available. Available means
// all its sub tiles have been received and written to the
// textures array!
texture.is_available()
} else {
// The texture is not contained in the buffer i.e.
// even not one sub tile that has been received
false
}
}
@@ -461,20 +463,20 @@ impl ImageSurveyTextures {
pub fn contains_tile(&self, cell: &HEALPixCell) -> bool {
let texture_cell = cell.get_texture_cell(self.config.delta_depth());
//let tex_cell_is_root = texture_cell.is_root(self.config.delta_depth());
//if tex_cell_is_root {
// let HEALPixCell(_, idx) = texture_cell;
// self.base_textures[idx as usize].contains(cell)
//} else {
if let Some(texture) = self.get(&texture_cell) {
// The texture is present in the buffer
// We must check whether it contains the tile
texture.contains(cell)
let tex_cell_is_root = texture_cell.is_root(self.config.delta_depth());
if tex_cell_is_root {
let HEALPixCell(_, idx) = texture_cell;
self.base_textures[idx as usize].contains(cell)
} else {
// The texture in which cell should be is not present
false
if let Some(texture) = self.textures.get(&texture_cell) {
// The texture is present in the buffer
// We must check whether it contains the tile
texture.contains(cell)
} else {
// The texture in which cell should be is not present
false
}
}
//}
}
// Update the priority of the texture containing the tile
@@ -484,9 +486,9 @@ impl ImageSurveyTextures {
// Get the texture cell in which the tile has to be
let texture_cell = cell.get_texture_cell(self.config.delta_depth());
//if texture_cell.is_root(self.config().delta_depth()) {
// return;
//}
if texture_cell.is_root(self.config().delta_depth()) {
return;
}
let texture = self
.textures
@@ -518,7 +520,7 @@ impl ImageSurveyTextures {
let (pix, dx, dy) = crate::healpix::utils::hash_with_dxdy(depth, lonlat);
let texture_cell = HEALPixCell(depth, pix);
if let Some(texture) = self.get(&texture_cell) {
if let Some(texture) = self.textures.get(&texture_cell) {
let cfg = &self.config;
// Index of the texture in the total set of textures
@@ -566,33 +568,29 @@ impl ImageSurveyTextures {
/// Accessors
pub fn get(&self, texture_cell: &HEALPixCell) -> Option<&Texture> {
//if texture_cell.is_root(self.config().delta_depth()) {
// let HEALPixCell(_, idx) = texture_cell;
// Some(&self.base_textures[*idx as usize])
//} else {
self.textures.get(texture_cell)
//}
if texture_cell.is_root(self.config().delta_depth()) {
let HEALPixCell(_, idx) = texture_cell;
Some(&self.base_textures[*idx as usize])
} else {
self.textures.get(texture_cell)
}
}
// Get the nearest parent tile found in the CPU buffer
pub fn get_nearest_parent(&self, cell: &HEALPixCell) -> Option<HEALPixCell> {
pub fn get_nearest_parent(&self, cell: &HEALPixCell) -> HEALPixCell {
let dd = self.config.delta_depth();
/*if cell.is_root(dd) {
if cell.is_root(dd) {
// Root cells are in the buffer by definition
*cell
} else {*/
let mut parent_cell = cell.parent();
while !self.contains(&parent_cell) && !parent_cell.is_root(dd) {
parent_cell = parent_cell.parent();
}
if self.contains(&parent_cell) {
Some(parent_cell)
} else {
None
let mut parent_cell = cell.parent();
while !self.contains(&parent_cell) && !parent_cell.is_root(dd) {
parent_cell = parent_cell.parent();
}
parent_cell
}
//}
}
pub fn config(&self) -> &HiPSConfig {
@@ -630,8 +628,8 @@ impl ImageSurveyTextures {
]
}*/
pub fn get_texture_array(&self) -> &Texture2DArray {
&self.texture_2d_array
pub fn get_texture_array(&self) -> Rc<Texture2DArray> {
self.texture_2d_array.clone()
}
}
@@ -639,7 +637,7 @@ fn send_to_gpu<I: Image>(
cell: &HEALPixCell,
texture: &Texture,
image: I,
texture_array: &Texture2DArray,
texture_array: Rc<Texture2DArray>,
cfg: &HiPSConfig,
) -> Result<(), JsValue> {
// Index of the texture in the total set of textures
@@ -679,30 +677,17 @@ impl SendUniforms for ImageSurveyTextures {
// Send only the allsky textures
fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> {
// Send the textures
/*let textures = &self.base_textures;
let textures = &self.base_textures;
for (idx, texture) in textures.iter().enumerate() {
let texture_uniforms = TextureUniforms::new(texture, idx as i32);
shader.attach_uniforms_from(&texture_uniforms);
}*/
//if self.raytracing {
for idx in 0..NUM_HPX_TILES_DEPTH_ZERO {
let cell = HEALPixCell(0, idx as u64);
if let Some(texture) = self.get(&cell) {
let texture_uniforms = TextureUniforms::new(texture, idx as i32);
shader.attach_uniforms_from(&texture_uniforms);
} else {
let texture = &Texture::new(&cell, idx as i32, Time::now());
let texture_uniforms = TextureUniforms::new(texture, idx as i32);
shader.attach_uniforms_from(&texture_uniforms);
}
}
//}
let num_tiles = textures.len() as i32;
let shader = shader
.attach_uniform("num_tiles", &num_tiles)
.attach_uniforms_from(&self.config)
.attach_uniforms_from(&self.texture_2d_array);
.attach_uniforms_from(&*self.texture_2d_array);
shader
}

View File

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

View File

@@ -105,10 +105,14 @@ impl Texture {
self.full
}
pub fn is_available(&self) -> bool {
self.is_full()
}
// Getter
// Returns the current time if the texture is not full
pub fn start_time(&self) -> Time {
if self.is_full() {
if self.is_available() {
self.start_time.unwrap_abort()
} else {
Time::now()

View File

@@ -92,7 +92,6 @@ impl TileFetcherQueue {
// Try to fetch the MOC
downloader.fetch(query::Moc::new(
format!("{}/Moc.fits", cfg.get_root_url()),
cfg.get_creator_did().to_string(),
al_api::moc::MOC::default(),
));

View File

@@ -1,14 +1,14 @@
/*body { overscroll-behavior: contain; }*/
body { overscroll-behavior: contain; }
.aladin-container {
position: relative;
/*height: 100%;*/
border: 0px solid #ddd;
/* SVG inside divs add a 4px height: https://stackoverflow.com/questions/75751593/why-there-is-additional-4px-height-for-div-when-there-is-svg-inside-it */
border: 1px solid #ddd;
height: 100%;
/* disable x swipe on chrome, firefox */
/* see. https://stackoverflow.com/questions/30636930/disable-web-page-navigation-on-swipeback-and-forward */
overscroll-behavior-x: none;
/* media query on the aladin lite container. not supported everywhere.
There can be a more supported alternative here: https://caniuse.com/?search=grid-template-columns */
/*container-type: inline-size;*/
@@ -80,7 +80,7 @@
display: block;
max-height: 30vh;
max-height: 15em;
max-width: 100%;
-ms-overflow-style: none;
overscroll-behavior-x: none;
@@ -115,7 +115,6 @@
.aladin-measurement-div.aladin-dark-theme table thead {
background-color: #000;
color: white;
}
.aladin-measurement-div table td.aladin-href-td-container a:hover {
@@ -151,8 +150,8 @@
white-space: nowrap;
overflow: hidden;
text-align: center;
/*max-width: 150px;
text-overflow: ellipsis;*/
max-width: 150px;
text-overflow: ellipsis;
}
.aladin-measurement-div table td.aladin-text-td-container {
@@ -160,8 +159,8 @@
white-space: nowrap;
overflow: hidden;
/*max-width: 150px;
text-overflow: ellipsis;*/
max-width: 150px;
text-overflow: ellipsis;
}
.aladin-measurement-div table td.aladin-href-td-container:hover {
@@ -245,6 +244,8 @@
}
.aladin-box {
display: none;
padding: 0.2rem;
background: whitesmoke;
border-radius: 2px;
@@ -269,6 +270,26 @@
height: fit-content;
}
.aladin-box::-webkit-scrollbar {
display: none; /* for Chrome, Safari, and Opera */
}
.aladin-dialog {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #eee;
border-radius: 4px;
/*font-family: Verdana, Geneva, Tahoma, sans-serif;*/
line-height: 1.3;
color: #222;
max-width: 500px;
padding: 0.8em;
}
canvas {
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
@@ -413,9 +434,6 @@ canvas {
.aladin-measurement-div.aladin-dark-theme {
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid white;
}
.aladin-measurement-div.aladin-dark-theme table {
color: white;
}
@@ -451,11 +469,11 @@ canvas {
}
.aladin-input-text.aladin-dark-theme.search {
width: 14rem;
width: 15rem;
text-shadow: 0px 0px 2px #000;
}
.aladin-input-text.aladin-dark-theme.search:focus, .aladin-input-text.aladin-dark-theme.search:hover {
.aladin-input-text.aladin-dark-theme.search:focus {
background-image: url(../../assets/icons/search-white.svg);
background-size: 1.8rem;
background-repeat: no-repeat;
@@ -465,15 +483,16 @@ canvas {
.aladin-input-text.search {
background-image:none;
text-indent: 0rem;
font-size: 1rem;
}
.aladin-input-text.search.aladin-unknownObject {
-webkit-box-shadow:inset 0px 0px 0px 1px #f00;
-moz-box-shadow:inset 0px 0px 0px 1px #f00;
box-shadow:inset 0px 0px 0px 1px #f00;
-webkit-box-shadow:inset 0px 0px 0px 3px #f00;
-moz-box-shadow:inset 0px 0px 0px 3px #f00;
box-shadow:inset 0px 0px 0px 3px #f00;
}
border: 1px solid red;
.aladin-dark-theme {
color: white;
}
.aladin-cancelBtn {
@@ -657,14 +676,10 @@ canvas {
.aladin-status-bar-message {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-wrap: nowrap;
-ms-overflow-style: none;
overscroll-behavior-x: none;
overflow-y: scroll;
scrollbar-width: none;
max-width: 20rem;
max-width: 300px;
font-size: 1rem;
}
@@ -726,6 +741,8 @@ canvas {
.aladin-context-sub-menu,
.aladin-context-menu {
position: absolute;
background: #fff;
color: #000;
font-family: monospace;
width: max-content;
@@ -752,9 +769,10 @@ canvas {
padding: 0.2rem 0.4rem;
position: relative;
box-shadow:inset 1px 1px 0px 0px #fff;
color: lightgray;
background-color: black;
background-color: rgba(0, 0, 0, 0.7);
box-shadow:inset 1px 1px 0px 0px #fff;
}
.aladin-context-menu .aladin-context-menu-item:first-of-type {
@@ -967,10 +985,6 @@ canvas {
border-radius: 0.5rem;
}
.aladin-dark-theme {
color: white;
}
/* *********************************************** */
/* Tooltip */
@@ -980,27 +994,22 @@ canvas {
/* take the size of its inner div child */
font-family: monospace;
line-height: 1rem;
float: left;
}
.aladin-tooltip-container .aladin-tooltip {
pointer-events: none;
cursor: default;
visibility: hidden;
background-color: white;
color: black;
background-color: black;
width: max-content;
color: #fff;
text-align: center;
padding: 4px;
border-radius: 2px;
top:0%;
left:0%;
z-index: 100;
@@ -1009,13 +1018,6 @@ canvas {
/*font-family: Verdana, Geneva, Tahoma, sans-serif;*/
font-size: 0.9rem;
transition-delay: 100ms;
}
.aladin-tooltip-container .aladin-tooltip.aladin-dark-theme {
background-color: #333;
color: white;
}
/* Show the tooltip text when you mouse over the tooltip container */
@@ -1075,42 +1077,35 @@ canvas {
cursor: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEIEwUMBS20MQAAApRJREFUWEfdV7GO2zAMfXY7x1luzOFwDeB/KHCAB87eumvqmI/JWhTwF3TIrMFAv8JbgWyHG3IpOjbpcKJC02KipECHclIU+j2KfKRlAABRUyFYak3UgKiZiXUJAIt1d1ysu2PYn53DsPCucpbkRE3JAdxKTtQgWo6zJAfGGbAwLuEV7OB9/yrXIbqZ9/0+rMuhdb+RYfWmm+fged8fihzyoXXxlNcYB2KRxwwA6SzI9Crgd973B/5/u3IF8FYSw98M5D2QR86kRE3pfX+AMqKm8iEQoqYaWrfj/4bW7QgokMhCeSs5KeVrDM4K29C6Y6oE0YGEUlndocVGyg/rGZDXBQpr0kmjLiAlOOvk3vf7RJZM5Q+te2W/7coVEq+wnC1yCZYyS3B8MMYF3vBKK9Jz5PWmm8sab1eu4N9D63aaHEAsH88SzmQpnSHsHDmnWvlXIoiJ4JTviY8FRUJ8ZAiOEiJbLpcjARM1M0twpmjZOeGQrXYm1/7yMLz/eH8fnyus6XXOtmLgWBrKtdMguNKYPPystIausn9egsVDfI674KxS6003F/sX357AdOBwcADwWD9EjBKJubxYd0cml4RhP5IPrduFk04GjiZXMyZiRHKdAU3OWeB2lLNAk+tpl9IHY0zSlBo4OgsaTJpFzs+F0pxKYEXK73Nd8+3KFfWmG71qGfgSeQqPN0fvdlZrSvmUoXaJJ7EiocArZaS6tgzA+5RQe3gumUl5gPLXzy+6pEQNzDuhvFKx1ZuuEuTxliwmY/KuoHxGhzGv5QDw9PTx7senz88aLHUpJeOu8OHb17u+//4CTMm97/eFVQK5vqR8y6xOyipByjn3+0C3moUH4O++D1UX3PR9eJWzJCf6Tz5O/wDUeIfTLPlbywAAAABJRU5ErkJggg==') 15 15, auto;
}
/**
* Aladin Lite pre-defined UI features.
*
* User may need to overwrite those classes if they want
* change their position. They can also add media query on them.
*
*/
/* Aladin Lite pre-defined UI features */
.aladin-stack-control {
position: absolute;
top: 3rem;
left: 0.2rem;
left: 0;
}
.aladin-settings-control {
position: absolute;
top: 5.4rem;
left: 0.2rem;
left: 0;
}
.aladin-simbadPointer-control {
position: absolute;
top: 7.8rem;
left: 0.2rem;
left: 0;
}
.aladin-grid-control {
position: absolute;
top: 10.2rem;
left: 0.2rem;
left: 0;
}
.aladin-cooFrame {
position: absolute;
top: 0.2rem;
left: 0.2rem;
top: 0;
left: 0;
font-family: monospace;
@@ -1123,8 +1118,8 @@ canvas {
.aladin-location {
position: absolute;
top: 0.2rem;
left: 6.9rem;
top: 0;
left: 7rem;
font-family: monospace;
color: white;
@@ -1136,61 +1131,40 @@ canvas {
.aladin-fov {
position: absolute;
bottom: 0.2rem;
left: 0.2rem;
top: 0;
left: 25rem;
font-family: monospace;
color: white;
font-size: 1rem;
border-radius: 5px;
line-height: 1.7rem;
height: 1.7rem;
}
.aladin-status-bar {
border-radius: 3px;
padding: 0.4rem;
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 0);
}
.aladin-status-bar.aladin-dark-theme {
color: white;
background-color: black;
}
.aladin-fov.aladin-dark-theme {
background-color: rgba(0, 0, 0, 0.5);
}
.aladin-table {
position: absolute;
bottom: 2.8rem;
left: 0.2rem;
max-width: calc(100% - 0.4rem);
line-height: 1rem;
}
.aladin-measurement-div.aladin-dark-theme {
color: white;
transform: translate(-50%, 0%);
}
.aladin-share-control {
position: absolute;
top: 12.6rem;
left: 0.2rem;
bottom: 0;
left: 0;
}
.aladin-fullScreen-control {
position: absolute;
top: 0.2rem;
right: 0.2rem;
top: 0;
right: 0;
}
.aladin-projection-control {
position: absolute;
top: 0.2rem;
top: 0;
right: 3rem;
}
@@ -1206,6 +1180,8 @@ canvas {
background: #fff;
}
/* Media query */
/*@media screen and (max-width: 31rem) {
.aladin-projection-control {

View File

@@ -1,7 +1,7 @@
//const int MAX_NUM_TEX = 3;
uniform sampler2D tex1;
uniform sampler2D tex2;
//uniform sampler2D tex3;
uniform sampler2D tex3;
uniform int num_tex;
@@ -23,16 +23,16 @@ uniform int tex_storing_fits;
#include ./hsv.glsl;
vec4 get_pixels(vec3 uv) {
/*if (idx_texture == 0) {
int idx_texture = int(uv.z);
if (idx_texture == 0) {
return texture(tex1, uv.xy);
} else if (idx_texture == 1) {
return texture(tex2, uv.xy);
} else if (idx_texture == 2) {
return texture(tex3, uv.xy);
} else {
return vec4(0.0, 1.0, 0.0, 1.0);
}*/
int idx_texture = int(uv.z);
return mix(texture(tex1, uv.xy), texture(tex2, uv.xy), float(idx_texture));
}
}
vec3 reverse_uv(vec3 uv) {

View File

@@ -1,7 +1,7 @@
//const int MAX_NUM_TEX = 3;
uniform isampler2D tex1;
uniform isampler2D tex2;
//uniform isampler2D tex3;
uniform isampler2D tex3;
uniform int num_tex;
uniform float scale;
@@ -22,7 +22,7 @@ uniform int tex_storing_fits;
#include ./tonal_corrections.glsl;
ivec4 get_pixels(vec3 uv) {
/*int idx_texture = int(uv.z);
int idx_texture = int(uv.z);
if (idx_texture == 0) {
return texture(tex1, uv.xy);
} else if (idx_texture == 1) {
@@ -31,10 +31,7 @@ ivec4 get_pixels(vec3 uv) {
return texture(tex3, uv.xy);
} else {
return ivec4(0, 0, 0, 1);
}*/
//return texture(tex1, uv.xy);
int idx_texture = int(uv.z);
return ivec4(mix(vec4(texture(tex1, uv.xy)), vec4(texture(tex2, uv.xy)), float(idx_texture)));
}
}
vec3 reverse_uv(vec3 uv) {

View File

@@ -1,7 +1,7 @@
//const int MAX_NUM_TEX = 3;
uniform usampler2D tex1;
uniform usampler2D tex2;
//uniform usampler2D tex3;
uniform usampler2D tex3;
uniform int num_tex;
uniform float scale;
@@ -22,7 +22,7 @@ uniform int tex_storing_fits;
#include ./tonal_corrections.glsl;
uvec4 get_pixels(vec3 uv) {
/*int idx_texture = int(uv.z);
int idx_texture = int(uv.z);
if (idx_texture == 0) {
return texture(tex1, uv.xy);
} else if (idx_texture == 1) {
@@ -31,11 +31,7 @@ uvec4 get_pixels(vec3 uv) {
return texture(tex3, uv.xy);
} else {
return uvec4(0, 0, 0, 1);
}*/
//return texture(tex1, uv.xy);
//int idx_texture = int(uv.z);
int idx_texture = int(uv.z);
return uvec4(mix(vec4(texture(tex1, uv.xy)), vec4(texture(tex2, uv.xy)), float(idx_texture)));
}
}
vec3 reverse_uv(vec3 uv) {

View File

@@ -17,6 +17,7 @@ struct Tile {
};
uniform Tile textures_tiles[12];
uniform int num_tiles;
#include ../color.glsl;
#include ./healpix.glsl;
@@ -28,6 +29,7 @@ vec4 get_tile_color(vec3 pos) {
int idx = result.idx;
vec2 uv = vec2(result.dy, result.dx);
Tile tile = textures_tiles[idx];
int idx_texture = tile.texture_idx >> 6;
@@ -39,7 +41,6 @@ vec4 get_tile_color(vec3 pos) {
vec3 UV = vec3(offset, float(idx_texture));
vec4 color = get_color_from_texture(UV);
color.a *= (1.0 - tile.empty);
return color;
}

View File

@@ -49,6 +49,7 @@ vec4 get_tile_color(vec3 pos) {
// For empty tiles we set the alpha of the pixel to 0.0
// so that what is behind will be plotted
color.a *= (1.0 - tile.empty);
return color;
}

View File

@@ -43,9 +43,6 @@ import { Footprint } from './Footprint.js';
import { Aladin } from "./Aladin.js";
import { ActionButton } from "./gui/Widgets/ActionButton.js";
import { Box } from "./gui/Widgets/Box.js";
import { AladinUtils } from "./AladinUtils.js";
import { Sesame } from "./Sesame.js";
// Wasm top level import
import init, * as module from './../core/pkg';
@@ -90,7 +87,6 @@ let A = {};
*/
A.aladin = function (divSelector, options) {
let divElement;
if (!(divSelector instanceof HTMLElement)) {
divElement = document.querySelector(divSelector)
} else {
@@ -99,45 +95,6 @@ A.aladin = function (divSelector, options) {
return new Aladin(divElement, options);
};
/**
* Creates a HiPS image object
*
* @function
* @name A.imageHiPS
* @memberof A
* @param {string} id - Mandatory unique identifier for the survey.
* @param {string} url - Can be an `url` that refers to a HiPS.
* Or it can be a "CDS ID" pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}.
* @param {ImageSurveyOptions} [options] - Options describing the survey
* @returns {ImageSurvey} - A HiPS image object
*/
A.imageHiPS = function (id, url, options) {
return Aladin.createImageSurvey(
id,
options && options.name,
url,
options && options.cooFrame,
options && options.maxOrder,
options
);
}
/**
* Creates a celestial source object with the given coordinates.
*
* @function
* @name A.imageFITS
* @memberof A
* @param {string} url - Options describing the fits file. An url is mandatory
* @param {ImageFITSOptions} [options] - Options describing the fits file. An url is mandatory
* @returns {ImageSurvey} - A HiPS image object
* @example
* const sourceObj = A.source(180.0, 30.0, data, options);
*/
A.imageFITS = function (url, options) {
return Aladin.createImageFITS(url, options.name, options, options.successCallback, options.errorCallback);
}
/**
* Creates a celestial source object with the given coordinates.
*
@@ -377,7 +334,6 @@ A.MOCFromPolygon= function (polygon, options, successCallback, errorCallback) {
* @property {string} [decField] - The ID or name of the field holding Declination (dec).
* @property {function} [filter] - The filtering function for sources. Returns a boolean
* @property {boolean} [displayLabel=false] - Whether to display labels for sources.
* @property {string} [labelColumn] - The name of the column to be used for the label.
* @property {string} [labelColor] - The color of the source labels.
* @property {string} [labelFont="10px sans-serif"] - The font for the source labels.
*/
@@ -503,9 +459,9 @@ A.catalogFromURL = function (url, options, successCallback, errorCallback, usePr
* @param {number} target.dec - Declination in degrees of the cone's center
* @param {number} radius - Radius of the cone in degrees
* @param {Object|CatalogOptions} [options] - Additional configuration options for SIMBAD cone search. See the {@link https://simbad.cds.unistra.fr/cone/help/#/ConeSearch/get_ SIMBAD cone search} parameters.
* @param {number} [options.limit] - The max number of sources to return
* @param {string} [options.orderBy='nb_ref'] - Order the result by specific ref number
* @param {number} [options.verbosity=2] - Verbosity, put 3 if you want all the column
* @param {Object} [options.limit] - The max number of sources to return
* @param {Object} [options.orderBy] - Order the result by specific
*
* @param {function} [successCallback] - The callback function to execute on successful catalog creation.
* @param {function} [errorCallback] - The callback function to execute on error during catalog creation.
* @returns {Catalog} A new instance of the Catalog class created from the SIMBAD cone search.
@@ -520,8 +476,8 @@ A.catalogFromSimbad = function (target, radius, options, successCallback, errorC
if (!('name' in options)) {
options['name'] = 'Simbad';
}
let cat = A.catalog(options);
new Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
let coo;
if (target && (typeof target === "object")) {
if ('ra' in target && 'dec' in target) {
@@ -557,45 +513,8 @@ A.catalogFromSimbad = function (target, radius, options, successCallback, errorC
}
}).then((coo) => {
const url = URLBuilder.buildSimbadCSURL(coo.lon, coo.lat, radius, options)
const processVOTable = function (table) {
let {sources, footprints, fields, type} = table;
cat.setFields(fields);
if (cat.type === 'ObsCore') {
// The fields corresponds to obscore ones
// Set the name of the catalog to be ObsCore:<catalog name>
cat.name = "ObsCore:" + url;
}
cat.addFootprints(footprints)
cat.addSources(sources);
if (successCallback) {
successCallback(cat);
}
if (sources.length === 0) {
console.warn(cat.name + ' has no sources!')
}
// Even if the votable is not a proper ObsCore one, try to see if specific columns are given
// e.g. access_format and access_url
//ObsCore.handleActions(catalog);
};
Catalog.parseVOTable(
url,
processVOTable,
errorCallback,
cat.maxNbSources,
false,
cat.raField, cat.decField
);
return A.catalogFromURL(url, options, successCallback, errorCallback, false);
})
return cat;
};
/**
@@ -749,77 +668,39 @@ A.catalogFromSkyBot = function (ra, dec, radius, epoch, queryOptions, options, s
* @returns {ActionButton} Returns a new button object representing the graphic overlay.
*
* @example
* <!-- This example instanciates a customized button that when clicked, enters the user in
* the polygonal selection mode. Once the polygon selection is done, the vertices are converted
* to sky coords and a Multi-Order Coverage (MOC) is created from that list of sky coords. -->
<!doctype html>
<html>
<head>
</head>
<body>
<div id="aladin-lite-div" style="width: 512px; height: 512px"></div>
<script type="module">
import A from aladin-lite;
let aladin;
A.init.then(() => {
var aladin = A.aladin(
'#aladin-lite-div',
{
survey: 'P/allWISE/color', // set initial image survey
projection: 'AIT', // set a projection
fov: 1.5, // initial field of view in degrees
target: 'NGC 2175', // initial target
cooFrame: 'icrs', // set galactic frame
reticleColor: '#ff89ff', // change reticle color
reticleSize: 64, // change reticle size
showContextMenu: true,
}
);
let btn = A.button({
content: 'My button',
classList: ['myButton'],
tooltip: {cssStyle: {color: 'red'}, content: 'Create a moc in pink!', position: {direction: 'top'}},
action(o) {
aladin.select('poly', p => {
try {
let ra = []
let dec = []
for (const v of p.vertices) {
let [lon, lat] = aladin.pix2world(v.x, v.y);
ra.push(lon)
dec.push(lat)
}
let moc = A.MOCFromPolygon(
{ra, dec},
{name: 'poly', lineWidth: 3.0, color: 'pink'},
);
aladin.addMOC(moc)
} catch(_) {
alert('Selection covers a region out of the projection definition domain.');
}
})
}
});
aladin.addUI(btn)
});
</script>
<style>
.myButton {
position: absolute;
bottom: 0;
left: 0;
background-color: pink;
}
</style>
</body>
</html>
* let btn = A.button({
* content: 'Draw your coverage',
* cssStyle: {
* backgroundColor: 'pink',
* },
* // Adding a CSS class allowing you to position your button on the aladin lite view
* classList: ['myButton'],
* tooltip: {cssStyle: {color: 'red'}, content: 'Create a moc in pink!', position: {direction: 'top'}},
* action(o) {
* // Enter a polygonal selection mode
* aladin.select('poly', p => {
* // Create a moc from the polygon
* try {
* let ra = []
* let dec = []
* for (const v of p.vertices) {
* let [lon, lat] = aladin.pix2world(v.x, v.y);
* ra.push(lon)
* dec.push(lat)
* }
*
* let moc = A.MOCFromPolygon(
* {ra, dec},
* {name: 'poly', lineWidth: 3.0, color: 'pink'},
* );
* aladin.addMOC(moc)
* } catch(_) {
* alert('Selection covers a region out of the projection definition domain.');
* }
* })
* }
* });
* aladin.addUI(btn)
*/
A.button = function(options) {
return new ActionButton(options);
@@ -861,19 +742,6 @@ A.getAvailableListOfColormaps = function() {
return ColorCfg.COLORMAPS;
};
/**
* Returns utils object
*
* This contains utilitary methods such as HEALPix basic or projection methods.
*
* @function
* @memberof A
* @name Utils
*
* @returns {AladinUtils} Returns a new box window object.
*/
A.Utils = AladinUtils;
/**
* Initializes the Aladin Lite library, checking for WebGL2 support.
* This method must be called before instancing an Aladin Lite object.

View File

@@ -56,32 +56,34 @@ import { Location } from "./gui/Location.js";
import { FoV } from "./gui/FoV.js";
import { ShareActionButton } from "./gui/Button/ShareView.js";
import { ContextMenu } from "./gui/Widgets/ContextMenu.js";
import { Input } from "./gui/Widgets/Input.js";
import { Popup } from "./Popup.js";
import A from "./A.js";
import { StatusBarBox } from "./gui/Box/StatusBarBox.js";
import { FullScreenActionButton } from "./gui/Button/FullScreen.js";
import { ProjectionActionButton } from "./gui/Button/Projection.js";
import { Toolbar } from './gui/Widgets/Toolbar';
import { ImageLayer } from './ImageLayer';
// features
import { SettingsButton } from "./gui/Button/Settings";
import { SimbadPointer } from "./gui/Button/SimbadPointer";
import { OverlayStackButton } from "./gui/Button/OverlayStack";
import { GridEnabler } from './gui/Button/GridEnabler';
import { CooFrame } from './gui/Input/CooFrame';
/**
* @typedef {Object} AladinOptions
* @description Options for configuring the Aladin Lite instance.
*
* @property {string} [survey="CDS/P/DSS2/color"] URL or ID of the survey to use
* @property {string[]} [surveyUrl]
* @property {string} [survey="https://alaskybis.unistra.fr/DSS/DSSColor"] URL or ID of the survey to use
* @property {string[]} [surveyUrl=["https://alaskybis.unistra.fr/DSS/DSSColor", "https://alasky.unistra.fr/DSS/DSSColor"]]
* Array of URLs for the survey images. This replaces the survey parameter.
* @property {string} [target="0 +0"] - Target coordinates for the initial view.
* @property {CooFrame} [cooFrame="J2000"] - Coordinate frame.
* @property {string} [cooFrame="J2000"] - Coordinate frame.
* @property {number} [fov=60] - Field of view in degrees.
* @property {string} [backgroundColor="rgb(60, 60, 60)"] - Background color in RGB format.
*
* @property {boolean} [showZoomControl=false] - Whether to show the zoom control toolbar.
* @property {boolean} [showZoomControl=true] - Whether to show the zoom control toolbar.
* 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`
@@ -127,18 +129,13 @@ import { CooFrame } from './gui/Input/CooFrame';
* @property {boolean} [gridOptions.showLabels=true] - Whether the grid has labels.
* @property {number} [gridOptions.labelSize=15] - The font size of the labels.
*
* @property {string} [projection="SIN"] - Projection type. Can be 'SIN' for orthographic, 'MOL' for mollweide, 'AIT' for hammer-aitoff, 'ZEA' for zenital equal-area or 'MER' for mercator
* @property {string} [projection="SIN"] - Projection type.
* @property {boolean} [log=true] - Whether to log events.
* @property {boolean} [samp=false] - Whether to enable SAMP (Simple Application Messaging Protocol).
* @property {boolean} [realFullscreen=false] - Whether to use real fullscreen mode.
* @property {boolean} [pixelateCanvas=true] - Whether to pixelate the canvas.
*/
/**
* @typedef {string} CooFrame
* String with possible values: 'equatorial', 'ICRS', 'ICRSd', 'j2000', 'gal, 'galactic'
*/
export let Aladin = (function () {
/**
* Creates an instance of the Aladin interactive sky atlas.
@@ -213,12 +210,14 @@ export let Aladin = (function () {
this.options = options;
this.reduceDeformations = true;
// Init the measurement table
this.measurementTable = new MeasurementTable(this);
// parent div
aladinDiv.classList.add("aladin-container");
// measurement table
this.measurementTable = new MeasurementTable(this);
//var location = new Location(locationDiv.find('.aladin-location-text'));
// set different options
// Reticle
this.view = new View(this);
@@ -229,6 +228,7 @@ export let Aladin = (function () {
this.reticle = new Reticle(this.options, this);
this.popup = new Popup(this.aladinDiv, this.view);
this.cacheSurveys = new Map();
this.ui = [];
// Background color
@@ -248,6 +248,10 @@ export let Aladin = (function () {
}
this.setCooGrid(gridOptions);
// Set the projection
let projection = (options && options.projection) || 'SIN';
this.setProjection(projection)
this.gotoObject(options.target, undefined);
if (options.log) {
@@ -274,14 +278,12 @@ export let Aladin = (function () {
i++;
});
} else if (options.survey === ImageSurvey.DEFAULT_SURVEY_ID) {
// DSS is cached inside ImageSurvey class, no need to provide any further information
const survey = this.createImageSurvey(ImageSurvey.DEFAULT_SURVEY_ID);
const survey = ImageSurvey.fromLayerOptions(this, ImageLayer.DEFAULT_SURVEY);
this.setBaseImageLayer(survey);
} else {
this.setBaseImageLayer(options.survey)
}
} else {
} else if (options.surveyUrl) {
// Add the image layers
// For that we check the survey key of options
// It can be given as a single string or an array of strings
@@ -298,6 +300,9 @@ export let Aladin = (function () {
}
this.setBaseImageLayer(url);
} else {
// This case should not happen because if there is no survey given
// then the surveyUrl pointing to the DSS is given.
}
this.view.showCatalog(options.showCatalog);
@@ -342,13 +347,35 @@ export let Aladin = (function () {
// Status bar
if (options.showStatusBar) {
this.statusBar = new StatusBarBox(this);
this.addUI(this.statusBar)
let statusBarOptions = {};
if (typeof options.showStatusBar === "object") {
statusBarOptions = options.showStatusBar;
}
this.statusBar = new StatusBarBox(this, statusBarOptions);
}
// Add the frame control
if (options.showFrame) {
this.addUI(new CooFrame(this))
let cooFrame = CooFrameEnum.fromString(options.cooFrame, CooFrameEnum.J2000);
let cooFrameControl = Input.select({
name: 'frame',
type: 'select',
value: cooFrame.label,
options: [CooFrameEnum.J2000.label, CooFrameEnum.J2000d.label, CooFrameEnum.GAL.label],
change(e) {
self.setFrame(e.target.value)
},
tooltip: {
content: "Change the frame",
position: {
direction: 'bottom'
}
}
});
cooFrameControl.addClass('aladin-cooFrame');
this.addUI(cooFrameControl)
}
// Add the location info
@@ -365,28 +392,24 @@ export let Aladin = (function () {
let stack = new OverlayStackButton(this);
let simbad = new SimbadPointer(this);
let grid = new GridEnabler(this);
this.addUI(stack)
this.addUI(simbad)
this.addUI(grid)
let settings = new SettingsButton(this, {features: {stack, simbad, grid}});
// Add the layers control
if (!options.showLayersControl) {
stack._hide();
if (options.showLayersControl) {
this.addUI(stack)
}
// Add the simbad pointer control
if (!options.showSimbadPointerControl) {
simbad._hide();
if (options.showSimbadPointerControl) {
this.addUI(simbad)
}
// Add the projection control
// Add the coo grid control
if (!options.showCooGridControl) {
grid._hide();
if (options.showCooGridControl) {
this.addUI(grid)
}
// Settings control
if (options.showSettingsControl) {
let settings = new SettingsButton(this, {features: {stack, simbad, grid}});
this.addUI(settings)
}
@@ -403,11 +426,9 @@ export let Aladin = (function () {
if (options.showFullscreenControl) {
this.addUI(new FullScreenActionButton(self))
}
this._applyMediaQueriesUI();
}
Aladin.prototype._applyMediaQueriesUI = function() {
/*Aladin.prototype._applyMediaQueriesUI = function() {
const applyMediaQuery = function(maxWidth, matchingCallback, unmatchingCallback) {
function mqFunction(x) {
if (x.matches) { // If media query matches
@@ -430,7 +451,6 @@ export let Aladin = (function () {
let self = this;
applyMediaQuery('48rem', () => {
if (self.projBtn) {
self.projBtn.update({verbosity: 'reduced'})
@@ -441,7 +461,7 @@ export let Aladin = (function () {
self.projBtn.update({verbosity: 'full'})
}
})
}
}*/
/**** CONSTANTS ****/
Aladin.VERSION = version;
@@ -461,7 +481,7 @@ export let Aladin = (function () {
fov: 60,
backgroundColor: "rgb(60, 60, 60)",
// Zoom toolbar
showZoomControl: false,
showZoomControl: true,
// Menu toolbar
showLayersControl: true,
showFullscreenControl: true,
@@ -608,18 +628,16 @@ export let Aladin = (function () {
* Sets the field of view (FoV) of the Aladin instance to the specified angle in degrees.
*
* @memberof Aladin
* @param {number} FoV - The angle of the field of view in degrees.
* @param {number} fovDegrees - The angle of the field of view in degrees.
*
* @example
* let aladin = A.aladin('#aladin-lite-div');
* aladin.setFoV(60);
*/
Aladin.prototype.setFoV = function (FoV) {
this.view.setZoom(FoV);
Aladin.prototype.setFoV = function (fovDegrees) {
this.view.setZoom(fovDegrees);
};
Aladin.prototype.setFov = Aladin.prototype.setFoV;
// @API
// (experimental) try to adjust the FoV to the given object name. Does nothing if object is not known from Simbad
Aladin.prototype.adjustFovForObject = function (objectName) {
@@ -630,7 +648,7 @@ export let Aladin = (function () {
};
Aladin.prototype.getFovForObject = Aladin.prototype.getFoVForObject = function (objectName, callback) {
Aladin.prototype.getFovForObject = function (objectName, callback) {
var query = "SELECT galdim_majaxis, V FROM basic JOIN ident ON oid=ident.oidref JOIN allfluxes ON oid=allfluxes.oidref WHERE id='" + objectName + "'";
var url = '//simbad.u-strasbg.fr/simbad/sim-tap/sync?query=' + encodeURIComponent(query) + '&request=doQuery&lang=adql&format=json&phase=run';
@@ -848,7 +866,7 @@ export let Aladin = (function () {
}
// planetary case
else {
const body = baseImageLayer.hipsBody;
const body = baseImageLayer.properties.hipsBody;
PlanetaryFeaturesNameResolver.resolve(targetName, body,
function (data) { // success callback
self.view.pointTo(data.lon, data.lat);
@@ -1147,7 +1165,6 @@ export let Aladin = (function () {
Aladin.prototype.addUI = function (ui) {
this.ui.push(ui);
ui.attachTo(this.aladinDiv)
// as the ui is pushed to the dom, setting position may need the aladin instance to work
// so we recompute it
if (ui.options) {
@@ -1174,59 +1191,29 @@ export let Aladin = (function () {
this.view.removeLayer(layer);
};
/**
* @deprecated
* Creates and return an image survey (HiPS) object
* Please use {@link A.imageHiPS} instead for creating a new survey image
*
* @memberof Aladin
* @param {string} id - Mandatory unique identifier for the survey.
* @param {string} [name] - A convinient name for the survey, optional
* @param {string} url - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>Or it can be a "CDS ID" that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* </ul>
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
* @param {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
* @param {ImageSurveyOptions} [options] - Options describing the survey
* @returns {ImageSurvey} A HiPS image object.
*/
Aladin.prototype.createImageSurvey = function(id, name, url, cooFrame, maxOrder, options) {
let surveyOptions = ImageSurvey.cache[id];
// @oldAPI
Aladin.prototype.createImageSurvey = function(id, name, rootUrl, cooFrame, maxOrder, options = {}) {
let cfg = this.cacheSurveys.get(id);
if (!cfg) {
// Add the cooFrame and maxOrder given by the user
// to the list of options passed to the ImageSurvey constructor
if (cooFrame) {
options.cooFrame = cooFrame;
}
if (!surveyOptions) {
surveyOptions = {url, name, maxOrder, cooFrame, ...options};
ImageSurvey.cache[id] = surveyOptions;
if (maxOrder) {
options.maxOrder = maxOrder;
}
cfg = {id, name, rootUrl, options};
this.cacheSurveys.set(id, cfg);
} else {
cfg = Utils.clone(cfg)
}
return new ImageSurvey(id, surveyOptions.url, surveyOptions);
return new ImageSurvey(cfg.id, cfg.name, cfg.rootUrl, cfg.options, this.view);
};
/**
* @deprecated
* Creates and return an image survey (HiPS) object.
* Please use {@link A.imageHiPS} instead for creating a new survey image
*
* @function createImageSurvey
* @memberof Aladin
* @static
* @param {string} id - Mandatory unique identifier for the survey.
* @param {string} [name] - A convinient name for the survey, optional
* @param {string} url - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>Or it can be a "CDS ID" that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* </ul>
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
* @param {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
* @param {ImageSurveyOptions} [options] - Options describing the survey
* @returns {ImageSurvey} A HiPS image object.
*/
Aladin.createImageSurvey = Aladin.prototype.createImageSurvey;
Aladin.prototype.createImageFITS = function(url, name, options, successCallback, errorCallback) {
Aladin.prototype.createImageFITS = function(url, name, options = {}, successCallback = undefined, errorCallback = undefined) {
try {
url = new URL(url);
} catch(e) {
@@ -1238,103 +1225,39 @@ export let Aladin = (function () {
// Do not use proxy with CORS headers until we solve that: https://github.com/MattiasBuelens/wasm-streams/issues/20
//url = Utils.handleCORSNotSameOrigin(url);
let image = ImageFITS.cache[url];
if (!image) {
image = new ImageFITS(url, name, options, successCallback, errorCallback)
ImageFITS.cache[url] = image;
let cfg = this.cacheSurveys.get(url);
if (!cfg) {
cfg = {url, name, options, successCallback, errorCallback}
this.cacheSurveys.set(url, cfg);
} else {
cfg = Utils.clone(cfg)
}
return image;
return new ImageFITS(cfg.url, cfg.name, this.view, cfg.options, cfg.successCallback, cfg.errorCallback);
};
/**
* Creates a FITS image object
*
* @function createImageFITS
* @memberof Aladin
* @static
* @param {string} url - The url of the fits.
* @param {string} [name] - The url of the fits.
* @param {ImageSurveyOptions} [options] - Options for rendering the image
* @param {function} [success] - A success callback
* @param {function} [error] - A success callback
* @returns {ImageSurvey} A FITS image object.
*/
Aladin.createImageFITS = Aladin.prototype.createImageFITS;
Aladin.prototype.newImageSurvey = function(rootUrlOrId, options) {
const idOrUrl = rootUrlOrId;
// Check if the survey has already been added
// Create a new ImageSurvey
const name = idOrUrl;
/**
* @deprecated
* Create a new layer from an url or CDS ID.
* Please use {@link A.imageHiPS} instead for creating a new survey image
*
* @memberof Aladin
* @static
* @param {string} url - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>Or it can be a "CDS ID" that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* </ul>
* @param {ImageSurveyOptions} [options] - Options for rendering the image
* @param {function} [success] - A success callback
* @param {function} [error] - A success callback
* @returns {ImageSurvey} A FITS image object.
*/
Aladin.prototype.newImageSurvey = function(url, options) {
const id = url;
return A.imageHiPS(id, url, options);
return this.createImageSurvey(idOrUrl, name, idOrUrl, null, null, options);
}
/**
* Add a new HiPS layer to the view on top of the others
*
* @memberof Aladin
* @param {string|ImageSurvey} [survey="CDS/P/DSS2/color"] - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>2. Or it can be a CDS ID that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* <li>3. It can also be an {@link ImageSurvey} HiPS object created from {@link A.imageHiPS}</li>
* </ul>
* By default, the {@link https://alasky.cds.unistra.fr/DSS/DSSColor/|Digital Sky Survey 2} survey will be displayed
*/
Aladin.prototype.addNewImageLayer = function(survey="CDS/P/DSS2/color") {
Aladin.prototype.addNewImageLayer = function() {
let layerName = Utils.uuidv4();
this.setOverlayImageLayer(survey, layerName);
// A HIPS_LAYER_ADDED will be called after the hips is added to the view
this.setOverlayImageLayer('CDS/P/DSS2/color', layerName);
}
/**
* Change the base layer of the view
*
* It internally calls {@link Aladin#setBaseImageLayer|Aladin.setBaseImageLayer} with the url/{@link ImageSurvey}/{@link ImageFITS} given
*
* @memberof Aladin
* @param {string|ImageSurvey|ImageFITS} urlOrHiPSOrFITS - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>2. Or it can be a CDS identifier that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* <li>3. A {@link ImageSurvey} HiPS object created from {@link A.imageHiPS}</li>
* <li>4. A {@link ImageFITS} FITS image object</li>
* </ul>
*/
// @param imageSurvey : ImageSurvey object or image survey identifier
// @api
// @old
Aladin.prototype.setImageLayer = function(imageLayer) {
this.setBaseImageLayer(imageLayer);
};
/**
* Change the base layer of the view
*
* It internally calls {@link Aladin#setBaseImageLayer|Aladin.setBaseImageLayer} with the url/{@link ImageSurvey}/{@link ImageFITS} given
*
* @memberof Aladin
* @param {string|ImageSurvey|ImageFITS} urlOrHiPSOrFITS - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>2. Or it can be a CDS ID that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* <li>3. A {@link ImageSurvey} HiPS object created from {@link A.imageHiPS}</li>
* <li>4. A {@link ImageFITS} FITS image object</li>
* </ul>
*/
Aladin.prototype.setImageSurvey = Aladin.prototype.setImageLayer;
// @param imageSurvey : ImageSurvey object or image survey identifier
@@ -1361,20 +1284,9 @@ export let Aladin = (function () {
this.view.removeImageLayer(layer);
};
/**
* Change the base layer of the view
*
* @memberof Aladin
* @param {string|ImageSurvey|ImageFITS} urlOrHiPSOrFITS - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>2. Or it can be a CDS ID that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* <li>3. A {@link ImageSurvey} HiPS object created from {@link A.imageHiPS}</li>
* <li>4. A {@link ImageFITS} FITS image object</li>
* </ul>
*/
Aladin.prototype.setBaseImageLayer = function(urlOrHiPSOrFITS) {
return this.setOverlayImageLayer(urlOrHiPSOrFITS, "base");
Aladin.prototype.setBaseImageLayer = function(idOrSurvey) {
return this.setOverlayImageLayer(idOrSurvey, "base");
};
// @api
@@ -1382,31 +1294,35 @@ export let Aladin = (function () {
return this.view.getImageLayer("base");
};
/**
* Add a new HiPS/FITS image layer in the view
*
* @memberof Aladin
* @param {string|ImageSurvey|ImageFITS} urlOrHiPSOrFITS - Can be:
* <ul>
* <li>1. An url that refers to a HiPS.</li>
* <li>2. Or it can be a CDS ID that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
* <li>3. A {@link ImageSurvey} HiPS object created from {@link A.imageHiPS}</li>
* <li>4. A {@link ImageFITS} FITS image object</li>
* </ul>
* @param {string} [layer="overlay"] - A layer name. By default 'overlay' is chosen and it is destined to be plot
* on top the 'base' layer. If the layer is already present in the view, it will be replaced by the new HiPS/FITS image given here.
*/
Aladin.prototype.setOverlayImageLayer = function (urlOrHiPSOrFITS, layer = "overlay") {
// @api
Aladin.prototype.setOverlayImageLayer = function (idOrUrlOrImageLayer, layer = "overlay") {
let imageLayer;
// 1. User gives an ID
if (typeof urlOrHiPSOrFITS === "string") {
const idOrUrl = urlOrHiPSOrFITS;
imageLayer = A.imageHiPS(idOrUrl, idOrUrl);
if (typeof idOrUrlOrImageLayer === "string") {
const idOrUrl = idOrUrlOrImageLayer;
// Check if the survey has already been added
// Create a new ImageSurvey
/*let isUrl = false;
if (idOrUrl.includes("http")) {
isUrl = true;
}
const name = idOrUrl;
if (isUrl) {
const url = idOrUrl;
const id = url;
// Url
imageLayer = this.createImageSurvey(idOrUrl, name, idOrUrl, null, null);
} else {
const id = idOrUrl;
// ID
imageLayer = this.createImageSurvey(idOrUrl, name, idOrUrl, null, null);
}*/
const name = idOrUrl;
imageLayer = this.createImageSurvey(idOrUrl, name, idOrUrl, null, null);
// 2. User gives a non resolved promise
} else {
imageLayer = urlOrHiPSOrFITS;
imageLayer = idOrUrlOrImageLayer;
}
return this.view.setOverlayImageLayer(imageLayer, layer);
@@ -1553,6 +1469,11 @@ export let Aladin = (function () {
Aladin.prototype.select = async function (mode = 'rect', callback) {
await this.reticle.loaded;
// Default callback selects objects
callback = callback || ((selection) => {
this.view.selectObjects(selection);
});
this.fire('selectstart', {mode, callback});
};
@@ -1589,6 +1510,7 @@ export let Aladin = (function () {
* This method allows you to customize the appearance of the coordinate grid in the Aladin Lite view.
*
* @memberof Aladin
*
* @param {Object} options - Options to customize the coordinate grid.
* @param {string} [options.color] - The color of the coordinate grid.
* @param {number} [options.opacity] - The opacity of the coordinate grid (value between 0 and 1).
@@ -1726,7 +1648,7 @@ export let Aladin = (function () {
let radecsys;
if (this.getBaseImageLayer().isPlanetaryBody()) {
const body = this.getBaseImageLayer().hipsBody
const body = this.getBaseImageLayer().properties.hipsBody
if (body in solarSystemObjects) {
cooType1 = `${solarSystemObjects[body]}LN-`;
cooType2 = `${solarSystemObjects[body]}LT-`;
@@ -1770,65 +1692,39 @@ export let Aladin = (function () {
return WCS;
}
/**
* Restrict the FoV range between a min and a max value
*
* @memberof Aladin
* @param {number} minFoV - in degrees when zoom in at max. If undefined, the zooming in is not limited
* @param {number} maxFoV - in degrees when zoom out at max. If undefined, the zooming out is not limited
*
* @example
* let aladin = A.aladin('#aladin-lite-div');
* aladin.setFoVRange(30, 60);
*/
Aladin.prototype.setFoVRange = function (minFoV, maxFoV) {
if (minFoV > maxFoV) {
var tmp = minFoV;
minFoV = maxFoV;
maxFoV = tmp;
/** restrict FOV range
* @API
* @param minFOV in degrees when zoom in at max
* @param maxFOV in degrees when zoom out at max
*/
Aladin.prototype.setFovRange = Aladin.prototype.setFOVRange = function (minFOV, maxFOV) {
if (minFOV > maxFOV) {
var tmp = minFOV;
minFOV = maxFOV;
maxFOV = tmp;
}
this.view.minFoV = minFoV;
this.view.maxFoV = maxFoV;
this.view.minFOV = minFOV;
this.view.maxFOV = maxFOV;
// reset the field of view
this.setFoV(this.view.fov)
};
Aladin.prototype.setFOVRange = Aladin.prototype.setFoVRange;
/**
* Transform pixel coordinates to world coordinates.
*
* The origin (0,0) of pixel coordinates is at the top-left corner of the Aladin Lite view.
*
* @memberof Aladin
*
* @param {number} x - The x-coordinate in pixel coordinates.
* @param {number} y - The y-coordinate in pixel coordinates.
* @param {CooFrame} [frame] - The frame in which we want to retrieve the coordinates.
* If not given, the frame chosen is the one from the view
*
* @returns {number[]} - An array representing the [Right Ascension, Declination] coordinates in degrees in the `frame`.
* If not specified, returns the coo in the frame of the current view.
* @returns {number[]} - An array representing the [Right Ascension, Declination] coordinates in degrees.
*
* @throws {Error} Throws an error if an issue occurs during the transformation.
*/
Aladin.prototype.pix2world = function (x, y, frame) {
let radec = this.view.wasm.screenToWorld(x, y);
frame = frame || this.view.cooFrame.label;
frame = CooFrameEnum.fromString(frame, CooFrameEnum.J2000);
if (frame !== this.view.cooFrame) {
if (frame.label === 'Galactic') {
console.warn('Conversion from icrs to galactic not yet impl')
} else {
radec = this.view.wasm.viewToICRSCooSys(radec[0], radec[1]);
}
}
let [ra, dec] = radec;
Aladin.prototype.pix2world = function (x, y) {
const [ra, dec] = this.view.wasm.screenToWorld(x, y);
if (ra < 0) {
return [ra + 360.0, dec];
@@ -1841,8 +1737,9 @@ export let Aladin = (function () {
* Transform world coordinates to pixel coordinates in the view.
*
* @memberof Aladin
* @param {number} ra - The Right Ascension (RA) coordinate in degrees. Frame considered is the current view frame
* @param {number} dec - The Declination (Dec) coordinate in degrees. Frame considered is the current view frame
*
* @param {number} ra - The Right Ascension (RA) coordinate in degrees.
* @param {number} dec - The Declination (Dec) coordinate in degrees.
*
* @returns {number[]} - An array representing the [x, y] coordinates in pixel coordinates in the view.
*
@@ -1856,20 +1753,19 @@ export let Aladin = (function () {
* Get the angular distance in degrees between two locations
*
* @memberof Aladin
*
* @param {number} x1 - The x-coordinate of the first pixel coordinates.
* @param {number} y1 - The y-coordinate of the first pixel coordinates.
* @param {number} x2 - The x-coordinate of the second pixel coordinates.
* @param {number} y2 - The y-coordinate of the second pixel coordinates.
* @param {CooFrame} [frame] - The frame in which we want to retrieve the coordinates.
* If not given, the frame chosen is the one from the view
*
* @returns {number} - The angular distance between the two pixel coordinates in degrees
*
* @throws {Error} Throws an error if an issue occurs during the transformation.
*/
Aladin.prototype.angularDist = function (x1, y1, x2, y2, frame) {
const [ra1, dec1] = this.pix2world(x1, y1, frame);
const [ra2, dec2] = this.pix2world(x2, y2, frame);
Aladin.prototype.angularDist = function (x1, y1, x2, y2) {
const [ra1, dec1] = this.pix2world(x1, y1);
const [ra2, dec2] = this.pix2world(x2, y2);
return this.wasm.angularDist(ra1, dec1, ra2, dec2);
};
@@ -1878,6 +1774,7 @@ export let Aladin = (function () {
* Gets a set of points along the current Field of View (FoV) corners.
*
* @memberof Aladin
*
* @param {number} nbSteps - The number of points to return along each side (the total number of points returned is 4 * nbSteps).
*
* @returns {number[][]} - A set of positions along the current FoV with the following format: [[ra1, dec1], [ra2, dec2], ..., [ra_n, dec_n]].
@@ -1886,7 +1783,7 @@ export let Aladin = (function () {
* @throws {Error} Throws an error if an issue occurs during the transformation.
*
*/
Aladin.prototype.getFoVCorners = function (nbSteps) {
Aladin.prototype.getFovCorners = function (nbSteps) {
// default value: 1
if (!nbSteps || nbSteps < 1) {
nbSteps = 1;
@@ -1914,6 +1811,7 @@ export let Aladin = (function () {
* Gets the current Field of View (FoV) size in degrees as a 2-element array.
*
* @memberof Aladin
*
* @returns {number[]} - A 2-element array representing the current FoV size in degrees. The first element is the FoV width,
* and the second element is the FoV height.
*/
@@ -1932,12 +1830,11 @@ export let Aladin = (function () {
return [fovX, fovY];
};
Aladin.prototype.getFoV = Aladin.prototype.getFov;
/**
* Returns the size in pixels for the Aladin view
*
* @memberof Aladin
*
* @returns {number[]} - A 2-element array representing the current Aladin view size in pixels. The first element is the width,
* and the second element is the height.
*/
@@ -1946,10 +1843,9 @@ export let Aladin = (function () {
};
/**
* Returns the HTML div element
* @API
*
* @memberof Aladin
* @return {HTMLElement} - The aladin lite div HTML element
* @return the jQuery object representing the DIV element where the Aladin Lite instance lies
*/
Aladin.prototype.getParentDiv = function () {
return this.aladinDiv;
@@ -2048,6 +1944,7 @@ export let Aladin = (function () {
* Display a JPEG image in the Aladin Lite view.
*
* @memberof Aladin
*
* @param {string} url - The URL of the JPEG image.
* @param {Object} options - Options to customize the display. Can include the following properties:
* @param {string} options.label - A label for the displayed image.
@@ -2057,8 +1954,7 @@ export let Aladin = (function () {
* @param {Function} successCallback - The callback function to be executed on a successful display.
* The callback gives the ra, dec, and fov of the image;
* @param {Function} errorCallback - The callback function to be executed if an error occurs during display.
* @param {string} [layer="base"] - The name of the layer. If not specified, it will be replace the base layer.
*
*
* @example
* aladin.displayJPG(
* // the JPG to transform to HiPS
@@ -2091,6 +1987,7 @@ export let Aladin = (function () {
* Display a JPEG image in the Aladin Lite view.
*
* @memberof Aladin
*
* @param {string} url - The URL of the JPEG image.
* @param {Object} options - Options to customize the display. Can include the following properties:
* @param {string} options.label - A label for the displayed image.
@@ -2100,7 +1997,6 @@ export let Aladin = (function () {
* @param {Function} successCallback - The callback function to be executed on a successful display.
* The callback gives the ra, dec, and fov of the image;
* @param {Function} errorCallback - The callback function to be executed if an error occurs during display.
* @param {string} [layer="overlay"] - The name of the layer. If not specified, it will add a new overlay layer on top of the base.
*
* @example
* aladin.displayJPG(
@@ -2115,7 +2011,7 @@ export let Aladin = (function () {
* })
*);
*/
Aladin.prototype.displayJPG = function (url, options, successCallback, errorCallback, layer = "overlay") {
Aladin.prototype.displayJPG = Aladin.prototype.displayPNG = function (url, options, successCallback, errorCallback) {
options = options || {};
options.color = true;
options.label = options.label || "JPG/PNG image";
@@ -2165,7 +2061,7 @@ export let Aladin = (function () {
var meta = response.data.meta;
const survey = self.createImageSurvey(response.data.url, label, response.data.url);
self.setOverlayImageLayer(survey, layer);
self.setOverlayImageLayer(survey, "overlay");
var transparency = (options && options.transparency) || 1.0;
survey.setOpacity(transparency);
@@ -2187,8 +2083,6 @@ export let Aladin = (function () {
});
};
Aladin.prototype.displayPNG = Aladin.prototype.displayJPG;
/*
Aladin.prototype.setReduceDeformations = function (reduce) {
this.reduceDeformations = reduce;

View File

@@ -27,6 +27,8 @@
* Author: Thomas Boch[CDS]
*
*****************************************************************************/
import { HPXVertices } from "../core/pkg/core";
import A from "./A";
import { Aladin } from "./Aladin";
/**
@@ -146,12 +148,8 @@ export let AladinUtils = {
},
/**
* @deprecated
*
* Converts celestial coordinates (ra, dec) to screen coordinates (x, y) in pixels within the view.
* Use {@link Aladin.world2pix} instead
*
*
*
* @function
* @memberof AladinUtils
* @name radecToViewXy
@@ -162,7 +160,25 @@ export let AladinUtils = {
* @returns {number[]} xy - A 2 elements array representing the screen coordinates [X, Y] in pixels.
*/
radecToViewXy: function(ra, dec, aladin) {
return aladin.world2pix(ra, dec);
let xy = aladin.view.wasm.worldToScreen(ra, dec);
return xy;
},
/**
* Converts screen coordinates (X, Y) to clip coordinates within the view (coordinates lying between 0 and 1).
*
* @function
* @memberof AladinUtils
* @name viewXyToClipXy
*
* @param {number} x - X-coordinate in pixel screen coordinates
* @param {number} y - Y-coordinate in pixel screen coordinates.
* @param {Aladin} aladin - Aladin Lite object containing the WebAssembly API.
* @returns {number[]} xy - An array representing the coordinates [X, Y] in clipping space.
*/
viewXyToClipXy: function(x, y, aladin) {
let xy = aladin.view.wasm.screenToClip(x, y);
return xy;
},
/**

View File

@@ -55,6 +55,7 @@ export let Catalog = (function() {
* @param {string} [options.name="catalog"] - The name of the catalog.
* @param {string} [options.color] - The color associated with the catalog.
* @param {number} [options.sourceSize=8] - The size of the sources in the catalog.
* @param {number} [options.markerSize=12] - The size of the markers associated with sources.
* @param {string} [options.shape="square"] - The shape of the sources (can be, "square", "circle", "plus", "cross", "rhomb", "triangle").
* @param {number} [options.limit] - The maximum number of sources to display.
* @param {function} [options.onClick] - The callback function to execute on a source click.
@@ -63,7 +64,6 @@ export let Catalog = (function() {
* @param {string} [options.decField] - The ID or name of the field holding Declination (dec).
* @param {function} [options.filter] - The filtering function for sources.
* @param {boolean} [options.displayLabel=false] - Whether to display labels for sources.
* @param {string} [options.labelColumn] - The name of the column to be used for the label.
* @param {string} [options.labelColor] - The color of the source labels.
* @param {string} [options.labelFont="10px sans-serif"] - The font for the source labels.
*

View File

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

275
src/js/ColorMap.js Normal file
View File

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

View File

@@ -31,9 +31,6 @@
import { GenericPointer } from "./GenericPointer.js";
import A from "./A.js";
import { CatalogQueryBox } from "./gui/Box/CatalogQueryBox.js";
import cameraIconUrl from '../../assets/icons/camera.svg'
import targetIconUrl from '../../assets/icons/target.svg';
import uploadIconUrl from '../../assets/icons/upload.svg';
export let DefaultActionsForContextMenu = (function () {
@@ -48,38 +45,31 @@ export let DefaultActionsForContextMenu = (function () {
return [
{
label: "Copy position", action(o) {
let msg;
navigator.clipboard.writeText(o.target.innerText)
.then(() => {
msg = 'successful'
if (aladinInstance.statusBar) {
aladinInstance.statusBar.appendMessage({
message: 'Reticle location saved!',
duration: 2000,
type: 'info'
})
}
})
.catch((e) => {
msg = 'unsuccessful'
console.info('Oops, unable to copy', e);
})
.finally(() => {
console.info('Copying text command was ' + msg);
var r = document.createRange();
r.selectNode(o.target);
window.getSelection().removeAllRanges();
window.getSelection().addRange(r);
let statusBarMsg;
try {
let successful = document.execCommand('copy');
statusBarMsg = successful ? 'Position copied!' : 'Position could not be copied!';
} catch (err) {
statusBarMsg = 'Oops, unable to copy to clipboard';
}
if (a.statusBar) {
a.statusBar.appendMessage({
message: statusBarMsg,
duration: 2000,
type: 'info'
})
}
window.getSelection().removeAllRanges();
}
},
{
label: {
icon: {
tooltip: {content: 'Download a PNG image file of the view', position: {direction: 'top'}},
monochrome: true,
url: cameraIconUrl,
size: 'small',
},
content: 'Take a snapshot'
},
action(o) { a.exportAsPNG(); }
label: "Take snapshot", action(o) { a.exportAsPNG(); }
},
{
label: "Add",
@@ -95,30 +85,23 @@ export let DefaultActionsForContextMenu = (function () {
{
label: 'New catalogue layer', action(o) {
let catBox = new CatalogQueryBox(a)
catBox._show({
header: {
title: 'Add a new catalogue',
draggable: true
},
position: {
anchor :'center center'
},
});
if (catBox.isHidden) {
catBox._show({
header: {
title: 'Add a new catalogue',
draggable: true
},
position: {
anchor :'center center'
},
});
}
}
},
]
},
{
label: {
icon: {
monochrome: true,
url: uploadIconUrl,
cssStyle: {
cursor: 'help',
}
},
content: "Load a local file"
},
label: "Load local file",
subMenu: [
{
label: 'FITS image', action(o) {
@@ -186,21 +169,8 @@ export let DefaultActionsForContextMenu = (function () {
]
},
{
label: {
icon: {
tooltip: {content: 'Use Sesame, our name resolver!', position: {direction: 'top'}},
monochrome: true,
url: targetIconUrl,
size: 'small',
},
content: 'What is this?'
},
action(o, ctxMenu) {
GenericPointer(a.view, {
x: parseInt(ctxMenu.element().style.left),
y: parseInt(ctxMenu.element().style.top)
});
label: "What is this?", action(o) {
GenericPointer(a.view, o);
}
},
{

View File

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

View File

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

View File

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

View File

@@ -11,14 +11,9 @@ import { Utils } from './Utils';
// allow to call either Simbad or Planetary features Pointers
export let GenericPointer = function (view, e) {
let xymouse;
if (e instanceof Event) {
xymouse = Utils.relMouseCoords(e);
} else {
xymouse = e;
}
const xymouse = Utils.relMouseCoords(e);
let radec = view.aladin.pix2world(xymouse.x, xymouse.y, 'icrs');
let radec = view.aladin.pix2world(xymouse.x, xymouse.y);
if (radec) {
// sky case
if (view.aladin.getBaseImageLayer().isPlanetaryBody() === false) {
@@ -28,7 +23,7 @@ export let GenericPointer = function (view, e) {
// planetary body case
else {
// TODO: replace with actual value
const body = view.aladin.getBaseImageLayer().hipsBody;
const body = view.aladin.getBaseImageLayer().properties.hipsBody;
PlanetaryFeaturesPointer.query(radec[0], radec[1], Math.min(80, view.fov / 20.0), body, view.aladin);
}
} else {

View File

@@ -65,6 +65,7 @@ HiPSProperties.fetchFromID = async function(ID) {
// Exactly one matching
result = metadata[0];
}
return result;
}
}
@@ -73,7 +74,7 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
try {
urlOrId = new URL(urlOrId);
} catch (e) {
// Relative path test
// Relative path
try {
urlOrId = Utils.getAbsoluteURL(urlOrId)
@@ -134,36 +135,27 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
return result;
}
HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
const pingHiPSServiceUrl = async (baseUrl) => {
baseUrl = Utils.fixURLForHTTPS(baseUrl);
HiPSProperties.getFasterMirrorUrl = function (metadata) {
const pingHiPSServiceUrl = (hipsServiceUrl) => {
hipsServiceUrl = Utils.fixURLForHTTPS(hipsServiceUrl);
const controller = new AbortController()
const maxTime = 1000;
let startRequestTime = Date.now();
const maxTime = 500;
// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), maxTime)
let startRequestTime = performance.now();
let options = {
//headers: { 'Cache-Control': 'no-cache' }, // Disable caching
method: 'GET',
signal: controller.signal,
mode: 'cors',
cache: "no-cache",
};
let validRequest = await fetch(baseUrl + '/properties', options).then((resp) => {
const promise = fetch(hipsServiceUrl + '/properties', { cache: 'no-store', signal: controller.signal, mode: "cors" }).then(response => {
const duration = Date.now() - startRequestTime;//the time needed to do the request
// completed request before timeout fired
clearTimeout(timeoutId)
// Resolve with the time duration of the request
return Promise.resolve(true);
return { duration: duration, baseUrl: hipsServiceUrl, validRequest: true };
}).catch((e) => {
return Promise.resolve(false);
return { duration: maxTime, baseUrl: hipsServiceUrl, validRequest: false };
});
const duration = performance.now() - startRequestTime;//the time needed to do the request
return {duration, validRequest, baseUrl};
return promise;
};
// Get all the possible hips_service_url urls
@@ -200,38 +192,21 @@ HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
});
//console.log(validResponses)
let newUrlResp;
if (validResponses.length >= 2) {
const isSecondUrlOk = ((validResponses[1].duration - validResponses[0].duration) / validResponses[0].duration) < 0.10;
const isSecondUrlOk = ((validResponses[1].duration - validResponses[0].duration) / validResponses[0].duration) < 0.20;
if (isSecondUrlOk) {
newUrlResp = validResponses[getRandomIntInclusive(0, 1)];
return validResponses[getRandomIntInclusive(0, 1)].baseUrl;
} else {
newUrlResp = validResponses[0];
return validResponses[0].baseUrl;
}
} else if (validResponses.length === 1) {
newUrlResp = validResponses[0];
return validResponses[0].baseUrl;
} else {
// no valid response => we return an error
return Promise.reject('Survey not found. 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)
let urlChosen;
if (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 {
// good difference we take the best
urlChosen = newUrlResp.baseUrl;
}
//console.log('curr url', currUrlResp, ', new ', newUrlResp)
urlChosen = Utils.fixURLForHTTPS(urlChosen)
return urlChosen;
})
.then((url) => Utils.fixURLForHTTPS(url))
}

View File

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

218
src/js/ImageLayer.js Normal file
View File

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

View File

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

View File

@@ -81,6 +81,11 @@ export let MeasurementTable = (function() {
this.table = new Tabs({
aladin: this.aladin,
layout,
cssStyle: {
position: 'absolute',
bottom: '2.4rem',
maxWidth: '100%',
}
}, this.aladin.aladinDiv);
};

View File

@@ -103,19 +103,12 @@ export let PlanetaryFeaturesPointer = (function() {
const featureFieldIdx = fields.findIndex((element) => element.includes('feature_name'));
const featureName = values[featureFieldIdx];
const featureId = values[fields.indexOf('feature_id')];
let moreInfoURL = 'https://planetarynames.wr.usgs.gov/Feature/' + featureId;
if (body === 'earth') {
const placeId = values[fields.indexOf('place_id')];
moreInfoURL = 'https://nominatim.openstreetmap.org/ui/details.html?place_id=' + placeId;
}
const title = '<div class="aladin-sp-title"><a target="_blank" href=" ' + moreInfoURL + '">' + featureName + '</a></div>';
const featureId = values[fields.indexOf('feature_id')]
const title = '<div class="aladin-sp-title"><a target="_blank" href="https://planetarynames.wr.usgs.gov/Feature/' + featureId + '">' + featureName + '</a></div>';
const featureType = values[fields.indexOf('feature_type')]
let content = '<div class="aladin-sp-content">' + ' ' + '</div>';
content += '<em>Type: </em>' + featureType + '<br><br>';
content += '<a target="_blank" href="' + moreInfoURL + '">More information</a>';
content += '<a target="_blank" href="https://planetarynames.wr.usgs.gov/Feature/' + featureId + '">More information</a>';
let lon = parseFloat(values[lonFieldIdx]);
const lat = parseFloat(values[latFieldIdx]);

View File

@@ -43,16 +43,16 @@ import { ProjectionEnum } from "./ProjectionEnum.js";
export let Polyline= (function() {
function _calculateMag2ForNoSinProjections(line, view) {
// check if the line is too big (in the clip space) to be drawn
const [x1, y1] = view.wasm.screenToClip(line.x1, line.y1);
const [x2, y2] = view.wasm.screenToClip(line.x2, line.y2);
const [x1, y1] = AladinUtils.viewXyToClipXy(line.x1, line.y1, view.aladin);
const [x2, y2] = AladinUtils.viewXyToClipXy(line.x2, line.y2, view.aladin);
const mag2 = (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2);
return mag2;
}
function _isAcrossCollignonZoneForHpxProjection(line, view) {
const [x1, y1] = view.wasm.screenToClip(line.x1, line.y1);
const [x2, y2] = view.wasm.screenToClip(line.x2, line.y2);
const [x1, y1] = AladinUtils.viewXyToClipXy(line.x1, line.y1, view.aladin);
const [x2, y2] = AladinUtils.viewXyToClipXy(line.x2, line.y2, view.aladin);
// x, y, between -1 and 1
let triIdxCollignionZone = function(x, y) {

View File

@@ -90,7 +90,6 @@ export let Popup = (function() {
}
source.popup = this;
this.source = source;
this.setPosition(source.x, source.y);
};

View File

@@ -29,26 +29,25 @@
*****************************************************************************/
export let ProjectionEnum = {
// Zenithal
TAN: {id: 1, fov: 150, label: "Tangential"}, /* Gnomonic projection */
STG: {id: 2, fov: 360, label: "Stereographic"}, /* Stereographic projection */
SIN: {id: 3, fov: 180, label: "Spheric"}, /* Orthographic */
// TODO: fix why the projection disappears at fov = 360.0
ZEA: {id: 4, fov: 359.999, label: "Zenital equal-area"}, /* Equal-area */
TAN: {id: 1, fov: 150, label: "gnomonic"}, /* Gnomonic projection */
STG: {id: 2, fov: 360, label: "stereographic"}, /* Stereographic projection */
SIN: {id: 3, fov: 180, label: "orthographic"}, /* Orthographic */
ZEA: {id: 4, fov: 360, label: "zenital equal-area"}, /* Equal-area */
//FEYE: {id: 5, fov: 190, label: "fish eye"},
//AIR: {id: 6, fov: 360, label: "airy"},
//AZP: {fov: 180},
//ARC: {id: 7, fov: 360, label: "zenital equidistant"},
//NCP: {id: 8, fov: 180, label: "north celestial pole"},
// Cylindrical
MER: {id: 9, fov: 360, label: "Mercator"},
MER: {id: 9, fov: 360, label: "mercator"},
//CAR: {id: 10, fov: 360, label: "plate carrée"},
//CEA: {id: 11, fov: 360, label: "cylindrical equal area"},
//CYP: {id: 12, fov: 360, label: "cylindrical perspective"},
// Pseudo-cylindrical
AIT: {id: 13, fov: 360, label: "Hammer-toff"},
AIT: {id: 13, fov: 360, label: "hammer-aitoff"},
//PAR: {id: 14, fov: 360, label: "parabolic"},
//SFL: {id: 15, fov: 360, label: "sanson-flamsteed"},
MOL: {id: 16, fov: 360, label: "Mollweide"},
MOL: {id: 16, fov: 360, label: "mollweide"},
// Conic
//COD: {id: 17, fov: 360, label: "conic equidistant"},
// Hybrid

View File

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

View File

@@ -40,10 +40,6 @@ export let URLBuilder = (function() {
url += '&MAXREC=' + options.limit;
}
if (options && options.verbosity) {
url += '&VERB=' + options.verbosity;
}
const orderBy = options && options.orderBy || 'nb_ref';
url += '&ORDER_BY=' + orderBy;

View File

@@ -50,8 +50,10 @@ import { ObsCore } from "./vo/ObsCore.js";
import { DefaultActionsForContextMenu } from "./DefaultActionsForContextMenu.js";
import { Layout } from "./gui/Layout.js";
import { SAMPActionButton } from "./gui/Button/SAMP.js";
import { Icon } from "./gui/Widgets/Icon.js";
import openerIconUrl from '../../assets/icons/loading.svg'
import { ImageSurvey } from "./ImageSurvey.js";
import { ImageFITS } from "./ImageFITS.js";
import { ImageLayer } from "./ImageLayer.js";
export let View = (function () {
@@ -63,6 +65,8 @@ export let View = (function () {
this.aladinDiv = this.aladin.aladinDiv;
this.createCanvases();
this.loadingState = false;
let self = this;
self.redrawClbk = this.redraw.bind(this);
@@ -80,6 +84,9 @@ export let View = (function () {
callback(self.wasm);
});
// Retrieve all the possible colormaps
ColorCfg.COLORMAPS = this.wasm.getAvailableColormapList();
} catch (e) {
// For browsers not supporting WebGL2:
// 1. Print the original exception message in the console
@@ -121,6 +128,7 @@ export let View = (function () {
this.aladinDiv.ondragover = Utils.dragOverHandler;
//this.location = location;
this.mustClearCatalog = true;
this.mode = View.PAN;
@@ -131,8 +139,18 @@ export let View = (function () {
var lon, lat;
lon = lat = 0;
this.projection = ProjectionEnum.SIN;
// FoV init settings
this.viewCenter = { lon: lon, lat: lat }; // position of center of view
this.cooFrame = CooFrameEnum.fromString(this.options.cooFrame, CooFrameEnum.J2000);
// Frame setting
this.changeFrame(this.cooFrame);
this.selector = new Selector(this);
// Zoom starting setting
const si = 500000.0;
const alpha = 40.0;
let initialFov = this.options.fov || 180.0;
@@ -142,23 +160,7 @@ export let View = (function () {
initialDistance: undefined,
initialAccDelta: Math.pow(si / initialFov, 1.0 / alpha)
};
// Projection definition
const projName = (this.options && this.options.projection) || "SIN";
this.setProjection(projName)
// Then set the zoom properly once the projection is defined
this.setZoom(initialFov);
// Target position settings
this.viewCenter = { lon, lat }; // position of center of view
// Coo frame setting
const cooFrame = CooFrameEnum.fromString(this.options.cooFrame, CooFrameEnum.J2000);
this.changeFrame(cooFrame);
this.selector = new Selector(this);
// current reference image survey displayed
this.imageLayers = new Map();
@@ -195,6 +197,7 @@ export let View = (function () {
this.empty = true;
//this.fixLayoutDimensions();
this.promises = [];
this.firstHiPS = true;
this.curNorder = 1;
@@ -228,18 +231,19 @@ export let View = (function () {
self.fixLayoutDimensions();
})
} else {*/
let resizeLayout = () => {
self.fixLayoutDimensions();
}
let resizeLayout = () => {
self.fixLayoutDimensions();
}
let doit;
this.resizeObserver = new ResizeObserver(() => {
clearTimeout(doit);
doit = setTimeout(resizeLayout, 100);
});
let doit;
this.resizeObserver = new ResizeObserver(() => {
//clearTimeout(doit);
//doit = setTimeout(resizeLayout, 100);
resizeLayout();
});
self.resizeObserver.observe(this.aladinDiv);
//}
self.resizeObserver.observe(this.aladinDiv)
/**/
this.throttledPositionChanged = Utils.throttle(
() => {
@@ -346,13 +350,10 @@ export let View = (function () {
// called at startup and when window is resized
// The WebGL backend is resized
View.prototype.fixLayoutDimensions = function () {
// make de line height at 0. This prevents the resize observer to infinitely
// trigger over and over.
this.aladinDiv.style.setProperty('line-height', 0);
Utils.cssScale = undefined;
var computedWidth = parseFloat(this.aladinDiv.getBoundingClientRect().width) || 1.0;
var computedHeight = parseFloat(this.aladinDiv.getBoundingClientRect().height) || 1.0;
var computedWidth = parseFloat(window.getComputedStyle(this.aladinDiv).width) || 1.0;
var computedHeight = parseFloat(window.getComputedStyle(this.aladinDiv).height) || 1.0;
this.width = Math.max(computedWidth, 1);
this.height = Math.max(computedHeight, 1); // this prevents many problems when div size is equal to 0
@@ -367,6 +368,10 @@ export let View = (function () {
this.mouseMoveIncrement = 160 / this.largestDim;
// reinitialize 2D context
this.imageCtx = this.imageCanvas.getContext("webgl2");
//this.aladinDiv.style.width = this.width + "px";
//this.aladinDiv.style.height = this.height + "px";
this.wasm.resize(this.width, this.height);
this.catalogCtx = this.catalogCanvas.getContext("2d");
this.catalogCtx.canvas.width = this.width;
@@ -376,14 +381,6 @@ export let View = (function () {
this.gridCtx.canvas.width = this.width;
this.gridCtx.canvas.height = this.height;
this.imageCtx = this.imageCanvas.getContext("webgl2");
this.imageCtx.canvas.style.width = this.width + "px";
this.imageCtx.canvas.style.height = this.height + "px";
this.wasm.resize(this.width, this.height);
pixelateCanvasContext(this.imageCtx, this.aladin.options.pixelateCanvas);
// change logo
@@ -405,8 +402,6 @@ export let View = (function () {
}
this.computeNorder();
this.aladinDiv.style.removeProperty('line-height');
};
var pixelateCanvasContext = function (ctx, pixelateFlag) {
@@ -636,9 +631,13 @@ export let View = (function () {
// Take as start cut values what is inside the properties
// If the cuts are not defined in the metadata of the survey
// then we take what has been defined by the user
cutMinInit = imageLayer.getColorCfg().minCut || 0.0;
cutMaxInit = imageLayer.getColorCfg().maxCut || 1.0;
if (imageLayer.imgFormat === "fits") {
cutMinInit = imageLayer.properties.minCutout || imageLayer.getColorCfg().minCut || 0.0;
cutMaxInit = imageLayer.properties.maxCutout || imageLayer.getColorCfg().maxCut || 1.0;
} else {
cutMinInit = imageLayer.getColorCfg().minCut || 0.0;
cutMaxInit = imageLayer.getColorCfg().maxCut || 1.0;
}
}
}
@@ -812,6 +811,8 @@ export let View = (function () {
if (view.mode == View.TOOL_SIMBAD_POINTER) {
// call Simbad pointer or Planetary features
GenericPointer(view, e);
// exit the simbad pointer mode
//view.setMode(View.PAN);
return; // when in TOOL_SIMBAD_POINTER mode, we do not call the listeners
}
@@ -1352,7 +1353,6 @@ export let View = (function () {
this.selection = Selector.getObjects(selection, this);
}
if (this.selection.length > 0) {
this.selection.forEach((objListPerCatalog) => {
objListPerCatalog.forEach((obj) => obj.select())
@@ -1409,24 +1409,10 @@ export let View = (function () {
// Called for touchmove events
// initialAccDelta must be consistent with fovDegrees here
View.prototype.setZoom = function (fov) {
// limit the fov in function of the projection
fov = Math.min(fov, this.projection.fov);
// then clamp the fov between minFov and maxFov
const minFoV = this.minFoV;
const maxFoV = this.maxFoV;
if (minFoV) {
fov = Math.max(fov, minFoV);
}
if (maxFoV) {
fov = Math.min(fov, maxFoV);
}
this.wasm.setFieldOfView(fov);
View.prototype.setZoom = function (fovDegrees) {
fovDegrees = Math.min(fovDegrees, this.projection.fov);
this.wasm.setFieldOfView(fovDegrees);
this.updateZoomState();
};
@@ -1535,10 +1521,6 @@ export let View = (function () {
};
View.prototype.setOverlayImageLayer = function (imageLayer, layer = "overlay") {
// set the view to the image layer object
// do the properties query if needed
imageLayer.setView(this);
// register its promise
this.imageLayersBeingQueried.set(layer, imageLayer);
@@ -1552,12 +1534,20 @@ export let View = (function () {
// Check whether this layer already exist
const idxOverlayLayer = this.overlayLayers.findIndex(overlayLayer => overlayLayer == layerName);
if (idxOverlayLayer == -1) {
// it does not exist so we add it to the stack
this.overlayLayers.push(layerName);
}
this.imageLayers.set(layerName, imageLayer);
// Find the toppest layer
//const toppestLayer = this.overlayLayers[this.overlayLayers.length - 1];
//this.selectedLayer = toppestLayer;
// Remove the existant layer if there is one
let existantImageLayer = this.imageLayers.get(layerName);
if (existantImageLayer) {
existantImageLayer.added = false;
}
this.imageLayers.set(layerName, imageLayer);
ALEvent.HIPS_LAYER_ADDED.dispatchedTo(this.aladinDiv, { layer: imageLayer });
}
@@ -1580,6 +1570,9 @@ export let View = (function () {
.then((imageLayer) => {
// Add to the backend
const promise = imageLayer.add(layer);
self.loadingState = true;
ALEvent.FETCH.dispatchedTo(document, {task});
return promise;
@@ -1597,21 +1590,18 @@ export let View = (function () {
}
// change the view frame in case we have a planetary hips loaded
if (imageLayer.hipsBody) {
if (imageLayer.properties.hipsBody) {
if (this.options.showFrame) {
this.aladin.setFrame('J2000d');
}
}
})
.catch((e) => {
// remove it from the cache
delete ImageSurvey.cache[imageLayer.id]
delete ImageFITS.cache[imageLayer.id]
throw e;
})
.finally(() => {
// Loading state is over
self.loadingState = false;
ALEvent.RESOURCE_FETCHED.dispatchedTo(document, {task});
self.imageLayersBeingQueried.delete(layer);
@@ -1625,7 +1615,9 @@ export let View = (function () {
if (noMoreLayersToWaitFor) {
if (self.empty) {
// no promises to launch!
//self.aladin.setBaseImageLayer(self.aladin.createImageSurvey(ImageSurvey.DEFAULT_SURVEY_ID));
const dssLayerOptions = ImageLayer.DEFAULT_SURVEY
self.aladin.setBaseImageLayer(ImageSurvey.fromLayerOptions(self, dssLayerOptions));
} else {
// there is surveys that have been queried
// rename the first overlay layer to "base"
@@ -1694,8 +1686,6 @@ export let View = (function () {
// Get the survey to remove to dissociate it from the view
imageLayer.added = false;
// Delete it
this.imageLayers.delete(layer);
const idxOverlaidLayer = this.overlayLayers.findIndex(overlaidLayer => overlaidLayer == layer);
if (idxOverlaidLayer == -1) {
@@ -1703,13 +1693,17 @@ export let View = (function () {
return;
}
// Delete it
this.imageLayers.delete(layer);
// Remove it from the layer stack
this.overlayLayers.splice(idxOverlaidLayer, 1);
if (this.overlayLayers.length === 0) {
this.empty = true;
} else if (this.selectedLayer === layer) {
// If the layer removed was selected then we select the base layer
// find the toppest layer
//const toppestLayer = this.overlayLayers[this.overlayLayers.length - 1];
this.selectedLayer = 'base';
}
@@ -1719,8 +1713,9 @@ export let View = (function () {
const noMoreLayersToWaitFor = this.promises.length === 0;
if (noMoreLayersToWaitFor && this.empty) {
// no promises to launch!
const dssId = Aladin.DEFAULT_OPTIONS.survey;
this.aladin.setBaseImageLayer(dssId);
const idxServiceUrl = Math.round(Math.random());
const dssUrl = Aladin.DEFAULT_OPTIONS.surveyUrl[idxServiceUrl]
this.aladin.setBaseImageLayer(dssUrl);
}
};
@@ -1749,7 +1744,7 @@ export let View = (function () {
projName = 'SIN'
}
if (this.projection && this.projection.id === ProjectionEnum[projName].id) {
if (this.projection.id === ProjectionEnum[projName].id) {
return;
}

View File

@@ -77,6 +77,7 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
);
}
else {
console.log('cone search', params.baseURL)
let url = params.baseURL;
if (! url.endsWith('?')) {
url += '?';
@@ -247,11 +248,9 @@ import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
if (self.box) {
self.box.remove();
}
// output the resulting cone search in the icrs frame
self.box = new ConeSearchBox(aladin, {frame: 'icrs'});
self.box = new ConeSearchBox(aladin);
self.box.attach({
callback: (cs) => {
// the cone search services are asking for
self.fnIdSelected('coneSearch', {
baseURL: self.selectedItem.cs_service_url,
id: self.selectedItem.ID,

View File

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

View File

@@ -41,8 +41,6 @@ import { Input } from "../Widgets/Input.js";
.then((HiPSes) => {
HiPSes.forEach((h) => {
HiPSSelectorBox.HiPSList[h.obs_title] = h
HiPSSelectorBox.HiPSList[h.ID] = h
});
inputText.update({autocomplete: {options: Object.keys(HiPSSelectorBox.HiPSList)}})

View File

@@ -85,6 +85,10 @@ export class ServiceQueryBox extends Box {
.catch((e) => {
window.alert(e)
})
.finally(() => {
// set cursor back to the normal mode
//loadingBtn.remove();
})
},
subInputs: []
});
@@ -152,6 +156,8 @@ export class ServiceQueryBox extends Box {
self.form.set('ra', +lon)
self.form.set('dec', +lat)
self.form.set('rad', fov)
console.log(lon, lat, fov)
} catch (e) {
alert(e, 'Cone search out of projection')
}

View File

@@ -38,6 +38,14 @@ import { Icon } from "../Widgets/Icon";
export class StatusBarBox extends Box {
constructor(aladin, options) {
options.cssStyle = {
color: 'white',
backgroundColor: 'black',
borderRadius: '3px',
padding: 0,
...options.cssStyle
};
super(options, aladin.aladinDiv)
this.addClass("aladin-status-bar");
@@ -122,12 +130,12 @@ export class StatusBarBox extends Box {
position: {
direction: "top",
},
hoverable: true,
delayShowUpTime: '500ms',
cssStyle: {
fontSize: 'x-small',
border: "1px solid white",
fontSize: 'xx-small',
maxWidth: "200px",
"overflow-wrap": "break-word",
"pointer-events": "auto",
}
},
});

View File

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

View File

@@ -31,22 +31,19 @@
import { ActionButton } from "../Widgets/ActionButton.js";
import { ContextMenu } from "../Widgets/ContextMenu.js";
/*
options = {
action: (connector) => {
}
tooltip
}
*/
export class CtxMenuActionButtonOpener extends ActionButton {
// Constructor
constructor(options, aladin) {
let self;
const enableTooltips = () => {
aladin.aladinDiv.removeEventListener('click', enableTooltips);
aladin.aladinDiv.querySelectorAll('.aladin-tooltip')
// for each tooltips reset its visibility and transition delay
.forEach((t) => {
t.style.visibility = ''
t.style.transitionDelay = ''
})
};
super({
...options,
cssStyle: {
@@ -55,8 +52,6 @@ export class CtxMenuActionButtonOpener extends ActionButton {
...options.cssStyle
},
action(e) {
enableTooltips()
let isHidden = self.ctxMenu.isHidden
ContextMenu.hideAll();
@@ -78,15 +73,6 @@ export class CtxMenuActionButtonOpener extends ActionButton {
},
});
}
// the panel is now open and we know the button has a tooltip
// => we close it!
if (self.tooltip && !self.ctxMenu.isHidden) {
self.tooltip.element().style.visibility = 'hidden'
self.tooltip.element().style.transitionDelay = '0ms';
aladin.aladinDiv.addEventListener("click", enableTooltips)
}
}
})
@@ -138,6 +124,7 @@ export class CtxMenuActionButtonOpener extends ActionButton {
// it case it is not given then it will be computed by default
direction: options.openDirection,
},
//cssStyle: options.ctxMenu && options.ctxMenu.cssStyle
});
}
}

View File

@@ -52,8 +52,7 @@ import { ALEvent } from "../../events/ALEvent";
url: projectionIconUrl,
},
classList: ['aladin-projection-control'],
//content: [options.verbosity === 'full' ? ProjectionEnum[projectionName].label : projectionName],
content: projectionName,
content: [options.verbosity === 'full' ? ProjectionEnum[projectionName].label : ''],
tooltip: {content: 'Change the view projection', position: {direction: 'bottom left'}},
cssStyle: {
cursor: 'pointer',
@@ -75,8 +74,8 @@ import { ALEvent } from "../../events/ALEvent";
ALEvent.PROJECTION_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
let projName = aladin.getProjectionName();
//let content = self.options.verbosity === 'full' ? ProjectionEnum[projName].label : projName;
let content = projName;
let content = self.options.verbosity === 'full' ? ProjectionEnum[projName].label : '';
self.update({content})
});
}
@@ -98,8 +97,7 @@ import { ALEvent } from "../../events/ALEvent";
aladin.setProjection(key)
let ctxMenu = self._buildLayout(aladin);
//self.update({ctxMenu, content: self.options.verbosity === 'full' ? proj.label : key});
self.update({ctxMenu});
self.update({ctxMenu, content: self.options.verbosity === 'full' ? proj.label : ''});
}
})
}
@@ -110,11 +108,11 @@ import { ALEvent } from "../../events/ALEvent";
update(options) {
super.update(options);
/*if (options.verbosity) {
if (options.verbosity) {
let ctxMenu = this._buildLayout();
let projName = this.aladin.getProjectionName();
let label = options.verbosity === 'full' ? ProjectionEnum[projName].label : projName;
let label = options.verbosity === 'full' ? ProjectionEnum[projName].label : '';
super.update({ctxMenu, content: label});
}*/
}
}
}

View File

@@ -49,9 +49,9 @@ import { SettingsCtxMenu } from "../CtxMenu/Settings";
},
classList: ['aladin-settings-control'],
tooltip: {
content: 'Some general settings for the<br/>coordinate grid, the reticle or tools to enable',
content: 'Some general settings e.g. background color, reticle, windows to show',
position: {
direction: 'right'
direction: 'top right'
}
},
ctxMenu: new SettingsCtxMenu(aladin, options),

View File

@@ -20,8 +20,6 @@
import { CtxMenuActionButtonOpener } from "./CtxMenuOpener";
import shareIconUrl from '../../../../assets/icons/share.svg';
import cameraIconUrl from '../../../../assets/icons/camera.svg';
import linkIconUrl from '../../../../assets/icons/link.svg';
import jupyterIconUrl from '../../../../assets/icons/jupyter.svg';
/******************************************************************************
* Aladin Lite project
@@ -47,16 +45,11 @@ import jupyterIconUrl from '../../../../assets/icons/jupyter.svg';
let layout = [
{
label: {
content: 'Get view URL',
icon: {
monochrome: true,
url: linkIconUrl,
size: 'small',
},
content: 'Save the view',
tooltip: {
content: 'View URL will be saved into your clipboard',
position: {
direction: 'right'
direction: 'bottom'
}
}
},
@@ -85,22 +78,32 @@ import jupyterIconUrl from '../../../../assets/icons/jupyter.svg';
window.open(hips2fitsUrl, '_blank');
}
},
{
label: 'Export to notebook',
disabled: true,
},
{
label: {
content: 'Export to notebook',
icon: {
url: jupyterIconUrl,
size: 'medium',
},
content: 'Save the WCS',
tooltip: {
content: '<i><font color="#ff0000">Not implemented</font></i><br/>Launch a notebook with <a href="https://github.com/cds-astro/ipyaladin" target="_blank"><font color="#fff">ipyaladin</font></a> inside.',
hoverable: true,
content: 'World Coordinate System of the view',
position: {
direction: 'right'
}
}
},
disabled: true,
action(o) {
let wcs = aladin.getViewWCS()
navigator.clipboard.writeText(JSON.stringify(wcs));
if (aladin.statusBar) {
aladin.statusBar.appendMessage({
message: 'WCS saved into your clipboard!',
duration: 2000,
type: 'info'
})
}
}
},
{
label: {
@@ -110,7 +113,7 @@ import jupyterIconUrl from '../../../../assets/icons/jupyter.svg';
url: cameraIconUrl,
size: 'small',
},
content: 'Take a snapshot'
content: 'Export as image file'
},
action(o) {
aladin.exportAsPNG()

View File

@@ -32,6 +32,7 @@ import { CatalogQueryBox } from "../Box/CatalogQueryBox.js";
import { Layout } from "../Layout.js";
import { ContextMenu } from "../Widgets/ContextMenu.js";
import { ActionButton } from "../Widgets/ActionButton.js";
import { AladinUtils } from "../../AladinUtils.js";
import A from "../../A.js";
import { Utils } from "../../../js/Utils";
import { View } from "../../View.js";
@@ -41,12 +42,12 @@ import searchIconUrl from '../../../../assets/icons/search.svg';
import showIconUrl from '../../../../assets/icons/show.svg';
import hideIconUrl from '../../../../assets/icons/hide.svg';
import removeIconUrl from '../../../../assets/icons/remove.svg';
import settingsIconUrl from '../../../../assets/icons/settings.svg';
import editIconUrl from '../../../../assets/icons/edit.svg';
import { ImageFITS } from "../../ImageFITS.js";
import { ImageLayer } from "../../ImageLayer.js";
import searchIconImg from '../../../../assets/icons/search.svg';
import { TogglerActionButton } from "../Button/Toggler.js";
import { Icon } from "../Widgets/Icon.js";
import { ImageSurvey } from "../../ImageSurvey.js";
export class OverlayStack extends ContextMenu {
static previewImagesUrl = {
@@ -292,18 +293,17 @@ export class OverlayStack extends ContextMenu {
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 [ra, dec] = self.aladin.pix2world(c.x, c.y);
let radius = self.aladin.angularDist(c.x, c.y, c.x + c.r, c.y);
if (ra && dec && radius) {
let moc = A.MOCFromCircle(
{ra, dec, radius},
{name: 'cone', lineWidth: 3.0},
);
self.aladin.addMOC(moc)
} catch {
console.error('Circle out of projection. Selection canceled')
} else {
alert('The circle selection might be invalid. ra: ' + ra + 'deg, dec: ' + dec + 'deg, radius: ' + radius + 'deg')
}
})
}
@@ -321,10 +321,10 @@ export class OverlayStack extends ContextMenu {
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 [ra1, dec1] = self.aladin.pix2world(r.x, r.y);
let [ra2, dec2] = self.aladin.pix2world(r.x + r.w, r.y);
let [ra3, dec3] = self.aladin.pix2world(r.x + r.w, r.y + r.h);
let [ra4, dec4] = self.aladin.pix2world(r.x, r.y + r.h);
let moc = A.MOCFromPolygon(
{
@@ -356,7 +356,7 @@ export class OverlayStack extends ContextMenu {
let ra = []
let dec = []
for (const v of p.vertices) {
let [lon, lat] = self.aladin.pix2world(v.x, v.y, 'j2000');
let [lon, lat] = self.aladin.pix2world(v.x, v.y);
ra.push(lon)
dec.push(lat)
}
@@ -528,19 +528,15 @@ export class OverlayStack extends ContextMenu {
return;
}*/
const defaultLayers = Object.entries(ImageSurvey.cache).sort(function (e1, e2) {
let a = e1[1]
let b = e2[1]
const defaultLayers = ImageLayer.LAYERS.sort(function (a, b) {
if (!a.order) {
return a.name > b.name ? 1 : -1;
}
return a.maxOrder && a.maxOrder > b.maxOrder ? 1 : -1;
});
for(const layer of layers) {
let backgroundUrl = layer.url + '/preview.jpg';
let backgroundUrl = layer.properties.url + '/preview.jpg';
let cssStyle = {
height: 'fit-content',
};
@@ -590,17 +586,18 @@ export class OverlayStack extends ContextMenu {
});
let editBtn = ActionButton.createSmallSizedIconBtn({
icon: {url: settingsIconUrl, monochrome: true},
icon: {url: editIconUrl, monochrome: true},
cssStyle: {
visibility: Utils.hasTouchScreen() ? 'visible' : 'hidden',
},
tooltip: {content: 'Settings', position: {direction: 'bottom'}},
tooltip: {content: 'Edit', position: {direction: 'bottom'}},
action: (e) => {
e.stopPropagation();
e.preventDefault();
self._hide();
console.log("kjkj")
//self.aladin.selectLayer(layer.layer);
//self.attach()
@@ -621,35 +618,35 @@ export class OverlayStack extends ContextMenu {
tooltip: {content: 'Add coverage', position: {direction: 'bottom'}},
toggled: (() => {
let overlays = self.aladin.getOverlays();
let found = overlays.find((o) => o.type === "moc" && o.name === layer.name);
let found = overlays.find((o) => o.type === "moc" && o.name === layer.properties.obsTitle);
return found !== undefined;
})(),
actionOn: (e) => {
let moc = A.MOCFromURL(layer.url + '/Moc.fits', {lineWidth: 3, name: layer.name});
let moc = A.MOCFromURL(layer.properties.url + '/Moc.fits', {lineWidth: 3, name: layer.properties.obsTitle});
self.aladin.addMOC(moc);
self.mocHiPSUrls[layer.url] = moc;
self.mocHiPSUrls[layer.properties.url] = moc;
loadMOCBtn.update({tooltip: {content: 'Remove coverage', position: {direction: 'bottom'}}})
if (self.aladin.statusBar) {
self.aladin.statusBar.appendMessage({
message: 'Coverage of ' + layer.name + ' loaded',
message: 'Coverage of ' + layer.properties.obsTitle + ' loaded',
duration: 2000,
type: 'info'
})
}
},
actionOff: (e) => {
let moc = self.mocHiPSUrls[layer.url];
let moc = self.mocHiPSUrls[layer.properties.url];
self.aladin.removeLayer(moc)
delete self.mocHiPSUrls[layer.url];
delete self.mocHiPSUrls[layer.properties.url];
loadMOCBtn.update({tooltip: {content: 'Add coverage', position: {direction: 'bottom'}}})
if (self.aladin.statusBar) {
self.aladin.statusBar.appendMessage({
message: 'Coverage of ' + layer.name + ' removed',
message: 'Coverage of ' + layer.properties.obsTitle + ' removed',
duration: 2000,
type: 'info'
})
@@ -668,16 +665,16 @@ 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>',
'<div class="' + layerClassName + '" style="background-color: rgba(0, 0, 0, 0.6); padding: 3px; border-radius: 3px; word-break: break-word;' + (selectedLayer === layer.layer ? 'border: 1px solid white;' : '') + '">' + (layer.name) + '</div>',
Layout.horizontal({layout: btns})
],
/*cssStyle: {
cssStyle: {
display: 'flex',
alignItems: 'center',
listStyle: 'none',
justifyContent: 'space-between',
width: '100%',
}*/
}
});
let l = {
@@ -700,7 +697,7 @@ export class OverlayStack extends ContextMenu {
l.subMenu = [];
for(const [id, ll] of defaultLayers) {
for(let ll of defaultLayers) {
backgroundUrl = OverlayStack.previewImagesUrl[ll.name];
if (!backgroundUrl) {
backgroundUrl = ll.url + '/preview.jpg'
@@ -718,10 +715,34 @@ export class OverlayStack extends ContextMenu {
l.subMenu.push({
//selected: layer.name === aladin.getBaseImageLayer().name,
label: '<div style="background-color: rgba(0, 0, 0, 0.6); line-height: 1rem; padding: 3px; border-radius: 3px">' + ll.name + '</div>',
label: '<div style="background-color: rgba(0, 0, 0, 0.6); padding: 3px; border-radius: 3px">' + ll.name + '</div>',
cssStyle,
action(e) {
self.aladin.setOverlayImageLayer(id, layer.layer);
let cfg = ImageLayer.LAYERS.find((l) => l.name === ll.name);
let newLayer;
// Max order is specific for surveys
if (cfg.subtype === "fits") {
// FITS
newLayer = self.aladin.createImageFITS(
cfg.url,
cfg.name,
cfg.options,
);
} else {
// HiPS
newLayer = self.aladin.createImageSurvey(
cfg.id,
cfg.name,
cfg.url,
undefined,
cfg.maxOrder,
cfg.options
);
}
self.aladin.setOverlayImageLayer(newLayer, layer.layer);
//self._hide();
},
hover(e, item) {
item.style.filter = 'brightness(1.5)';
@@ -785,11 +806,11 @@ export class OverlayStack extends ContextMenu {
return;
}
if (!layer.creatorDid) {
if (!layer.properties || !layer.properties.creatorDid) {
return;
}
const creatorDid = layer.creatorDid;
const creatorDid = layer.properties.creatorDid;
for (const key in Stack.previewImagesUrl) {
if (creatorDid.includes(key)) {
@@ -797,7 +818,7 @@ export class OverlayStack extends ContextMenu {
}
}
// if not found
return layer.url + '/preview.jpg'
return layer.properties.url + '/preview.jpg'
}
_addOverlayIcon(overlay) {

View File

@@ -200,7 +200,7 @@ export class SettingsCtxMenu extends ContextMenu {
},
},
{
label: 'Tools',
label: 'Features',
subMenu: [
{
label: 'Stack',
@@ -291,6 +291,10 @@ export class SettingsCtxMenu extends ContextMenu {
super.show({
position: this.position,
cssStyle: {
backgroundColor: 'black',
maxWidth: '17rem',
}
})
}
}

View File

@@ -82,11 +82,9 @@ 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);
el.addClass('aladin-fov');
el.addClass('aladin-dark-theme')
super(el)

View File

@@ -1,78 +0,0 @@
// Copyright 2013 - UDS/CNRS
// The Aladin Lite program is distributed under the terms
// of the GNU General Public License version 3.
//
// This file is part of Aladin Lite.
//
// Aladin Lite is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Aladin Lite is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available in COPYING file
// along with Aladin Lite.
//
/******************************************************************************
* Aladin Lite project
*
* File Location.js
*
* Author: Thomas Boch[CDS]
*
*****************************************************************************/
import { CooFrameEnum } from "../../CooFrameEnum";
import { ALEvent } from "../../events/ALEvent.js";
import { Input } from "./../Widgets/Input.js";
export class CooFrame extends Input {
// constructor
constructor(aladin, options) {
let self;
let cooFrame = CooFrameEnum.fromString(aladin.options.cooFrame, CooFrameEnum.J2000);
super({
name: 'cooFrame',
type: 'select',
value: cooFrame.label,
options: [CooFrameEnum.J2000.label, CooFrameEnum.J2000d.label, CooFrameEnum.GAL.label],
change(e) {
aladin.setFrame(e.target.value)
},
classList: ['aladin-cooFrame'],
tooltip: {
content: "Change the frame",
position: {
direction: 'bottom'
}
},
...options
})
self = this;
this._addEventListeners(aladin);
}
_addEventListeners(aladin) {
let self = this;
ALEvent.FRAME_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
let frame = e.detail.cooFrame;
self.update({
value: frame.label
}, aladin);
});
}
};

View File

@@ -88,7 +88,7 @@ export class Layout extends DOMElement {
}
if (options.classList) {
this.addClass(options.classList)
options.classList.forEach((className) => this.addClass(className))
}
}

View File

@@ -61,7 +61,7 @@ export class Location extends DOMElement {
tooltip: {
global: true,
aladin,
content: 'Edit for typing an object name/position'
content: 'Search for an object name/position'
},
placeholder: "Search for an object...",
autocomplete: 'off',
@@ -109,29 +109,27 @@ export class Location extends DOMElement {
}
});
let copyBtn = new ActionButton({
icon: {
monochrome: true,
size: 'small',
url: copyIconUrl,
},
tooltip: {content: 'Copy to clipboard!', position: {direction: 'bottom'}},
action(e) {
self.copyCoordinatesToClipboard()
},
cssStyle: {
height: '1.4rem',
width: '1.4rem',
paddingRight: '0.2rem',
borderRadius: "5px 0px 0px 5px",
borderRight: 'none',
}
})
copyBtn.element().style.marginRight = 0;
let el = Layout.horizontal({
layout: [
copyBtn,
new ActionButton({
icon: {
monochrome: true,
size: 'small',
url: copyIconUrl,
},
//tooltip: {content: 'Copy to clipboard!', position: {direction: 'bottom'}},
action(e) {
self.copyCoordinatesToClipboard()
},
cssStyle: {
height: '1.4rem',
width: '1.4rem',
marginRight: 0,
paddingRight: '0.2rem',
borderRadius: "5px 0px 0px 5px",
borderRight: 'none',
}
}),
field
]
})
@@ -197,7 +195,7 @@ export class Location extends DOMElement {
}, aladin)
};
static prec = 6;
static prec = 7;
update(options, aladin) {
let self = this;
@@ -253,7 +251,7 @@ export class Location extends DOMElement {
})
.finally(() => {
console.info('Copying text command was ' + msg);
})
})
}
};

View File

@@ -147,15 +147,15 @@ export class ActionButton extends DOMElement {
}
}
if (this.options.cssStyle) {
this.setCss(this.options.cssStyle);
}
// trigger el added
if (this.options.tooltip) {
Tooltip.add(this.options.tooltip, this)
}
if (this.options.cssStyle) {
this.setCss(this.options.cssStyle);
}
if (this.options.position) {
this.setPosition(this.options.position)
}

View File

@@ -47,7 +47,7 @@ export class Box extends DOMElement {
constructor(options, target, position = "beforeend") {
let el = document.createElement("div");
el.classList.add('aladin-box');
//el.style.display = "initial";
el.style.display = "initial";
super(el, options);
this._show();
@@ -58,6 +58,8 @@ export class Box extends DOMElement {
}
_show(options) {
//this.el.parentNode.appendChild(this.el);
this.options = {
...this.options,
...options
@@ -86,7 +88,7 @@ export class Box extends DOMElement {
size: "small",
monochrome: true,
},
tooltip: {content: 'Drag the window to move it', position: {direction: 'top'}},
tooltip: {content: 'Drag the window to move it', position: {direction: 'right'}},
cssStyle: {
cursor: 'move',
},

View File

@@ -38,8 +38,6 @@ import { Layout } from '../Layout.js';
import { Icon } from './Icon.js';
import uploadIconUrl from '../../../../assets/icons/upload.svg';
import copyIconUrl from '../../../../assets/icons/copy.svg';
import nextIconSvg from '../../../../assets/icons/next.svg';
export class ContextMenu extends DOMElement {
@@ -51,8 +49,6 @@ export class ContextMenu extends DOMElement {
super(el, options);
this.addClass('aladin-dark-theme')
this.aladin = aladin;
this.cssStyleDefault = el.style;
@@ -99,10 +95,6 @@ export class ContextMenu extends DOMElement {
if (opt.label == 'Copy position') {
try {
// erase the label
item.innerHTML = '';
// compute the position string
const xymouse = Utils.relMouseCoords(e);
const pos = this.aladin.pix2world(xymouse.x, xymouse.y);
const coo = new Coo(pos[0], pos[1], 6);
@@ -114,18 +106,7 @@ export class ContextMenu extends DOMElement {
} else {
posStr = coo.format('d/');
}
// construct the new item
Layout.horizontal([
new Icon({
monochrome: true,
url: copyIconUrl,
size: 'small',
tooltip: {content: 'Copy the position!', position: {direction: 'bottom'}}
}),
posStr
]).attachTo(item)
item.innerHTML = '<span>' + posStr + '</span>';
} catch (e) {
item.innerHTML = '<span>Out of projection</span>';
}
@@ -231,7 +212,7 @@ export class ContextMenu extends DOMElement {
.style.display = 'block';
if (opt.action && (!opt.disabled || opt.disabled === false)) {
opt.action(e, self);
opt.action(e);
}
});
} else if (opt.action) {
@@ -244,7 +225,7 @@ export class ContextMenu extends DOMElement {
self._hide();
}
opt.action(e, self);
opt.action(e);
}
}
});
@@ -317,7 +298,7 @@ export class ContextMenu extends DOMElement {
let r = item.getBoundingClientRect();
if (r.x - aladinRect.left <= aladinRect.right - (r.x + r.width)) {
if (r.x - aladinRect.left <= offsetWidth / 2.0) {
leftDir -= 1;
} else {
leftDir += 1;

View File

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

View File

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

View File

@@ -104,13 +104,10 @@ export class Tabs extends DOMElement {
contentTabEl.appendChild(contentTabOptionEl)
}
let el = new Layout({
layout: [
new Layout({layout: tabsLayout, orientation: 'horizontal'}),
contentTabEl
],
classList: "aladin-table"
});
let el = new Layout([
new Layout({layout: tabsLayout, orientation: 'horizontal'}),
contentTabEl
]);
super(el, options);
this._show();

View File

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

View File

@@ -69,14 +69,8 @@ export class Tooltip extends DOMElement {
}
options.position.anchor = target;
if (!options.delayShowUpTime) {
options.delayShowUpTime = 500;
}
super(wrapperEl, options)
this.element().classList.add('aladin-dark-theme')
this._show();
}
@@ -127,14 +121,6 @@ export class Tooltip extends DOMElement {
let tooltipEl = this.el.querySelector('.aladin-tooltip');
tooltipEl.innerHTML = '';
if (this.options.hoverable) {
this.element().style.pointerEvents = "auto";
}
if (this.options.delayShowUpTime) {
this.element().style.transitionDelay = this.options.delayShowUpTime;
}
if (this.options.content) {
let content = this.options.content;
if (content instanceof DOMElement) {
@@ -148,6 +134,8 @@ export class Tooltip extends DOMElement {
}
}
super._show();
if (this.options.position) {
this.setPosition(this.options.position)
}
@@ -155,8 +143,6 @@ export class Tooltip extends DOMElement {
if (this.options.cssStyle) {
this.setCss(this.options.cssStyle)
}
super._show();
}
setCss(options) {

View File

@@ -80,7 +80,7 @@ export class DOMElement {
setCss(options) {
// CSS style elements
if (options) {
let el = this.el;
let el = this.element();
for (const property in options) {
el.style[property] = options[property];
}
@@ -203,12 +203,10 @@ export class DOMElement {
} else if (options && options.nextTo) {
let dir = options.direction;
let nextTo = options.nextTo;
let aDivRect = aladinDiv.getBoundingClientRect();
const offViewX = aDivRect.x;
const offViewY = aDivRect.y;
if (!dir) {
// determine the direction with respect to the element given
let elX = options.nextTo.el.getBoundingClientRect().left + options.nextTo.el.getBoundingClientRect().width * 0.5 - offViewX;
let elX = options.nextTo.el.getBoundingClientRect().left + options.nextTo.el.getBoundingClientRect().width * 0.5;
dir = (elX < innerWidth / 2) ? 'right' : 'left';
}
@@ -217,6 +215,10 @@ export class DOMElement {
}
let rect = nextTo.getBoundingClientRect();
let aDivRect = aladinDiv.getBoundingClientRect();
const offViewX = aDivRect.x;
const offViewY = aDivRect.y;
switch (dir) {
case 'left':
@@ -292,13 +294,18 @@ export class DOMElement {
}
_show() {
this.el.style.display = ""
delete this.el.style.display;
//this.el.style.display = 'block';
this.isHidden = false;
}
_hide() {
this.isHidden = true;
this.el.style.display = 'none';
if (this.options && this.options.onHidden) {
this.options.onHidden();
}
}
attachTo(target, position = 'beforeend') {
@@ -317,10 +324,6 @@ export class DOMElement {
this.options = {...this.options, ...options};
}
if (this.isHidden) {
return;
}
this._show();
}
};

Some files were not shown because too many files have changed in this diff Show More