mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-04-29 20:29:01 -07:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3affe8c062 | ||
|
|
ce9644d83f | ||
|
|
36b0f9392c | ||
|
|
dda9f07cb4 |
3
.github/workflows/api_doc.yml
vendored
3
.github/workflows/api_doc.yml
vendored
@@ -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:
|
||||
|
||||
3
.github/workflows/npm-publish.yml
vendored
3
.github/workflows/npm-publish.yml
vendored
@@ -6,9 +6,6 @@ name: Publish to NPM
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -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
|
||||
|
||||
43
README.md
43
README.md
@@ -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/).
|
||||
|
||||
[](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml)
|
||||
[](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
|
||||
```
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ A.init.then(() => {
|
||||
console.log(objs, "are selected");
|
||||
})
|
||||
|
||||
aladin.select();
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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")
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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(),
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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(),
|
||||
));
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
210
src/js/A.js
210
src/js/A.js
@@ -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.
|
||||
|
||||
446
src/js/Aladin.js
446
src/js/Aladin.js
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
275
src/js/ColorMap.js
Normal 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;
|
||||
})();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
218
src/js/ImageLayer.js
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
})();
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -90,7 +90,6 @@ export let Popup = (function() {
|
||||
}
|
||||
source.popup = this;
|
||||
this.source = source;
|
||||
|
||||
this.setPosition(source.x, source.y);
|
||||
};
|
||||
|
||||
|
||||
@@ -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-Aï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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
159
src/js/View.js
159
src/js/View.js
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)}})
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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});
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ export class Layout extends DOMElement {
|
||||
}
|
||||
|
||||
if (options.classList) {
|
||||
this.addClass(options.classList)
|
||||
options.classList.forEach((className) => this.addClass(className))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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();
|
||||
|
||||
182
src/js/gui/Widgets/Toolbar.js
Normal file
182
src/js/gui/Widgets/Toolbar.js
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user