mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-12 15:49:18 -08:00
rename ImageHiPS in HiPS, factorize Image/HiPS, zoom for trackpad refined
This commit is contained in:
committed by
Matthieu Baumann
parent
46cf0c2939
commit
180b63db37
@@ -9,7 +9,7 @@
|
|||||||
let aladin;
|
let aladin;
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
aladin = A.aladin('#aladin-lite-div', { fov:0.15, target: 'Arp 240', showReticle: false, fullScreen: true });
|
aladin = A.aladin('#aladin-lite-div', { fov:0.15, target: 'Arp 240', showReticle: false, fullScreen: true });
|
||||||
aladin.setBaseImageLayer(aladin.newImageSurvey('P/SDSS9/g', {colormap: "rainbow", stretch: "Linear"}));
|
aladin.setBaseImageLayer(aladin.newImageSurvey('P/SDSS9/g', {colormap: "eosb", stretch: "linear"}));
|
||||||
|
|
||||||
var simbad = A.catalog({name: 'Simbad', sourceSize: 16, color: '#4050F0'});
|
var simbad = A.catalog({name: 'Simbad', sourceSize: 16, color: '#4050F0'});
|
||||||
aladin.addCatalog(simbad);
|
aladin.addCatalog(simbad);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
let aladin;
|
let aladin;
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
aladin = A.aladin('#aladin-lite-div', {survey: ["P/PanSTARRS/DR1/color-i-r-g"], showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: 1000, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGrid: true, showCooGridControl: false});
|
aladin = A.aladin('#aladin-lite-div', {survey: "P/PanSTARRS/DR1/color-z-zg-g", showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: 1000, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGrid: true, showCooGridControl: false});
|
||||||
|
|
||||||
const chft = aladin.createImageSurvey('CFHT', "CFHT deep view of NGC7331 and Stephan's quintet u+g+r", "https://cds.unistra.fr/~derriere/PR_HiPS/2022_Duc/", null, null, {imgFormat: 'png'});
|
const chft = aladin.createImageSurvey('CFHT', "CFHT deep view of NGC7331 and Stephan's quintet u+g+r", "https://cds.unistra.fr/~derriere/PR_HiPS/2022_Duc/", null, null, {imgFormat: 'png'});
|
||||||
const nircamJWST = aladin.createImageSurvey('Nircam', "Stephans Quintet NIRCam+MIRI", "http://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam+MIRI/", null, null, {imgFormat: 'png', colormap: "viridis"});
|
const nircamJWST = aladin.createImageSurvey('Nircam', "Stephans Quintet NIRCam+MIRI", "http://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam+MIRI/", null, null, {imgFormat: 'png', colormap: "viridis"});
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ A.init.then(() => {
|
|||||||
hscGreenSurvey.setColormap("green", { stretch: "asinh" });
|
hscGreenSurvey.setColormap("green", { stretch: "asinh" });
|
||||||
hscGreenSurvey.setCuts(-0.2186, 5.30322);
|
hscGreenSurvey.setCuts(-0.2186, 5.30322);
|
||||||
|
|
||||||
const HSCRedSurvey = aladin.newImageSurvey('CDS/P/HSC/DR2/deep/r', {imgFormat: 'fits', colormap: "red", minCut: 0.34228, maxCut: 2.75785, additive: true, stretch: "asinh"});
|
const HSCRedSurvey = aladin.newImageSurvey('P/HSC/DR2/deep/r', {imgFormat: 'fits', colormap: "red", minCut: 0.34228, maxCut: 2.75785, additive: true, stretch: "asinh"});
|
||||||
const HSCBlueSurvey = aladin.newImageSurvey('CDS/P/HSC/DR2/deep/z', {imgFormat: 'fits', colormap: "blue", minCut: -0.01218, maxCut: 2.27397, additive: true, stretch: "asinh"});
|
const HSCBlueSurvey = aladin.newImageSurvey('P/HSC/DR2/deep/z', {imgFormat: 'fits', colormap: "blue", minCut: -0.01218, maxCut: 2.27397, additive: true, stretch: "asinh"});
|
||||||
|
|
||||||
aladin.setOverlayImageLayer('CDS/P/HSC/DR2/deep/r', 'hsc red layer');
|
aladin.setOverlayImageLayer('P/HSC/DR2/deep/r', 'hsc red layer');
|
||||||
aladin.setOverlayImageLayer('CDS/P/HSC/DR2/deep/z', 'hsc blue layer');
|
aladin.setOverlayImageLayer('P/HSC/DR2/deep/z', 'hsc blue layer');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id="aladin-lite-div" style="width: 1024px; height: 100%;"></div>
|
<div id="aladin-lite-div" style="width: 1024px; height: 256px;"></div>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
var aladin = A.aladin('#aladin-lite-div', {showContextMenu: true, target: '05 37 58 +08 17 35', fov: 12, backgroundColor: 'rgb(120, 0, 0)'});
|
var aladin = A.aladin('#aladin-lite-div', {showContextMenu: true, target: '05 37 58 +08 17 35', fov: 12, backgroundColor: 'rgb(120, 0, 0)'});
|
||||||
var cat = A.catalog({sourceSize: 20, onClick: 'showTable'});
|
var cat = A.catalog({sourceSize: 20, onClick: (s) => {console.log("kjk", s)}});
|
||||||
aladin.addCatalog(cat);
|
aladin.addCatalog(cat);
|
||||||
cat.addSources([A.source(83.784490, 9.934156, {name: 'Meissa'}), A.source(88.792939, 7.407064, {name: 'Betelgeuse'}), A.source(81.282764, 6.349703, {name: 'Bellatrix'})]);
|
cat.addSources([A.source(83.784490, 9.934156, {name: 'Meissa'}), A.source(88.792939, 7.407064, {name: 'Betelgeuse'}), A.source(81.282764, 6.349703, {name: 'Bellatrix'})]);
|
||||||
var msg;
|
var msg;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
aladin.removeHiPSFromFavorites('CDS/P/allWISE/color')
|
//aladin.removeHiPSFromFavorites('CDS/P/allWISE/color')
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -44,6 +44,12 @@
|
|||||||
landingSites.addSources([A.marker(-225.71, 47.64, {popupTitle: 'Viking 2', popupDesc: 'Landing date: September 3, 1976 22:37:50'})]);
|
landingSites.addSources([A.marker(-225.71, 47.64, {popupTitle: 'Viking 2', popupDesc: 'Landing date: September 3, 1976 22:37:50'})]);
|
||||||
landingSites.addSources([A.marker(175.472636, -14.5684, {popupTitle: 'Spirit', popupDesc: 'Landing date: January 4, 2004, 04:35 UTC '})]);
|
landingSites.addSources([A.marker(175.472636, -14.5684, {popupTitle: 'Spirit', popupDesc: 'Landing date: January 4, 2004, 04:35 UTC '})]);
|
||||||
landingSites.addSources([A.marker(137.4417, -4.5895, {popupTitle: 'Curiosity', popupDesc: 'Landing date: August 6, 2012, 05:17 UTC '})])
|
landingSites.addSources([A.marker(137.4417, -4.5895, {popupTitle: 'Curiosity', popupDesc: 'Landing date: August 6, 2012, 05:17 UTC '})])
|
||||||
|
|
||||||
|
var cat = A.catalog({name: "Temp", sourceSize: 18, onClick: 'showPopup'});
|
||||||
|
aladin.addCatalog(cat);
|
||||||
|
cat.addSources(A.source(105.69239256, -8.45235969, {a: 1, b: 2, c:3}));
|
||||||
|
cat.addSources(A.source(105.70779763, -8.31350997, {a: 4, b: 5, c:6}));
|
||||||
|
cat.addSources(A.source(105.74242906, -8.34776709, {a: 7, b: 8, c:9}));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -16,10 +16,6 @@
|
|||||||
var overlay = A.graphicOverlay({lineWidth: 2});
|
var overlay = A.graphicOverlay({lineWidth: 2});
|
||||||
aladin.addOverlay(overlay);
|
aladin.addOverlay(overlay);
|
||||||
overlay.add(A.polyline([ [2.29452158, 59.14978110], [10.12683778, 56.53733116], [14.1772154, 60.7167403], [21.45396446, 60.23528403], [28.59885697, 63.67010079] ], {color: 'green'}));
|
overlay.add(A.polyline([ [2.29452158, 59.14978110], [10.12683778, 56.53733116], [14.1772154, 60.7167403], [21.45396446, 60.23528403], [28.59885697, 63.67010079] ], {color: 'green'}));
|
||||||
|
|
||||||
aladin.select('rect', (s) => {
|
|
||||||
console.log(s)
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -25,7 +25,10 @@
|
|||||||
|
|
||||||
aladin.setImageLayer(survey2);
|
aladin.setImageLayer(survey2);
|
||||||
|
|
||||||
aladin.removeHiPSFromFavorites(survey3);
|
/*setTimeout(() => {
|
||||||
|
aladin.removeHiPSFromFavorites(survey3)
|
||||||
|
}, 10000);*/
|
||||||
|
|
||||||
|
|
||||||
aladin.addColormap('mycmap', ["lightblue", "red", "violet", "lightgreen"])
|
aladin.addColormap('mycmap', ["lightblue", "red", "violet", "lightgreen"])
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
<script type="text/javascript" src="./../dist/aladin.umd.cjs" charset="utf-8"></script>
|
<script type="text/javascript" src="./../dist/aladin.umd.cjs" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
<!-- Aladin Lite V3 JS code -->
|
<!-- Aladin Lite V3 JS code -->
|
||||||
<!-- Creation of Aladin Lite instance with initial parameters -->
|
<!-- Creation of Aladin Lite instance with initial parameters -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@@ -28,7 +27,7 @@
|
|||||||
|
|
||||||
let aladin;
|
let aladin;
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
aladin = A.aladin('#aladin-lite-div', {survey: "https://alasky.cds.unistra.fr/AllWISE/RGB-W4-W2-W1/", fov:1.5, target: "14 03 12.583 +54 20 55.5", });
|
aladin = A.aladin('#aladin-lite-div', {fov:1.5, target: "14 03 12.583 +54 20 55.5", });
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ use crate::{
|
|||||||
tile_fetcher::TileFetcherQueue,
|
tile_fetcher::TileFetcherQueue,
|
||||||
time::DeltaTime,
|
time::DeltaTime,
|
||||||
};
|
};
|
||||||
|
use al_core::log::console_log;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use wcs::WCS;
|
use wcs::WCS;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
@@ -53,7 +55,7 @@ pub struct App {
|
|||||||
shaders: ShaderManager,
|
shaders: ShaderManager,
|
||||||
pub camera: CameraViewPort,
|
pub camera: CameraViewPort,
|
||||||
|
|
||||||
downloader: Downloader,
|
downloader: Rc<RefCell<Downloader>>,
|
||||||
tile_fetcher: TileFetcherQueue,
|
tile_fetcher: TileFetcherQueue,
|
||||||
layers: Layers,
|
layers: Layers,
|
||||||
|
|
||||||
@@ -146,7 +148,7 @@ impl App {
|
|||||||
//gl.enable(WebGl2RenderingContext::CULL_FACE);
|
//gl.enable(WebGl2RenderingContext::CULL_FACE);
|
||||||
|
|
||||||
// The tile buffer responsible for the tile requests
|
// The tile buffer responsible for the tile requests
|
||||||
let downloader = Downloader::new();
|
let downloader = Rc::new(RefCell::new(Downloader::new()));
|
||||||
|
|
||||||
let camera = CameraViewPort::new(&gl, CooSystem::ICRS, &projection);
|
let camera = CameraViewPort::new(&gl, CooSystem::ICRS, &projection);
|
||||||
let screen_size = &camera.get_screen_size();
|
let screen_size = &camera.get_screen_size();
|
||||||
@@ -266,6 +268,7 @@ impl App {
|
|||||||
if self.camera.get_texture_depth() == 0
|
if self.camera.get_texture_depth() == 0
|
||||||
&& self
|
&& self
|
||||||
.downloader
|
.downloader
|
||||||
|
.borrow()
|
||||||
.is_queried(&query::Allsky::new(survey.get_config()).id)
|
.is_queried(&query::Allsky::new(survey.get_config()).id)
|
||||||
{
|
{
|
||||||
// do not ask for tiles if we download the allsky
|
// do not ask for tiles if we download the allsky
|
||||||
@@ -285,10 +288,12 @@ impl App {
|
|||||||
if let Some(tiles_iter) = survey.look_for_new_tiles(&mut self.camera, &self.projection)
|
if let Some(tiles_iter) = survey.look_for_new_tiles(&mut self.camera, &self.projection)
|
||||||
{
|
{
|
||||||
for tile_cell in tiles_iter.into_iter() {
|
for tile_cell in tiles_iter.into_iter() {
|
||||||
self.tile_fetcher.append(
|
self.tile_fetcher.append(query::Tile::new(
|
||||||
query::Tile::new(&tile_cell, creator_did.clone(), root_url.clone(), format),
|
&tile_cell,
|
||||||
&mut self.downloader,
|
creator_did.clone(),
|
||||||
);
|
root_url.clone(),
|
||||||
|
format,
|
||||||
|
));
|
||||||
|
|
||||||
// check if we are starting aladin lite or not.
|
// check if we are starting aladin lite or not.
|
||||||
// If so we want to retrieve only the tiles in the view and access them
|
// If so we want to retrieve only the tiles in the view and access them
|
||||||
@@ -314,10 +319,12 @@ impl App {
|
|||||||
// Request for ancestor
|
// Request for ancestor
|
||||||
for ancestor in ancestors {
|
for ancestor in ancestors {
|
||||||
if !survey.update_priority_tile(&ancestor) {
|
if !survey.update_priority_tile(&ancestor) {
|
||||||
self.tile_fetcher.append(
|
self.tile_fetcher.append(query::Tile::new(
|
||||||
query::Tile::new(&ancestor, creator_did.clone(), root_url.clone(), format),
|
&ancestor,
|
||||||
&mut self.downloader,
|
creator_did.clone(),
|
||||||
);
|
root_url.clone(),
|
||||||
|
format,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -489,12 +496,6 @@ impl App {
|
|||||||
self.catalog_loaded
|
self.catalog_loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
/*pub(crate) fn is_ready(&self) -> Result<bool, JsValue> {
|
|
||||||
let res = self.layers.is_ready();
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub(crate) fn get_moc(&self, cfg: &al_api::moc::MOC) -> Option<&HEALPixCoverage> {
|
pub(crate) fn get_moc(&self, cfg: &al_api::moc::MOC) -> Option<&HEALPixCoverage> {
|
||||||
self.moc.get_hpx_coverage(cfg)
|
self.moc.get_hpx_coverage(cfg)
|
||||||
}
|
}
|
||||||
@@ -594,7 +595,7 @@ impl App {
|
|||||||
/*let is_there_new_available_tiles = self
|
/*let is_there_new_available_tiles = self
|
||||||
.downloader
|
.downloader
|
||||||
.get_resolved_tiles(/*&available_tiles, */&mut self.surveys);*/
|
.get_resolved_tiles(/*&available_tiles, */&mut self.surveys);*/
|
||||||
let rscs_received = self.downloader.get_received_resources();
|
let rscs_received = self.downloader.borrow_mut().get_received_resources();
|
||||||
|
|
||||||
let _num_tile_handled = 0;
|
let _num_tile_handled = 0;
|
||||||
let _tile_copied = false;
|
let _tile_copied = false;
|
||||||
@@ -621,7 +622,7 @@ impl App {
|
|||||||
//let is_tile_root = tile.cell().depth() == delta_depth;
|
//let is_tile_root = tile.cell().depth() == delta_depth;
|
||||||
//let _depth = tile.cell().depth();
|
//let _depth = tile.cell().depth();
|
||||||
// do not perform tex_sub costly GPU calls while the camera is zooming
|
// do not perform tex_sub costly GPU calls while the camera is zooming
|
||||||
if included_or_near_coverage {
|
if tile.cell().is_root() || included_or_near_coverage {
|
||||||
let is_missing = tile.missing();
|
let is_missing = tile.missing();
|
||||||
/*self.tile_fetcher.notify_tile(
|
/*self.tile_fetcher.notify_tile(
|
||||||
&tile,
|
&tile,
|
||||||
@@ -721,7 +722,6 @@ impl App {
|
|||||||
// The allsky image is missing so we donwload all the tiles contained into
|
// The allsky image is missing so we donwload all the tiles contained into
|
||||||
// the 0's cell
|
// the 0's cell
|
||||||
let cfg = survey.get_config();
|
let cfg = survey.get_config();
|
||||||
let _delta_depth = cfg.delta_depth();
|
|
||||||
for texture_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
for texture_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||||
for cell in texture_cell.get_tile_cells(cfg.delta_depth()) {
|
for cell in texture_cell.get_tile_cells(cfg.delta_depth()) {
|
||||||
let query = query::Tile::new(
|
let query = query::Tile::new(
|
||||||
@@ -730,8 +730,7 @@ impl App {
|
|||||||
cfg.get_root_url().to_string(),
|
cfg.get_root_url().to_string(),
|
||||||
cfg.get_format(),
|
cfg.get_format(),
|
||||||
);
|
);
|
||||||
self.tile_fetcher
|
self.tile_fetcher.append_base_tile(query);
|
||||||
.append_base_tile(query, &mut self.downloader);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -772,27 +771,20 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We fetch when we does not move
|
// Tiles are fetched if:
|
||||||
/*let has_not_moved_recently =
|
let fetch_tiles = self.inertia.is_none() &&
|
||||||
(Time::now() - self.camera.get_time_of_last_move()) > DeltaTime(100.0);
|
// * the user is not zooming
|
||||||
if has_not_moved_recently && self.inertia.is_none() {
|
!self.camera.has_zoomed() &&
|
||||||
// Triggers the fetching of new queued tiles
|
// * no inertia action is in progress
|
||||||
self.tile_fetcher.notify(&mut self.downloader);
|
(
|
||||||
}*/
|
// * the user is not panning the view
|
||||||
|
!self.dragging ||
|
||||||
|
// * or the user is but did not move for at least 100ms
|
||||||
|
(self.dragging && Time::now() - self.camera.get_time_of_last_move() >= DeltaTime(100.0))
|
||||||
|
);
|
||||||
|
|
||||||
// If there is inertia, we do not fetch any new tiles
|
if fetch_tiles {
|
||||||
if self.inertia.is_none() {
|
self.tile_fetcher.notify(self.downloader.clone(), None);
|
||||||
let has_not_moved_recently =
|
|
||||||
(Time::now() - self.camera.get_time_of_last_move()) > DeltaTime(100.0);
|
|
||||||
|
|
||||||
/*let dt = if has_not_moved_recently {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(DeltaTime::from_millis(700.0))
|
|
||||||
};*/
|
|
||||||
if has_not_moved_recently {
|
|
||||||
self.tile_fetcher.notify(&mut self.downloader, None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,21 +803,6 @@ impl App {
|
|||||||
// - there is at least one tile in its blending phase
|
// - there is at least one tile in its blending phase
|
||||||
let blending_anim_occuring =
|
let blending_anim_occuring =
|
||||||
(Time::now() - self.time_start_blending) < BLENDING_ANIM_DURATION;
|
(Time::now() - self.time_start_blending) < BLENDING_ANIM_DURATION;
|
||||||
/*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 {
|
|
||||||
// Catalogues update
|
|
||||||
/*if let Some(view) = self.layers.get_view() {
|
|
||||||
self.manager.update(&self.camera, view);
|
|
||||||
}*/
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Check for async retrieval
|
// Check for async retrieval
|
||||||
if let Ok(img) = self.img_recv.try_recv() {
|
if let Ok(img) = self.img_recv.try_recv() {
|
||||||
@@ -1012,7 +989,7 @@ impl App {
|
|||||||
self.layers
|
self.layers
|
||||||
.add_image_hips(&self.gl, hips_cfg, &mut self.camera, &self.projection)?;
|
.add_image_hips(&self.gl, hips_cfg, &mut self.camera, &self.projection)?;
|
||||||
self.tile_fetcher
|
self.tile_fetcher
|
||||||
.launch_starting_hips_requests(hips, &mut self.downloader);
|
.launch_starting_hips_requests(hips, self.downloader.clone());
|
||||||
|
|
||||||
// Once its added, request the tiles in the view (unless the viewer is at depth 0)
|
// Once its added, request the tiles in the view (unless the viewer is at depth 0)
|
||||||
self.request_for_new_tiles = true;
|
self.request_for_new_tiles = true;
|
||||||
@@ -1318,7 +1295,7 @@ impl App {
|
|||||||
|
|
||||||
// Relaunch the base tiles for the survey to be ready with the new url
|
// Relaunch the base tiles for the survey to be ready with the new url
|
||||||
self.tile_fetcher
|
self.tile_fetcher
|
||||||
.launch_starting_hips_requests(hips, &mut self.downloader);
|
.launch_starting_hips_requests(hips, self.downloader.clone());
|
||||||
|
|
||||||
// Once its added, request the tiles in the view (unless the viewer is at depth 0)
|
// Once its added, request the tiles in the view (unless the viewer is at depth 0)
|
||||||
self.request_for_new_tiles = true;
|
self.request_for_new_tiles = true;
|
||||||
@@ -1507,7 +1484,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn press_left_button_mouse(&mut self, _sx: f32, _sy: f32) {
|
pub(crate) fn press_left_button_mouse(&mut self) {
|
||||||
self.dist_dragging = 0.0;
|
self.dist_dragging = 0.0;
|
||||||
self.time_start_dragging = Time::now();
|
self.time_start_dragging = Time::now();
|
||||||
self.dragging = true;
|
self.dragging = true;
|
||||||
@@ -1517,11 +1494,10 @@ impl App {
|
|||||||
self.out_of_fov = false;
|
self.out_of_fov = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn release_left_button_mouse(&mut self, sx: f32, sy: f32) {
|
pub(crate) fn release_left_button_mouse(&mut self) {
|
||||||
self.request_for_new_tiles = true;
|
self.request_for_new_tiles = true;
|
||||||
|
|
||||||
self.dragging = false;
|
self.dragging = false;
|
||||||
let _cur_mouse_pos = [sx, sy];
|
|
||||||
|
|
||||||
// Check whether the center has moved
|
// Check whether the center has moved
|
||||||
// between the pressing and releasing
|
// between the pressing and releasing
|
||||||
@@ -1632,9 +1608,6 @@ impl App {
|
|||||||
self.prev_cam_position = self.camera.get_center().truncate();
|
self.prev_cam_position = self.camera.get_center().truncate();
|
||||||
self.camera.apply_rotation(&(-axis), d, &self.projection);
|
self.camera.apply_rotation(&(-axis), d, &self.projection);
|
||||||
|
|
||||||
/* 2. Or just set the center to the current position */
|
|
||||||
//self.set_center(&cur_pos.lonlat());
|
|
||||||
|
|
||||||
self.request_for_new_tiles = true;
|
self.request_for_new_tiles = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ use wasm_bindgen::JsCast;
|
|||||||
|
|
||||||
const MAX_DPI_LIMIT: f32 = 3.0;
|
const MAX_DPI_LIMIT: f32 = 3.0;
|
||||||
use crate::math;
|
use crate::math;
|
||||||
use crate::time::Time;
|
use crate::time::{DeltaTime, Time};
|
||||||
use crate::Abort;
|
use crate::Abort;
|
||||||
use crate::ArcDeg;
|
use crate::ArcDeg;
|
||||||
impl CameraViewPort {
|
impl CameraViewPort {
|
||||||
|
|||||||
@@ -61,8 +61,6 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let _ = wasm_bindgen_futures::future_to_promise(fut);
|
let _ = wasm_bindgen_futures::future_to_promise(fut);
|
||||||
|
|
||||||
log!("launch promises");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ use al_core::image::html::HTMLImage;
|
|||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{HtmlImageElement, RequestInit, RequestMode, Response};
|
use web_sys::{RequestInit, RequestMode, Response};
|
||||||
impl From<query::Tile> for TileRequest {
|
impl From<query::Tile> for TileRequest {
|
||||||
// Create a tile request associated to a HiPS
|
// Create a tile request associated to a HiPS
|
||||||
fn from(query: query::Tile) -> Self {
|
fn from(query: query::Tile) -> Self {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ impl HEALPixCell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_root(&self, _delta_depth_to_texture: u8) -> bool {
|
pub fn is_root(&self) -> bool {
|
||||||
self.depth() == 0
|
self.depth() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ impl WebClient {
|
|||||||
/// * If the number of surveys is greater than 4. For the moment, due to the limitations
|
/// * If the number of surveys is greater than 4. For the moment, due to the limitations
|
||||||
/// of WebGL2 texture units on some architectures, the total number of surveys rendered is
|
/// of WebGL2 texture units on some architectures, the total number of surveys rendered is
|
||||||
/// limited to 4.
|
/// limited to 4.
|
||||||
#[wasm_bindgen(js_name = addImageHiPS)]
|
#[wasm_bindgen(js_name = addHiPS)]
|
||||||
pub fn add_image_hips(&mut self, hips: JsValue) -> Result<(), JsValue> {
|
pub fn add_image_hips(&mut self, hips: JsValue) -> Result<(), JsValue> {
|
||||||
// Deserialize the survey objects that compose the survey
|
// Deserialize the survey objects that compose the survey
|
||||||
let hips = serde_wasm_bindgen::from_value(hips)?;
|
let hips = serde_wasm_bindgen::from_value(hips)?;
|
||||||
@@ -404,7 +404,8 @@ impl WebClient {
|
|||||||
let wcs_params: WCSParams = serde_wasm_bindgen::from_value(wcs)?;
|
let wcs_params: WCSParams = serde_wasm_bindgen::from_value(wcs)?;
|
||||||
let wcs = WCS::new(&wcs_params).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
|
let wcs = WCS::new(&wcs_params).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
|
||||||
|
|
||||||
self.app.add_image_from_blob_and_wcs(layer, stream, wcs, cfg)
|
self.app
|
||||||
|
.add_image_from_blob_and_wcs(layer, stream, wcs, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = removeLayer)]
|
#[wasm_bindgen(js_name = removeLayer)]
|
||||||
@@ -773,16 +774,16 @@ impl WebClient {
|
|||||||
///
|
///
|
||||||
/// This is useful for beginning inerting.
|
/// This is useful for beginning inerting.
|
||||||
#[wasm_bindgen(js_name = releaseLeftButtonMouse)]
|
#[wasm_bindgen(js_name = releaseLeftButtonMouse)]
|
||||||
pub fn release_left_button_mouse(&mut self, sx: f32, sy: f32) -> Result<(), JsValue> {
|
pub fn release_left_button_mouse(&mut self) -> Result<(), JsValue> {
|
||||||
self.app.release_left_button_mouse(sx, sy);
|
self.app.release_left_button_mouse();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signal the backend when the left mouse button has been pressed.
|
/// Signal the backend when the left mouse button has been pressed.
|
||||||
#[wasm_bindgen(js_name = pressLeftMouseButton)]
|
#[wasm_bindgen(js_name = pressLeftMouseButton)]
|
||||||
pub fn press_left_button_mouse(&mut self, sx: f32, sy: f32) -> Result<(), JsValue> {
|
pub fn press_left_button_mouse(&mut self) -> Result<(), JsValue> {
|
||||||
self.app.press_left_button_mouse(sx, sy);
|
self.app.press_left_button_mouse();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,10 @@ fn is_too_large(cell: &HEALPixCell, camera: &CameraViewPort, projection: &Projec
|
|||||||
|
|
||||||
fn num_subdivision(cell: &HEALPixCell, camera: &CameraViewPort, projection: &ProjectionType) -> u8 {
|
fn num_subdivision(cell: &HEALPixCell, camera: &CameraViewPort, projection: &ProjectionType) -> u8 {
|
||||||
let d = cell.depth();
|
let d = cell.depth();
|
||||||
let mut num_sub = 0;
|
// Subdivide all cells at least one time.
|
||||||
|
// TODO: use a single subdivision number computed from the current cells inside the view
|
||||||
|
// i.e. subdivide all cells in the view with the cell that has to be the most subdivided
|
||||||
|
let mut num_sub = 1;
|
||||||
if d < 2 {
|
if d < 2 {
|
||||||
num_sub = 2 - d;
|
num_sub = 2 - d;
|
||||||
}
|
}
|
||||||
@@ -124,158 +127,6 @@ impl<'a, 'b> TextureToDraw<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
pub trait RecomputeRasterizer {
|
|
||||||
// Returns:
|
|
||||||
// * The UV of the starting tile in the global 4096x4096 texture
|
|
||||||
// * The UV of the ending tile in the global 4096x4096 texture
|
|
||||||
// * the blending factor between the two tiles in the texture
|
|
||||||
fn get_textures_from_survey<'a, 'b>(
|
|
||||||
view: &'b HEALPixCellsInView,
|
|
||||||
// The survey from which we get the textures to plot
|
|
||||||
// Usually it is the most refined survey
|
|
||||||
survey: &'a ImageSurveyTextures,
|
|
||||||
) -> Vec<TextureToDraw<'a, 'b>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Move;
|
|
||||||
pub struct Zoom;
|
|
||||||
pub struct UnZoom;
|
|
||||||
|
|
||||||
impl RecomputeRasterizer for Move {
|
|
||||||
// Returns:
|
|
||||||
// * The UV of the starting tile in the global 4096x4096 texture
|
|
||||||
// * The UV of the ending tile in the global 4096x4096 texture
|
|
||||||
// * the blending factor between the two tiles in the texture
|
|
||||||
fn get_textures_from_survey<'a, 'b>(
|
|
||||||
view: &'b HEALPixCellsInView,
|
|
||||||
survey: &'a ImageSurveyTextures,
|
|
||||||
) -> Vec<TextureToDraw<'a, 'b>> {
|
|
||||||
let cells_to_draw = view.get_cells();
|
|
||||||
let mut textures = Vec::with_capacity(view.num_of_cells());
|
|
||||||
|
|
||||||
for cell in cells_to_draw {
|
|
||||||
if survey.contains(cell) {
|
|
||||||
let parent_cell = survey.get_nearest_parent(cell);
|
|
||||||
|
|
||||||
if let Some(ending_cell_in_tex) = survey.get(cell) {
|
|
||||||
if let Some(starting_cell_in_tex) = survey.get(&parent_cell) {
|
|
||||||
textures.push(TextureToDraw::new(
|
|
||||||
starting_cell_in_tex,
|
|
||||||
ending_cell_in_tex,
|
|
||||||
cell,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let parent_cell = survey.get_nearest_parent(cell);
|
|
||||||
let grand_parent_cell = survey.get_nearest_parent(&parent_cell);
|
|
||||||
|
|
||||||
if let Some(ending_cell_in_tex) = survey.get(&parent_cell) {
|
|
||||||
if let Some(starting_cell_in_tex) = survey.get(&grand_parent_cell) {
|
|
||||||
textures.push(TextureToDraw::new(
|
|
||||||
starting_cell_in_tex,
|
|
||||||
ending_cell_in_tex,
|
|
||||||
cell,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textures
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RecomputeRasterizer for Zoom {
|
|
||||||
// Returns:
|
|
||||||
// * The UV of the starting tile in the global 4096x4096 texture
|
|
||||||
// * The UV of the ending tile in the global 4096x4096 texture
|
|
||||||
// * the blending factor between the two tiles in the texture
|
|
||||||
fn get_textures_from_survey<'a, 'b>(
|
|
||||||
view: &'b HEALPixCellsInView,
|
|
||||||
survey: &'a ImageSurveyTextures,
|
|
||||||
) -> Vec<TextureToDraw<'a, 'b>> {
|
|
||||||
let cells_to_draw = view.get_cells();
|
|
||||||
let mut textures = Vec::with_capacity(view.num_of_cells());
|
|
||||||
|
|
||||||
for cell in cells_to_draw {
|
|
||||||
if survey.contains(cell) {
|
|
||||||
let parent_cell = survey.get_nearest_parent(cell);
|
|
||||||
|
|
||||||
if let Some(ending_cell_in_tex) = survey.get(cell) {
|
|
||||||
if let Some(starting_cell_in_tex) = survey.get(&parent_cell) {
|
|
||||||
textures.push(TextureToDraw::new(
|
|
||||||
starting_cell_in_tex,
|
|
||||||
ending_cell_in_tex,
|
|
||||||
cell,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let parent_cell = survey.get_nearest_parent(cell);
|
|
||||||
let grand_parent_cell = survey.get_nearest_parent(&parent_cell);
|
|
||||||
|
|
||||||
if let Some(ending_cell_in_tex) = survey.get(&parent_cell) {
|
|
||||||
if let Some(starting_cell_in_tex) = survey.get(&grand_parent_cell) {
|
|
||||||
textures.push(TextureToDraw::new(
|
|
||||||
starting_cell_in_tex,
|
|
||||||
ending_cell_in_tex,
|
|
||||||
cell,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textures
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RecomputeRasterizer for UnZoom {
|
|
||||||
// Returns:
|
|
||||||
// * The UV of the starting tile in the global 4096x4096 texture
|
|
||||||
// * The UV of the ending tile in the global 4096x4096 texture
|
|
||||||
// * the blending factor between the two tiles in the texture
|
|
||||||
fn get_textures_from_survey<'a, 'b>(
|
|
||||||
view: &'b HEALPixCellsInView,
|
|
||||||
survey: &'a ImageSurveyTextures,
|
|
||||||
) -> Vec<TextureToDraw<'a, 'b>> {
|
|
||||||
let _depth = view.get_depth();
|
|
||||||
let _max_depth = survey.config().get_max_depth();
|
|
||||||
|
|
||||||
// We do not draw the parent cells if the depth has not decreased by at least one
|
|
||||||
let cells_to_draw = view.get_cells();
|
|
||||||
|
|
||||||
let mut textures = Vec::with_capacity(view.num_of_cells());
|
|
||||||
|
|
||||||
for cell in cells_to_draw {
|
|
||||||
if survey.contains(cell) {
|
|
||||||
if let Some(starting_cell_in_tex) = survey.get(cell) {
|
|
||||||
textures.push(TextureToDraw::new(
|
|
||||||
starting_cell_in_tex,
|
|
||||||
starting_cell_in_tex,
|
|
||||||
cell,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let parent_cell = survey.get_nearest_parent(cell);
|
|
||||||
|
|
||||||
if let Some(ending_cell_in_tex) = survey.get(&parent_cell) {
|
|
||||||
textures.push(TextureToDraw::new(
|
|
||||||
ending_cell_in_tex,
|
|
||||||
ending_cell_in_tex,
|
|
||||||
cell,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textures
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub fn get_raster_shader<'a>(
|
pub fn get_raster_shader<'a>(
|
||||||
cmap: &Colormap,
|
cmap: &Colormap,
|
||||||
@@ -675,24 +526,10 @@ impl HiPS {
|
|||||||
self.textures.set_format(&self.gl, ext)
|
self.textures.set_format(&self.gl, ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*pub fn get_fading_factor(&self) -> f32 {
|
|
||||||
self.textures
|
|
||||||
.start_time
|
|
||||||
.map(|start_time| {
|
|
||||||
let fading = (Time::now().0 - start_time.0) / crate::app::BLENDING_ANIM_DURATION.0;
|
|
||||||
fading.clamp(0.0, 1.0)
|
|
||||||
})
|
|
||||||
.unwrap_or(0.0)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub fn is_allsky(&self) -> bool {
|
pub fn is_allsky(&self) -> bool {
|
||||||
self.textures.config().is_allsky
|
self.textures.config().is_allsky
|
||||||
}
|
}
|
||||||
|
|
||||||
/*pub fn reset_frame(&mut self) {
|
|
||||||
self.view.reset_frame();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Position given is in the camera space
|
// Position given is in the camera space
|
||||||
pub fn read_pixel(
|
pub fn read_pixel(
|
||||||
&self,
|
&self,
|
||||||
@@ -966,24 +803,6 @@ impl HiPS {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*pub fn (&mut self, camera: &CameraViewPort, proj: &ProjectionType) {
|
|
||||||
let cfg = self.textures.config();
|
|
||||||
let max_tile_depth = cfg.get_max_tile_depth();
|
|
||||||
//let delta_depth = cfg.delta_depth();
|
|
||||||
|
|
||||||
//let hips_frame = cfg.get_frame();
|
|
||||||
// Compute that depth
|
|
||||||
let camera_tile_depth = camera.get_tile_depth();
|
|
||||||
self.depth_tile = camera_tile_depth.min(max_tile_depth);
|
|
||||||
|
|
||||||
// Set the depth of the HiPS textures
|
|
||||||
/*self.depth = if self.depth_tile > delta_depth {
|
|
||||||
self.depth_tile - delta_depth
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};*/
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Return a boolean to signal if the tile is present or not in the survey
|
// Return a boolean to signal if the tile is present or not in the survey
|
||||||
pub fn update_priority_tile(&mut self, cell: &HEALPixCell) -> bool {
|
pub fn update_priority_tile(&mut self, cell: &HEALPixCell) -> bool {
|
||||||
if self.textures.contains_tile(cell) {
|
if self.textures.contains_tile(cell) {
|
||||||
@@ -1019,21 +838,6 @@ impl HiPS {
|
|||||||
self.textures.config_mut()
|
self.textures.config_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*#[inline]
|
|
||||||
pub fn get_view(&self) -> &HEALPixCellsInView {
|
|
||||||
&self.view
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*#[inline]
|
|
||||||
pub fn get_min_depth_tile(&self) -> u8 {
|
|
||||||
self.min_depth_tile
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*#[inline]
|
|
||||||
pub fn is_ready(&self) -> bool {
|
|
||||||
self.textures.is_ready()
|
|
||||||
}*/
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_ready_time(&self) -> &Option<Time> {
|
pub fn get_ready_time(&self) -> &Option<Time> {
|
||||||
&self.textures.start_time
|
&self.textures.start_time
|
||||||
|
|||||||
@@ -1,293 +0,0 @@
|
|||||||
//use moclib::moc::range::CellAndNeighs;
|
|
||||||
|
|
||||||
/*use crate::renderable::coverage::HEALPixCell;
|
|
||||||
|
|
||||||
use healpix::compass_point::Ordinal;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(super) struct EdgeNeigs {
|
|
||||||
// Indices of the neighbors in the stack
|
|
||||||
pub neig_idx: Vec<usize>,
|
|
||||||
// Smallest depth from the neighbor cells
|
|
||||||
pub max_depth_neig: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(super) struct NodeEdgeNeigs {
|
|
||||||
pub cell: HEALPixCell,
|
|
||||||
pub edge_neigs: [Option<EdgeNeigs>; 4],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for NodeEdgeNeigs {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.cell == other.cell
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeEdgeNeigs {
|
|
||||||
pub(super) fn add_neig(&mut self, org: Ordinal, neig_idx: usize, neig_cell_depth: u8) {
|
|
||||||
let org_idx = org as u8 as usize;
|
|
||||||
if let Some(neigs) = &mut self.edge_neigs[org_idx] {
|
|
||||||
neigs.neig_idx.push(neig_idx);
|
|
||||||
neigs.max_depth_neig = neigs.max_depth_neig.max(neig_cell_depth);
|
|
||||||
} else {
|
|
||||||
self.edge_neigs[org_idx] = Some(EdgeNeigs {
|
|
||||||
neig_idx: vec![neig_idx],
|
|
||||||
max_depth_neig: neig_cell_depth,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn compute_n_seg(&self, side: Ordinal) -> u32 {
|
|
||||||
let mut delta_depth =
|
|
||||||
if let Some(edge_neigs) = self.edge_neigs[side as u8 as usize].as_ref() {
|
|
||||||
edge_neigs.max_depth_neig.max(self.cell.depth()) - self.cell.depth()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.cell.depth() + delta_depth < 3 {
|
|
||||||
delta_depth = 3 - self.cell.depth();
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.cell.depth() >= 6 {
|
|
||||||
delta_depth = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
1 << delta_depth
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn compute_n_seg_with_neig_info(
|
|
||||||
&self,
|
|
||||||
neig: &Self,
|
|
||||||
side: Ordinal,
|
|
||||||
side_neig: Ordinal,
|
|
||||||
) -> u32 {
|
|
||||||
let mut delta_depth = if self.cell.depth() > 6 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
if let (Some(edge_neigs), Some(edge_self)) = (
|
|
||||||
self.edge_neigs[side as u8 as usize].as_ref(),
|
|
||||||
neig.edge_neigs[side_neig as u8 as usize].as_ref(),
|
|
||||||
) {
|
|
||||||
edge_neigs
|
|
||||||
.max_depth_neig
|
|
||||||
.max(edge_self.max_depth_neig)
|
|
||||||
.max(self.cell.depth())
|
|
||||||
- self.cell.depth()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.cell.depth() + delta_depth < 3 {
|
|
||||||
delta_depth = 3 - self.cell.depth();
|
|
||||||
}
|
|
||||||
|
|
||||||
1 << delta_depth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*pub(super) struct G {
|
|
||||||
nodes: Vec<NodeEdgeNeigs>,
|
|
||||||
}
|
|
||||||
use crate::renderable::coverage::mode::Node;
|
|
||||||
impl G {
|
|
||||||
pub(super) fn new(moc: &HEALPixCoverage) -> Self {
|
|
||||||
let mut nodes: Vec<_> = (&moc.0)
|
|
||||||
.into_range_moc_iter()
|
|
||||||
.cells()
|
|
||||||
.map(|cell| {
|
|
||||||
let cell = HEALPixCell(cell.depth, cell.idx);
|
|
||||||
|
|
||||||
NodeEdgeNeigs {
|
|
||||||
cell,
|
|
||||||
edge_neigs: [None, None, None, None],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let find_cell_node_idx = |nodes: &[NodeEdgeNeigs], cell: &Cell<u64>| -> usize {
|
|
||||||
let hpx_cell = HEALPixCell(cell.depth, cell.idx);
|
|
||||||
let result = nodes.binary_search_by(|n| n.cell.cmp(&hpx_cell));
|
|
||||||
match result {
|
|
||||||
Ok(i) => i,
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 1. Build the MOC graph structure
|
|
||||||
for cell_and_neig in moc.0.all_cells_with_unidirectional_neigs() {
|
|
||||||
let CellAndNeighs { cell, neigs } = cell_and_neig;
|
|
||||||
// cells are given by uniq order so big cells at first and smaller cells after
|
|
||||||
// neighbor information are also given for small cells towards bigger cells
|
|
||||||
// Thus we are sure we have already processed the neighbor before as it is a bigger cell or equal order
|
|
||||||
// cell having an idx inferior
|
|
||||||
|
|
||||||
let small_node_idx = find_cell_node_idx(&nodes, &cell);
|
|
||||||
|
|
||||||
if let Some(&nw_neig_cell_idx) = neigs.get(Ordinal::NW) {
|
|
||||||
//al_core::log("nw neig");
|
|
||||||
let nw_neig_cell_d = nodes[nw_neig_cell_idx].cell.depth();
|
|
||||||
debug_assert!(nw_neig_cell_d <= cell.depth);
|
|
||||||
|
|
||||||
if let Some(dir) =
|
|
||||||
find_neig_dir(nodes[nw_neig_cell_idx].cell, nodes[small_node_idx].cell)
|
|
||||||
{
|
|
||||||
nodes[nw_neig_cell_idx].add_neig(dir, small_node_idx, cell.depth);
|
|
||||||
}
|
|
||||||
// Add the neig info from the big to the small node
|
|
||||||
//nodes[nw_neig_cell_idx].add_neig(Ordinal::SE, small_node_idx, cell.depth);
|
|
||||||
// Add the neig info from the small to the big node
|
|
||||||
nodes[small_node_idx].add_neig(Ordinal::NW, nw_neig_cell_idx, nw_neig_cell_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(&ne_neig_cell_idx) = neigs.get(Ordinal::NE) {
|
|
||||||
//al_core::log("ne neig");
|
|
||||||
let ne_neig_cell_d = nodes[ne_neig_cell_idx].cell.depth();
|
|
||||||
debug_assert!(ne_neig_cell_d <= cell.depth);
|
|
||||||
|
|
||||||
if let Some(dir) =
|
|
||||||
find_neig_dir(nodes[ne_neig_cell_idx].cell, nodes[small_node_idx].cell)
|
|
||||||
{
|
|
||||||
nodes[ne_neig_cell_idx].add_neig(dir, small_node_idx, cell.depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the neig info from the big to the small node
|
|
||||||
//nodes[ne_neig_cell_idx].add_neig(Ordinal::SW, small_node_idx, cell.depth);
|
|
||||||
// Add the neig info from the small to the big node
|
|
||||||
nodes[small_node_idx].add_neig(Ordinal::NE, ne_neig_cell_idx, ne_neig_cell_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(&se_neig_cell_idx) = neigs.get(Ordinal::SE) {
|
|
||||||
//al_core::log("se neig");
|
|
||||||
let se_neig_cell_d = nodes[se_neig_cell_idx].cell.depth();
|
|
||||||
debug_assert!(se_neig_cell_d <= cell.depth);
|
|
||||||
|
|
||||||
if let Some(dir) =
|
|
||||||
find_neig_dir(nodes[se_neig_cell_idx].cell, nodes[small_node_idx].cell)
|
|
||||||
{
|
|
||||||
nodes[se_neig_cell_idx].add_neig(dir, small_node_idx, cell.depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the neig info from the big to the small node
|
|
||||||
//nodes[se_neig_cell_idx].add_neig(Ordinal::NW, small_node_idx, cell.depth);
|
|
||||||
// Add the neig info from the small to the big node
|
|
||||||
nodes[small_node_idx].add_neig(Ordinal::SE, se_neig_cell_idx, se_neig_cell_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(&sw_neig_cell_idx) = neigs.get(Ordinal::SW) {
|
|
||||||
//al_core::log("sw neig");
|
|
||||||
let sw_neig_cell_d = nodes[sw_neig_cell_idx].cell.depth();
|
|
||||||
debug_assert!(sw_neig_cell_d <= cell.depth);
|
|
||||||
|
|
||||||
if let Some(dir) =
|
|
||||||
find_neig_dir(nodes[sw_neig_cell_idx].cell, nodes[small_node_idx].cell)
|
|
||||||
{
|
|
||||||
nodes[sw_neig_cell_idx].add_neig(dir, small_node_idx, cell.depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the neig info from the big to the small node
|
|
||||||
//nodes[sw_neig_cell_idx].add_neig(Ordinal::NE, small_node_idx, cell.depth);
|
|
||||||
// Add the neig info from the small to the big node
|
|
||||||
nodes[small_node_idx].add_neig(Ordinal::SW, sw_neig_cell_idx, sw_neig_cell_d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self { nodes }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn get_neigs(
|
|
||||||
&self,
|
|
||||||
node: &NodeEdgeNeigs,
|
|
||||||
dir: Ordinal,
|
|
||||||
) -> Option<Vec<&NodeEdgeNeigs>> {
|
|
||||||
node.edge_neigs[dir as u8 as usize]
|
|
||||||
.as_ref()
|
|
||||||
.map(|edge| {
|
|
||||||
if !edge.neig_idx.is_empty() {
|
|
||||||
Some(
|
|
||||||
edge.neig_idx
|
|
||||||
.iter()
|
|
||||||
.map(|idx| &self.nodes[*idx])
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn get_neig_dir(
|
|
||||||
&self,
|
|
||||||
node: &NodeEdgeNeigs,
|
|
||||||
neig: &NodeEdgeNeigs,
|
|
||||||
) -> Option<Ordinal> {
|
|
||||||
if let Some(neigs) = self.get_neigs(node, Ordinal::NW) {
|
|
||||||
if let Some(_) = neigs.iter().find(|&&n| n == neig) {
|
|
||||||
return Some(Ordinal::NW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(neigs) = self.get_neigs(node, Ordinal::SW) {
|
|
||||||
if let Some(_) = neigs.iter().find(|&&n| n == neig) {
|
|
||||||
return Some(Ordinal::SW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(neigs) = self.get_neigs(node, Ordinal::SE) {
|
|
||||||
if let Some(_) = neigs.iter().find(|&&n| n == neig) {
|
|
||||||
return Some(Ordinal::SE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(neigs) = self.get_neigs(node, Ordinal::NE) {
|
|
||||||
if let Some(_) = neigs.iter().find(|&&n| n == neig) {
|
|
||||||
return Some(Ordinal::NE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn nodes_iter<'a>(&'a self) -> impl Iterator<Item = &'a NodeEdgeNeigs> {
|
|
||||||
self.nodes.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn nodes(&self) -> &[NodeEdgeNeigs] {
|
|
||||||
&self.nodes[..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_neig_dir(mut cell: HEALPixCell, mut neig: HEALPixCell) -> Option<Ordinal> {
|
|
||||||
if cell.depth() > neig.depth() {
|
|
||||||
cell = cell.ancestor(cell.depth() - neig.depth());
|
|
||||||
} else if cell.depth() < neig.depth() {
|
|
||||||
neig = neig.ancestor(neig.depth() - cell.depth());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(nw) = cell.neighbor(MainWind::NW) {
|
|
||||||
if nw == neig {
|
|
||||||
return Some(Ordinal::NW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ne) = cell.neighbor(MainWind::NE) {
|
|
||||||
if ne == neig {
|
|
||||||
return Some(Ordinal::NE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(sw) = cell.neighbor(MainWind::SW) {
|
|
||||||
if sw == neig {
|
|
||||||
return Some(Ordinal::SW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(se) = cell.neighbor(MainWind::SE) {
|
|
||||||
if se == neig {
|
|
||||||
return Some(Ordinal::SE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
mod graph;
|
|
||||||
mod mode;
|
|
||||||
|
|
||||||
pub mod hierarchy;
|
pub mod hierarchy;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub use renderer::MOCRenderer;
|
pub use renderer::MOCRenderer;
|
||||||
|
|||||||
@@ -1,192 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
pub struct Edge;
|
|
||||||
|
|
||||||
impl RenderMode for Edge {
|
|
||||||
fn build(moc: &HEALPixCoverage) -> Vec<Node> {
|
|
||||||
let g = graph::G::new(moc);
|
|
||||||
|
|
||||||
// 2. Precompute the vertices from the graph structure
|
|
||||||
g.nodes_iter()
|
|
||||||
.flat_map(|n| {
|
|
||||||
let mut edges = OrdinalMap::new();
|
|
||||||
let cell = n.cell;
|
|
||||||
|
|
||||||
if let Some(edge_neigs) = &n.edge_neigs[Ordinal::NW as u8 as usize] {
|
|
||||||
// if the smallest neig for this edge is smaller than self
|
|
||||||
let _smallest_neig_depth = edge_neigs.max_depth_neig;
|
|
||||||
|
|
||||||
let first_neig_idx = edge_neigs.neig_idx[0];
|
|
||||||
let neig_cell = &g.nodes()[first_neig_idx].cell;
|
|
||||||
|
|
||||||
let draw_side =
|
|
||||||
// the current node has several (smaller) neig
|
|
||||||
edge_neigs.neig_idx.len() > 1
|
|
||||||
// or it has only one neig and if so
|
|
||||||
// we draw the side either if the node's idx is < to the neig's idx
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() == neig_cell.depth()
|
|
||||||
&& neig_cell.idx() > cell.idx())
|
|
||||||
// or we draw the side if the neig is smaller than the node
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() < neig_cell.depth());
|
|
||||||
|
|
||||||
if draw_side {
|
|
||||||
debug_assert!(edge_neigs.max_depth_neig >= cell.depth());
|
|
||||||
|
|
||||||
// draw the NW edge
|
|
||||||
edges.put(Ordinal::NW, n.compute_n_seg(Ordinal::NW));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// draw the NW edge because there are no neig along that edge
|
|
||||||
edges.put(Ordinal::NW, n.compute_n_seg(Ordinal::NW));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(edge_neigs) = &n.edge_neigs[Ordinal::SW as u8 as usize] {
|
|
||||||
// if the smallest neig for this edge is smaller than self
|
|
||||||
let _smallest_neig_depth = edge_neigs.max_depth_neig;
|
|
||||||
|
|
||||||
let first_neig_idx = edge_neigs.neig_idx[0];
|
|
||||||
let neig_cell = &g.nodes()[first_neig_idx].cell;
|
|
||||||
|
|
||||||
let draw_side =
|
|
||||||
// the current node has several (smaller) neig
|
|
||||||
edge_neigs.neig_idx.len() > 1
|
|
||||||
// or it has only one neig and if so
|
|
||||||
// we draw the side either if the node's idx is < to the neig's idx
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() == neig_cell.depth()
|
|
||||||
&& neig_cell.idx() > cell.idx())
|
|
||||||
// or we draw the side if the neig is smaller than the node
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() < neig_cell.depth());
|
|
||||||
|
|
||||||
if draw_side {
|
|
||||||
debug_assert!(edge_neigs.max_depth_neig >= cell.depth());
|
|
||||||
|
|
||||||
// draw the NW edge
|
|
||||||
edges.put(Ordinal::SW, n.compute_n_seg(Ordinal::SW));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// draw the NW edge because there are no neig along that edge
|
|
||||||
edges.put(Ordinal::SW, n.compute_n_seg(Ordinal::SW));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(edge_neigs) = &n.edge_neigs[Ordinal::SE as u8 as usize] {
|
|
||||||
// if the smallest neig for this edge is smaller than self
|
|
||||||
let _smallest_neig_depth = edge_neigs.max_depth_neig;
|
|
||||||
|
|
||||||
let first_neig_idx = edge_neigs.neig_idx[0];
|
|
||||||
let neig_cell = &g.nodes()[first_neig_idx].cell;
|
|
||||||
|
|
||||||
let draw_side =
|
|
||||||
// the current node has several (smaller) neig
|
|
||||||
edge_neigs.neig_idx.len() > 1
|
|
||||||
// or it has only one neig and if so
|
|
||||||
// we draw the side either if the node's idx is < to the neig's idx
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() == neig_cell.depth()
|
|
||||||
&& neig_cell.idx() > cell.idx())
|
|
||||||
// or we draw the side if the neig is smaller than the node
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() < neig_cell.depth());
|
|
||||||
|
|
||||||
if draw_side {
|
|
||||||
debug_assert!(edge_neigs.max_depth_neig >= cell.depth());
|
|
||||||
|
|
||||||
edges.put(Ordinal::SE, n.compute_n_seg(Ordinal::SE));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// draw the NW edge because there are no neig along that edge
|
|
||||||
edges.put(Ordinal::SE, n.compute_n_seg(Ordinal::SE));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(edge_neigs) = &n.edge_neigs[Ordinal::NE as u8 as usize] {
|
|
||||||
// if the smallest neig for this edge is smaller than self
|
|
||||||
let _smallest_neig_depth = edge_neigs.max_depth_neig;
|
|
||||||
|
|
||||||
let first_neig_idx = edge_neigs.neig_idx[0];
|
|
||||||
let neig_cell = &g.nodes()[first_neig_idx].cell;
|
|
||||||
|
|
||||||
let draw_side =
|
|
||||||
// the current node has several (smaller) neig
|
|
||||||
edge_neigs.neig_idx.len() > 1
|
|
||||||
// or it has only one neig and if so
|
|
||||||
// we draw the side either if the node's idx is < to the neig's idx
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() == neig_cell.depth()
|
|
||||||
&& neig_cell.idx() > cell.idx())
|
|
||||||
// or we draw the side if the neig is smaller than the node
|
|
||||||
|| (edge_neigs.neig_idx.len() == 1
|
|
||||||
&& cell.depth() < neig_cell.depth());
|
|
||||||
|
|
||||||
if draw_side {
|
|
||||||
debug_assert!(edge_neigs.max_depth_neig >= cell.depth());
|
|
||||||
|
|
||||||
// draw the NW edge
|
|
||||||
edges.put(Ordinal::NE, n.compute_n_seg(Ordinal::NE));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// draw the NE edge because there are no neig along that edge
|
|
||||||
edges.put(Ordinal::NE, n.compute_n_seg(Ordinal::NE));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*let delta_depth = (3 - (cell.depth() as usize)).max(0) as u8;
|
|
||||||
|
|
||||||
cell.get_children_cells(delta_depth).map(move |child_cell| {
|
|
||||||
let mut edges = OrdinalMap::new();
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
Node {
|
|
||||||
vertices: child_cell.path_along_sides(&edges),
|
|
||||||
cell: child_cell,
|
|
||||||
}
|
|
||||||
})*/
|
|
||||||
|
|
||||||
if cell.depth() < 2 {
|
|
||||||
/*let max_depth = crate::math::utils::log_2_unchecked(n_seg_nw)
|
|
||||||
.max(crate::math::utils::log_2_unchecked(n_seg_se))
|
|
||||||
.max(crate::math::utils::log_2_unchecked(n_seg_ne))
|
|
||||||
.max(crate::math::utils::log_2_unchecked(n_seg_sw))
|
|
||||||
+ cell.depth() as u32;
|
|
||||||
let n_seg = if max_depth > 3 {
|
|
||||||
1 << (max_depth - 3)
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
};*/
|
|
||||||
|
|
||||||
cell.get_children_cells(2 - cell.depth())
|
|
||||||
.map(|child_cell| {
|
|
||||||
let mut edges = OrdinalMap::new();
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
|
|
||||||
Node {
|
|
||||||
vertices: child_cell.path_along_sides(&edges),
|
|
||||||
cell: child_cell,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
vec![Node {
|
|
||||||
vertices: cell.path_along_sides(&edges),
|
|
||||||
cell,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
use super::super::graph::G;
|
|
||||||
|
|
||||||
pub struct Fill;
|
|
||||||
|
|
||||||
impl RenderMode for Fill {
|
|
||||||
fn build(moc: &HEALPixCoverage) -> Vec<Node> {
|
|
||||||
let g = G::new(moc);
|
|
||||||
|
|
||||||
let n_seg_from_dir = |n: &NodeEdgeNeigs, dir: Ordinal| -> u32 {
|
|
||||||
if let Some(neigs) = g.get_neigs(n, dir) {
|
|
||||||
if let Some(neig_side) = g.get_neig_dir(neigs[0], n) {
|
|
||||||
n.compute_n_seg_with_neig_info(neigs[0], dir, neig_side)
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
g.nodes_iter()
|
|
||||||
.flat_map(|n| {
|
|
||||||
let cell = n.cell;
|
|
||||||
|
|
||||||
// Draw all of the node's edges
|
|
||||||
let n_seg_nw = n_seg_from_dir(n, Ordinal::NW);
|
|
||||||
let n_seg_ne = n_seg_from_dir(n, Ordinal::NE);
|
|
||||||
let n_seg_sw = n_seg_from_dir(n, Ordinal::SW);
|
|
||||||
let n_seg_se = n_seg_from_dir(n, Ordinal::SE);
|
|
||||||
|
|
||||||
match cell.depth() {
|
|
||||||
0 => {
|
|
||||||
let n_seg_sw = (n_seg_sw >> 2).max(1);
|
|
||||||
let n_seg_se = (n_seg_se >> 2).max(1);
|
|
||||||
let n_seg_nw = (n_seg_nw >> 2).max(1);
|
|
||||||
let n_seg_ne = (n_seg_ne >> 2).max(1);
|
|
||||||
|
|
||||||
cell.get_children_cells(2)
|
|
||||||
.map(|child_cell| {
|
|
||||||
let mut edges = OrdinalMap::new();
|
|
||||||
|
|
||||||
let off = child_cell.idx() - (cell.idx() << 4);
|
|
||||||
|
|
||||||
match off {
|
|
||||||
// S
|
|
||||||
0 => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, n_seg_sw);
|
|
||||||
edges.put(Ordinal::SE, n_seg_se);
|
|
||||||
}
|
|
||||||
// W
|
|
||||||
10 => {
|
|
||||||
edges.put(Ordinal::NW, n_seg_nw);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, n_seg_sw);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
// E
|
|
||||||
5 => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, n_seg_ne);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, n_seg_se);
|
|
||||||
}
|
|
||||||
// N
|
|
||||||
15 => {
|
|
||||||
edges.put(Ordinal::NW, n_seg_nw);
|
|
||||||
edges.put(Ordinal::NE, n_seg_ne);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
// SE
|
|
||||||
1 | 4 => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, n_seg_se);
|
|
||||||
}
|
|
||||||
// SW
|
|
||||||
2 | 8 => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, n_seg_sw);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
// NW
|
|
||||||
11 | 14 => {
|
|
||||||
edges.put(Ordinal::NW, n_seg_nw);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
// NE
|
|
||||||
7 | 13 => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, n_seg_ne);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Node {
|
|
||||||
vertices: child_cell.path_along_sides(&edges),
|
|
||||||
cell: child_cell,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let n_seg_sw = (n_seg_sw >> 1).max(1);
|
|
||||||
let n_seg_se = (n_seg_se >> 1).max(1);
|
|
||||||
let n_seg_nw = (n_seg_nw >> 1).max(1);
|
|
||||||
let n_seg_ne = (n_seg_ne >> 1).max(1);
|
|
||||||
|
|
||||||
cell.get_children_cells(1)
|
|
||||||
.map(|child_cell| {
|
|
||||||
let mut edges = OrdinalMap::new();
|
|
||||||
|
|
||||||
let off = child_cell.idx() - (cell.idx() << 2);
|
|
||||||
match off {
|
|
||||||
// S
|
|
||||||
0 => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, n_seg_sw);
|
|
||||||
edges.put(Ordinal::SE, n_seg_se);
|
|
||||||
}
|
|
||||||
// W
|
|
||||||
2 => {
|
|
||||||
edges.put(Ordinal::NW, n_seg_nw);
|
|
||||||
edges.put(Ordinal::NE, 1);
|
|
||||||
edges.put(Ordinal::SW, n_seg_sw);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
// E
|
|
||||||
1 => {
|
|
||||||
edges.put(Ordinal::NW, 1);
|
|
||||||
edges.put(Ordinal::NE, n_seg_ne);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, n_seg_se);
|
|
||||||
}
|
|
||||||
// N
|
|
||||||
3 => {
|
|
||||||
edges.put(Ordinal::NW, n_seg_nw);
|
|
||||||
edges.put(Ordinal::NE, n_seg_ne);
|
|
||||||
edges.put(Ordinal::SW, 1);
|
|
||||||
edges.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Node {
|
|
||||||
vertices: child_cell.path_along_sides(&edges),
|
|
||||||
cell: child_cell,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mut edges = OrdinalMap::new();
|
|
||||||
|
|
||||||
edges.put(Ordinal::NW, n_seg_nw);
|
|
||||||
edges.put(Ordinal::NE, n_seg_ne);
|
|
||||||
edges.put(Ordinal::SW, n_seg_sw);
|
|
||||||
edges.put(Ordinal::SE, n_seg_se);
|
|
||||||
|
|
||||||
vec![Node {
|
|
||||||
vertices: cell.path_along_sides(&edges),
|
|
||||||
cell,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
pub mod edge;
|
|
||||||
pub mod filled;
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
use super::Node;
|
|
||||||
use super::RenderMode;
|
|
||||||
use crate::healpix::cell::HEALPixCell;
|
|
||||||
use healpix::compass_point::{Ordinal, OrdinalMap};
|
|
||||||
use moclib::elem::cell::Cell;
|
|
||||||
|
|
||||||
use crate::HEALPixCoverage;
|
|
||||||
use moclib::moc::range::CellAndEdges;
|
|
||||||
|
|
||||||
pub struct Perimeter;
|
|
||||||
|
|
||||||
impl RenderMode for Perimeter {
|
|
||||||
fn build(moc: &HEALPixCoverage) -> impl Iterator<Item = Node> {
|
|
||||||
moc.0
|
|
||||||
.border_elementary_edges()
|
|
||||||
.map(|CellAndEdges { uniq, edges }| {
|
|
||||||
let c = Cell::from_uniq_hpx(uniq);
|
|
||||||
let cell = HEALPixCell(c.depth, c.idx);
|
|
||||||
|
|
||||||
let mut map = OrdinalMap::new();
|
|
||||||
if edges.get(moclib::moc::range::Ordinal::SE) {
|
|
||||||
map.put(Ordinal::SE, 1);
|
|
||||||
}
|
|
||||||
if edges.get(moclib::moc::range::Ordinal::SW) {
|
|
||||||
map.put(Ordinal::SW, 1);
|
|
||||||
}
|
|
||||||
if edges.get(moclib::moc::range::Ordinal::NE) {
|
|
||||||
map.put(Ordinal::NE, 1);
|
|
||||||
}
|
|
||||||
if edges.get(moclib::moc::range::Ordinal::NW) {
|
|
||||||
map.put(Ordinal::NW, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let vertices = cell.path_along_sides(&map);
|
|
||||||
|
|
||||||
Node { cell, vertices }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -36,8 +36,8 @@ pub struct TextureCellItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TextureCellItem {
|
impl TextureCellItem {
|
||||||
fn is_root(&self, delta_depth: u8) -> bool {
|
fn is_root(&self) -> bool {
|
||||||
self.cell.is_root(delta_depth)
|
self.cell.is_root()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ impl ImageSurveyTextures {
|
|||||||
// Get the texture cell in which the tile has to be
|
// Get the texture cell in which the tile has to be
|
||||||
let tex_cell = cell.get_texture_cell(dd);
|
let tex_cell = cell.get_texture_cell(dd);
|
||||||
|
|
||||||
let tex_cell_is_root = tex_cell.is_root(dd);
|
let tex_cell_is_root = tex_cell.is_root();
|
||||||
if !tex_cell_is_root && !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
|
// The texture is not among the essential ones
|
||||||
// (i.e. is not a root texture)
|
// (i.e. is not a root texture)
|
||||||
@@ -326,7 +326,7 @@ impl ImageSurveyTextures {
|
|||||||
// Pop the oldest requested texture
|
// Pop the oldest requested texture
|
||||||
let oldest_texture = self.heap.pop().unwrap_abort();
|
let oldest_texture = self.heap.pop().unwrap_abort();
|
||||||
// Ensure this is not a base texture
|
// Ensure this is not a base texture
|
||||||
debug_assert!(!oldest_texture.is_root(self.config.delta_depth()));
|
debug_assert!(!oldest_texture.is_root());
|
||||||
|
|
||||||
// Remove it from the textures HashMap
|
// Remove it from the textures HashMap
|
||||||
let mut texture = self.textures.remove(&oldest_texture.cell).expect(
|
let mut texture = self.textures.remove(&oldest_texture.cell).expect(
|
||||||
@@ -448,9 +448,10 @@ impl ImageSurveyTextures {
|
|||||||
// texture ancestor exists and then, it it contains the tile
|
// texture ancestor exists and then, it it contains the tile
|
||||||
pub fn contains_tile(&self, cell: &HEALPixCell) -> bool {
|
pub fn contains_tile(&self, cell: &HEALPixCell) -> bool {
|
||||||
let dd = self.config.delta_depth();
|
let dd = self.config.delta_depth();
|
||||||
|
|
||||||
let texture_cell = cell.get_texture_cell(dd);
|
let texture_cell = cell.get_texture_cell(dd);
|
||||||
|
|
||||||
let tex_cell_is_root = texture_cell.is_root(dd);
|
let tex_cell_is_root = texture_cell.is_root();
|
||||||
if tex_cell_is_root {
|
if tex_cell_is_root {
|
||||||
let HEALPixCell(_, idx) = texture_cell;
|
let HEALPixCell(_, idx) = texture_cell;
|
||||||
self.base_textures[idx as usize].contains(cell)
|
self.base_textures[idx as usize].contains(cell)
|
||||||
@@ -471,10 +472,11 @@ impl ImageSurveyTextures {
|
|||||||
pub fn update_priority(&mut self, cell: &HEALPixCell /*, new_fov_cell: bool*/) {
|
pub fn update_priority(&mut self, cell: &HEALPixCell /*, new_fov_cell: bool*/) {
|
||||||
debug_assert!(self.contains_tile(cell));
|
debug_assert!(self.contains_tile(cell));
|
||||||
|
|
||||||
// Get the texture cell in which the tile has to be
|
|
||||||
let dd = self.config.delta_depth();
|
let dd = self.config.delta_depth();
|
||||||
|
|
||||||
|
// Get the texture cell in which the tile has to be
|
||||||
let texture_cell = cell.get_texture_cell(dd);
|
let texture_cell = cell.get_texture_cell(dd);
|
||||||
if texture_cell.is_root(dd) {
|
if texture_cell.is_root() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,7 +558,7 @@ impl ImageSurveyTextures {
|
|||||||
|
|
||||||
/// Accessors
|
/// Accessors
|
||||||
pub fn get(&self, texture_cell: &HEALPixCell) -> Option<&Texture> {
|
pub fn get(&self, texture_cell: &HEALPixCell) -> Option<&Texture> {
|
||||||
if texture_cell.is_root(self.config().delta_depth()) {
|
if texture_cell.is_root() {
|
||||||
let HEALPixCell(_, idx) = texture_cell;
|
let HEALPixCell(_, idx) = texture_cell;
|
||||||
Some(&self.base_textures[*idx as usize])
|
Some(&self.base_textures[*idx as usize])
|
||||||
} else {
|
} else {
|
||||||
@@ -566,14 +568,13 @@ impl ImageSurveyTextures {
|
|||||||
|
|
||||||
// Get the nearest parent tile found in the CPU buffer
|
// 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) -> Option<HEALPixCell> {
|
||||||
let dd = self.config.delta_depth();
|
if cell.is_root() {
|
||||||
if cell.is_root(dd) {
|
|
||||||
// Root cells are in the buffer by definition
|
// Root cells are in the buffer by definition
|
||||||
Some(*cell)
|
Some(*cell)
|
||||||
} else {
|
} else {
|
||||||
let mut parent_cell = cell.parent();
|
let mut parent_cell = cell.parent();
|
||||||
|
|
||||||
while !self.contains(&parent_cell) && !parent_cell.is_root(dd) {
|
while !self.contains(&parent_cell) && !parent_cell.is_root() {
|
||||||
parent_cell = parent_cell.parent();
|
parent_cell = parent_cell.parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,19 @@ use crate::renderable::HiPS;
|
|||||||
use crate::time::{DeltaTime, Time};
|
use crate::time::{DeltaTime, Time};
|
||||||
use crate::Abort;
|
use crate::Abort;
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
use crate::utils;
|
||||||
const MAX_NUM_TILE_FETCHING: usize = 8;
|
const MAX_NUM_TILE_FETCHING: usize = 8;
|
||||||
const MAX_QUERY_QUEUE_LENGTH: usize = 100;
|
const MAX_QUERY_QUEUE_LENGTH: usize = 100;
|
||||||
|
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
pub struct TileFetcherQueue {
|
pub struct TileFetcherQueue {
|
||||||
// A stack of queries to fetch
|
// A stack of queries to fetch
|
||||||
queries: VecDeque<query::Tile>,
|
queries: VecDeque<query::Tile>,
|
||||||
@@ -35,7 +43,7 @@ impl TileFetcherQueue {
|
|||||||
//self.query_set.clear();
|
//self.query_set.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(&mut self, query: query::Tile, _downloader: &mut Downloader) {
|
pub fn append(&mut self, query: query::Tile) {
|
||||||
// Check if the query has already been done
|
// Check if the query has already been done
|
||||||
//if !self.query_set.contains(&query) {
|
//if !self.query_set.contains(&query) {
|
||||||
// discard too old tile queries
|
// discard too old tile queries
|
||||||
@@ -47,11 +55,11 @@ impl TileFetcherQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetch the base tile
|
// fetch the base tile
|
||||||
pub fn append_base_tile(&mut self, query: query::Tile, _downloader: &mut Downloader) {
|
pub fn append_base_tile(&mut self, query: query::Tile) {
|
||||||
self.base_tile_queries.push(query);
|
self.base_tile_queries.push(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify(&mut self, downloader: &mut Downloader, dt: Option<DeltaTime>) {
|
pub fn notify(&mut self, downloader: Rc<RefCell<Downloader>>, dt: Option<DeltaTime>) {
|
||||||
// notify all the x ms
|
// notify all the x ms
|
||||||
let now = Time::now();
|
let now = Time::now();
|
||||||
|
|
||||||
@@ -70,37 +78,40 @@ impl TileFetcherQueue {
|
|||||||
self.num_tiles_fetched
|
self.num_tiles_fetched
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(&mut self, downloader: &mut Downloader) {
|
fn fetch(&mut self, downloader: Rc<RefCell<Downloader>>) {
|
||||||
// Fetch the base tiles with higher priority
|
// Fetch the base tiles with higher priority
|
||||||
while let Some(query) = self.base_tile_queries.pop() {
|
while let Some(query) = self.base_tile_queries.pop() {
|
||||||
//if downloader.fetch(query) {
|
//if downloader.fetch(query) {
|
||||||
// The fetch has succeded
|
// The fetch has succeded
|
||||||
//self.num_tiles_fetched += 1;
|
//self.num_tiles_fetched += 1;
|
||||||
//}
|
//}
|
||||||
downloader.fetch(query);
|
downloader.borrow_mut().fetch(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut num_fetched_tile = 0;
|
let mut num_fetched_tile = 0;
|
||||||
while num_fetched_tile < MAX_NUM_TILE_FETCHING && !self.queries.is_empty() {
|
while num_fetched_tile < MAX_NUM_TILE_FETCHING && !self.queries.is_empty() {
|
||||||
let query = self.queries.pop_back().unwrap_abort();
|
let query = self.queries.pop_back().unwrap_abort();
|
||||||
|
|
||||||
if downloader.fetch(query) {
|
if downloader.borrow_mut().fetch(query) {
|
||||||
// The fetch has succeded
|
// The fetch has succeded
|
||||||
num_fetched_tile += 1;
|
num_fetched_tile += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.num_tiles_fetched += num_fetched_tile;
|
self.num_tiles_fetched += num_fetched_tile;
|
||||||
//log!(num_fetched_tile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launch_starting_hips_requests(&mut self, hips: &HiPS, downloader: &mut Downloader) {
|
pub fn launch_starting_hips_requests(
|
||||||
|
&mut self,
|
||||||
|
hips: &HiPS,
|
||||||
|
downloader: Rc<RefCell<Downloader>>,
|
||||||
|
) {
|
||||||
let cfg = hips.get_config();
|
let cfg = hips.get_config();
|
||||||
// Request for the allsky first
|
// Request for the allsky first
|
||||||
// The allsky is not mandatory present in a HiPS service but it is better to first try to search for it
|
// The allsky is not mandatory present in a HiPS service but it is better to first try to search for it
|
||||||
//downloader.fetch(query::PixelMetadata::new(cfg));
|
//downloader.fetch(query::PixelMetadata::new(cfg));
|
||||||
// Try to fetch the MOC
|
// Try to fetch the MOC
|
||||||
downloader.fetch(query::Moc::new(
|
downloader.borrow_mut().fetch(query::Moc::new(
|
||||||
format!("{}/Moc.fits", cfg.get_root_url()),
|
format!("{}/Moc.fits", cfg.get_root_url()),
|
||||||
cfg.get_creator_did().to_string(),
|
cfg.get_creator_did().to_string(),
|
||||||
al_api::moc::MOC::default(),
|
al_api::moc::MOC::default(),
|
||||||
@@ -110,7 +121,27 @@ impl TileFetcherQueue {
|
|||||||
//Request the allsky for the small tile size or if base tiles are not available
|
//Request the allsky for the small tile size or if base tiles are not available
|
||||||
if tile_size <= 128 || cfg.get_min_depth_tile() > 0 {
|
if tile_size <= 128 || cfg.get_min_depth_tile() > 0 {
|
||||||
// Request the allsky
|
// Request the allsky
|
||||||
downloader.fetch(query::Allsky::new(cfg));
|
downloader.borrow_mut().fetch(query::Allsky::new(cfg));
|
||||||
|
} else if cfg.get_min_depth_tile() == 0 {
|
||||||
|
let hips_cdid = cfg.get_creator_did().to_string();
|
||||||
|
let hips_url = cfg.get_root_url().to_string();
|
||||||
|
let hips_fmt = cfg.get_format();
|
||||||
|
let min_order = cfg.get_min_depth_texture();
|
||||||
|
|
||||||
|
let dl = downloader.clone();
|
||||||
|
utils::set_timeout(
|
||||||
|
move || {
|
||||||
|
for tile_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||||
|
dl.borrow_mut().fetch(query::Tile::new(
|
||||||
|
tile_cell,
|
||||||
|
hips_cdid.clone(),
|
||||||
|
hips_url.clone(),
|
||||||
|
hips_fmt,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2_000,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/*else {
|
/*else {
|
||||||
for texture_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
for texture_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||||
@@ -122,5 +153,25 @@ impl TileFetcherQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
let f = async move {
|
||||||
|
let mut cb = |resolve: js_sys::Function, reject: js_sys::Function| {
|
||||||
|
web_sys::window()
|
||||||
|
.unwrap()
|
||||||
|
.set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
let p = js_sys::Promise::new(&mut cb);
|
||||||
|
|
||||||
|
wasm_bindgen_futures::JsFuture::from(p).await.unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Ok(JsValue::from_bool(true))
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = wasm_bindgen_futures::future_to_promise(f);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,14 @@ impl Add<DeltaTime> for Time {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sub<DeltaTime> for Time {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, duration: DeltaTime) -> Self {
|
||||||
|
Time(self.0 - duration.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Mul<f32> for DeltaTime {
|
impl Mul<f32> for DeltaTime {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
|||||||
@@ -95,3 +95,39 @@ pub(super) fn merge_overlapping_intervals(mut intervals: Vec<Range<usize>>) -> V
|
|||||||
|
|
||||||
intervals
|
intervals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use wasm_bindgen::closure::{Closure, WasmClosureFnOnce};
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
/*
|
||||||
|
Execute a closure after some delay. This mimics the javascript built-in setTimeout procedure.
|
||||||
|
*/
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub(crate) fn set_timeout<F>(f: F, delay: i32)
|
||||||
|
where
|
||||||
|
F: 'static + FnOnce() -> (),
|
||||||
|
{
|
||||||
|
let timeout_id = Rc::new(Cell::new(0));
|
||||||
|
let t_id = timeout_id.clone();
|
||||||
|
let cb = Closure::once_into_js(move || {
|
||||||
|
f();
|
||||||
|
|
||||||
|
web_sys::window()
|
||||||
|
.unwrap()
|
||||||
|
.clear_timeout_with_handle(t_id.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
let window = web_sys::window().unwrap();
|
||||||
|
timeout_id.set(
|
||||||
|
window
|
||||||
|
.set_timeout_with_callback_and_timeout_and_arguments_0(
|
||||||
|
// Note this method call, which uses `as_ref()` to get a `JsValue`
|
||||||
|
// from our `Closure` which is then converted to a `&Function`
|
||||||
|
// using the `JsCast::unchecked_ref` function.
|
||||||
|
cb.unchecked_ref(),
|
||||||
|
delay,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
23
src/js/A.js
23
src/js/A.js
@@ -102,15 +102,11 @@ A.aladin = function (divSelector, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a HiPS image object
|
|
||||||
*
|
|
||||||
* @function
|
* @function
|
||||||
* @name A.imageHiPS
|
* @name A.imageHiPS
|
||||||
* @memberof A
|
* @memberof A
|
||||||
* @param {string} id - Can be either an `url` that refers to a HiPS.
|
* @deprecated
|
||||||
* 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}.
|
* Old method name, use {@link A.HiPS} instead.
|
||||||
* @param {HiPSOptions} [options] - Options describing the survey
|
|
||||||
* @returns {ImageHiPS} - A HiPS image object
|
|
||||||
*/
|
*/
|
||||||
A.imageHiPS = function (id, options) {
|
A.imageHiPS = function (id, options) {
|
||||||
let url = id;
|
let url = id;
|
||||||
@@ -124,6 +120,19 @@ A.imageHiPS = function (id, options) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HiPS image object
|
||||||
|
*
|
||||||
|
* @function
|
||||||
|
* @name A.HiPS
|
||||||
|
* @memberof A
|
||||||
|
* @param {string} id - Can be either 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 {HiPSOptions} [options] - Options describing the survey
|
||||||
|
* @returns {HiPS} - A HiPS image object
|
||||||
|
*/
|
||||||
|
A.HiPS = A.imageHiPS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a celestial source object with the given coordinates.
|
* Creates a celestial source object with the given coordinates.
|
||||||
*
|
*
|
||||||
@@ -273,7 +282,7 @@ A.circle = function (ra, dec, radiusDeg, options) {
|
|||||||
|
|
||||||
A.footprint = function(shapes) {
|
A.footprint = function(shapes) {
|
||||||
return new Footprint(shapes)
|
return new Footprint(shapes)
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an ellipse shape
|
* Creates an ellipse shape
|
||||||
|
|||||||
172
src/js/Aladin.js
172
src/js/Aladin.js
@@ -37,7 +37,7 @@ import { Sesame } from "./Sesame.js";
|
|||||||
import { PlanetaryFeaturesNameResolver } from "./PlanetaryFeaturesNameResolver.js";
|
import { PlanetaryFeaturesNameResolver } from "./PlanetaryFeaturesNameResolver.js";
|
||||||
import { CooFrameEnum } from "./CooFrameEnum.js";
|
import { CooFrameEnum } from "./CooFrameEnum.js";
|
||||||
import { MeasurementTable } from "./MeasurementTable.js";
|
import { MeasurementTable } from "./MeasurementTable.js";
|
||||||
import { ImageHiPS } from "./ImageHiPS.js";
|
import { HiPS } from "./HiPS.js";
|
||||||
import { Coo } from "./libs/astro/coo.js";
|
import { Coo } from "./libs/astro/coo.js";
|
||||||
import { CooConversion } from "./CooConversion.js";
|
import { CooConversion } from "./CooConversion.js";
|
||||||
import { HiPSCache } from "./HiPSCache.js";
|
import { HiPSCache } from "./HiPSCache.js";
|
||||||
@@ -79,7 +79,7 @@ import { Polyline } from "./shapes/Polyline";
|
|||||||
* @typedef {Object} AladinOptions
|
* @typedef {Object} AladinOptions
|
||||||
* @description Options for configuring the Aladin Lite instance.
|
* @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} [survey="P/DSS2/color"] URL or ID of the survey to use
|
||||||
* @property {string[]} [surveyUrl]
|
* @property {string[]} [surveyUrl]
|
||||||
* Array of URLs for the survey images. This replaces the survey parameter.
|
* Array of URLs for the survey images. This replaces the survey parameter.
|
||||||
* @property {Object[]|string[]} [hipsList] A list of predefined HiPS for the Aladin instance.
|
* @property {Object[]|string[]} [hipsList] A list of predefined HiPS for the Aladin instance.
|
||||||
@@ -160,7 +160,7 @@ import { Polyline } from "./shapes/Polyline";
|
|||||||
name: 'DESI Legacy Surveys color (g, r, i, z)',
|
name: 'DESI Legacy Surveys color (g, r, i, z)',
|
||||||
id: 'CDS/P/DESI-Legacy-Surveys/DR10/color',
|
id: 'CDS/P/DESI-Legacy-Surveys/DR10/color',
|
||||||
},
|
},
|
||||||
// HiPS with options. Fields accepted are those described in {@link A.imageHiPSOptions}.
|
// HiPS with options. Fields accepted are those described in {@link A.hiPSOptions}.
|
||||||
{
|
{
|
||||||
name: "SDSS9 band-g",
|
name: "SDSS9 band-g",
|
||||||
id: "P/SDSS9/g",
|
id: "P/SDSS9/g",
|
||||||
@@ -428,10 +428,11 @@ export let Aladin = (function () {
|
|||||||
|
|
||||||
// Merge what is already in the cache for that HiPS with new properties
|
// Merge what is already in the cache for that HiPS with new properties
|
||||||
// coming from the MOCServer
|
// coming from the MOCServer
|
||||||
let hips = new ImageHiPS(key, cachedSurvey.url, cachedSurvey)
|
let hips = new HiPS(key, key, cachedSurvey)
|
||||||
self.hipsCache.append(key, hips);
|
self.hipsCache.append(key, hips);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
this._setupUI(options);
|
||||||
|
|
||||||
fillHiPSCache();
|
fillHiPSCache();
|
||||||
|
|
||||||
@@ -446,10 +447,10 @@ export let Aladin = (function () {
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
});
|
});
|
||||||
} else if (options.survey === ImageHiPS.DEFAULT_SURVEY_ID) {
|
} else if (options.survey === HiPS.DEFAULT_SURVEY_ID) {
|
||||||
// DSS is cached inside ImageHiPS class, no need to provide any further information
|
// DSS is cached inside HiPS class, no need to provide any further information
|
||||||
const survey = this.createImageSurvey(
|
const survey = this.createImageSurvey(
|
||||||
ImageHiPS.DEFAULT_SURVEY_ID
|
HiPS.DEFAULT_SURVEY_ID
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setBaseImageLayer(survey);
|
this.setBaseImageLayer(survey);
|
||||||
@@ -528,9 +529,6 @@ export let Aladin = (function () {
|
|||||||
if (options.northPoleOrientation) {
|
if (options.northPoleOrientation) {
|
||||||
this.setViewCenter2NorthPoleAngle(options.northPoleOrientation);
|
this.setViewCenter2NorthPoleAngle(options.northPoleOrientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setupUI(options);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Aladin.prototype._setupUI = function (options) {
|
Aladin.prototype._setupUI = function (options) {
|
||||||
@@ -664,7 +662,7 @@ export let Aladin = (function () {
|
|||||||
// access to WASM libraries
|
// access to WASM libraries
|
||||||
Aladin.wasmLibs = {};
|
Aladin.wasmLibs = {};
|
||||||
Aladin.DEFAULT_OPTIONS = {
|
Aladin.DEFAULT_OPTIONS = {
|
||||||
survey: ImageHiPS.DEFAULT_SURVEY_ID,
|
survey: HiPS.DEFAULT_SURVEY_ID,
|
||||||
// surveys suggestion list
|
// surveys suggestion list
|
||||||
hipsList: HiPSList.DEFAULT,
|
hipsList: HiPSList.DEFAULT,
|
||||||
//surveyUrl: ["https://alaskybis.unistra.fr/DSS/DSSColor", "https://alasky.unistra.fr/DSS/DSSColor"],
|
//surveyUrl: ["https://alaskybis.unistra.fr/DSS/DSSColor", "https://alasky.unistra.fr/DSS/DSSColor"],
|
||||||
@@ -799,7 +797,7 @@ export let Aladin = (function () {
|
|||||||
var requestedSurveyId = Utils.urlParam("survey");
|
var requestedSurveyId = Utils.urlParam("survey");
|
||||||
if (
|
if (
|
||||||
requestedSurveyId &&
|
requestedSurveyId &&
|
||||||
ImageHiPS.getSurveyInfoFromId(requestedSurveyId)
|
HiPS.getSurveyInfoFromId(requestedSurveyId)
|
||||||
) {
|
) {
|
||||||
options.survey = requestedSurveyId;
|
options.survey = requestedSurveyId;
|
||||||
}
|
}
|
||||||
@@ -1431,13 +1429,17 @@ export let Aladin = (function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Aladin.prototype.addUI = function (ui) {
|
Aladin.prototype.addUI = function (ui) {
|
||||||
this.ui.push(ui);
|
ui = [].concat(ui);
|
||||||
ui.attachTo(this.aladinDiv);
|
|
||||||
|
|
||||||
// as the ui is pushed to the dom, setting position may need the aladin instance to work
|
for (var ui of ui) {
|
||||||
// so we recompute it
|
this.ui.push(ui);
|
||||||
if (ui.options) {
|
ui.attachTo(this.aladinDiv);
|
||||||
ui.update({ position: { ...ui.options.position, aladin: this } });
|
|
||||||
|
// as the ui is pushed to the dom, setting position may need the aladin instance to work
|
||||||
|
// so we recompute it
|
||||||
|
if (ui.options) {
|
||||||
|
ui.update({ position: { ...ui.options.position, aladin: this } });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1494,7 +1496,7 @@ export let Aladin = (function () {
|
|||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* Creates and return an image survey (HiPS) object
|
* Creates and return an image survey (HiPS) object
|
||||||
* Please use {@link A.imageHiPS} instead for creating a new survey image
|
* Please use {@link A.hiPS} instead for creating a new survey image
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string} id - Mandatory unique identifier for the survey.
|
* @param {string} id - Mandatory unique identifier for the survey.
|
||||||
@@ -1507,7 +1509,7 @@ export let Aladin = (function () {
|
|||||||
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
|
* @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 {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
|
||||||
* @param {HiPSOptions} [options] - Options describing the survey
|
* @param {HiPSOptions} [options] - Options describing the survey
|
||||||
* @returns {ImageHiPS} A HiPS image object.
|
* @returns {HiPS} A HiPS image object.
|
||||||
*/
|
*/
|
||||||
Aladin.prototype.createImageSurvey = function (
|
Aladin.prototype.createImageSurvey = function (
|
||||||
id,
|
id,
|
||||||
@@ -1517,25 +1519,12 @@ export let Aladin = (function () {
|
|||||||
maxOrder,
|
maxOrder,
|
||||||
options
|
options
|
||||||
) {
|
) {
|
||||||
/*let surveyOptions = HiPSCache.get(id);
|
let hips = new HiPS(id, url || id, { name, maxOrder, url, cooFrame, ...options })
|
||||||
|
|
||||||
if (!surveyOptions) {
|
|
||||||
surveyOptions = { name, maxOrder, cooFrame, ...options };
|
|
||||||
surveyOptions.url = url;
|
|
||||||
} else {
|
|
||||||
// update the cached survey
|
|
||||||
surveyOptions = {...surveyOptions, ...options};
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*let hips = this.hipsCache.get(id);
|
|
||||||
if (!hips) {
|
|
||||||
options = { name, maxOrder, url, cooFrame, ...options };
|
|
||||||
hips = new ImageHiPS(id, options.url, options)
|
|
||||||
this.hipsCache.append(id, hips);
|
|
||||||
} */
|
|
||||||
|
|
||||||
let hips = new ImageHiPS(id, url, { name, maxOrder, url, cooFrame, ...options })
|
|
||||||
|
|
||||||
|
if (this instanceof Aladin && !this.hipsCache.contains(id)) {
|
||||||
|
// Add it to the cache as soon as possible if we have a reference to the aladin object
|
||||||
|
this.hipsCache.append(hips.id, hips)
|
||||||
|
}
|
||||||
|
|
||||||
return hips;
|
return hips;
|
||||||
};
|
};
|
||||||
@@ -1543,7 +1532,7 @@ export let Aladin = (function () {
|
|||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* Creates and return an image survey (HiPS) object.
|
* Creates and return an image survey (HiPS) object.
|
||||||
* Please use {@link A.imageHiPS} instead for creating a new survey image
|
* Please use {@link A.hiPS} instead for creating a new survey image
|
||||||
*
|
*
|
||||||
* @function createImageSurvey
|
* @function createImageSurvey
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
@@ -1558,7 +1547,7 @@ export let Aladin = (function () {
|
|||||||
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
|
* @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 {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
|
||||||
* @param {HiPSOptions} [options] - Options describing the survey
|
* @param {HiPSOptions} [options] - Options describing the survey
|
||||||
* @returns {ImageHiPS} A HiPS image object.
|
* @returns {HiPS} A HiPS image object.
|
||||||
*/
|
*/
|
||||||
Aladin.createImageSurvey = Aladin.prototype.createImageSurvey;
|
Aladin.createImageSurvey = Aladin.prototype.createImageSurvey;
|
||||||
|
|
||||||
@@ -1568,11 +1557,11 @@ export let Aladin = (function () {
|
|||||||
* @throws A warning when the asset is currently present in the view
|
* @throws A warning when the asset is currently present in the view
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string|ImageHiPS|Image} urlOrHiPSOrFITS - Can be:
|
* @param {string|HiPS|Image} urlOrHiPSOrFITS - Can be:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>1. An url that refers to a HiPS</li>
|
* <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>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 ImageHiPS} HiPS object created from {@link A.imageHiPS}</li>
|
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||||
* <li>4. A {@link Image} FITS image object</li>
|
* <li>4. A {@link Image} FITS image object</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@@ -1593,11 +1582,11 @@ export let Aladin = (function () {
|
|||||||
* Check whether a survey is currently in the view
|
* Check whether a survey is currently in the view
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string|ImageHiPS|Image} urlOrHiPSOrFITS - Can be:
|
* @param {string|HiPS|Image} urlOrHiPSOrFITS - Can be:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>1. An url that refers to a HiPS</li>
|
* <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>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 ImageHiPS} HiPS object created from {@link A.imageHiPS}</li>
|
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||||
* <li>4. A {@link Image} Image object</li>
|
* <li>4. A {@link Image} Image object</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@@ -1637,12 +1626,6 @@ export let Aladin = (function () {
|
|||||||
// Do not use proxy with CORS headers until we solve that: https://github.com/MattiasBuelens/wasm-streams/issues/20
|
// Do not use proxy with CORS headers until we solve that: https://github.com/MattiasBuelens/wasm-streams/issues/20
|
||||||
//url = Utils.handleCORSNotSameOrigin(url).href;
|
//url = Utils.handleCORSNotSameOrigin(url).href;
|
||||||
|
|
||||||
/*let image = this.hipsCache.get(url);
|
|
||||||
if (!image) {
|
|
||||||
options = { successCallback, errorCallback, ...options };
|
|
||||||
image = new Image(url, options);
|
|
||||||
this.hipsCache.append(url, image);
|
|
||||||
}*/
|
|
||||||
let image = new Image(url, {...options, successCallback, errorCallback});
|
let image = new Image(url, {...options, successCallback, errorCallback});
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
@@ -1666,7 +1649,7 @@ export let Aladin = (function () {
|
|||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* Create a new layer from an url or CDS ID.
|
* Create a new layer from an url or CDS ID.
|
||||||
* Please use {@link A.imageHiPS} instead for creating a new survey image
|
* Please use {@link A.hiPS} instead for creating a new survey image
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @static
|
* @static
|
||||||
@@ -1678,25 +1661,32 @@ export let Aladin = (function () {
|
|||||||
* @param {HiPSOptions} [options] - Options for rendering the image
|
* @param {HiPSOptions} [options] - Options for rendering the image
|
||||||
* @param {function} [success] - A success callback
|
* @param {function} [success] - A success callback
|
||||||
* @param {function} [error] - A success callback
|
* @param {function} [error] - A success callback
|
||||||
* @returns {ImageHiPS} A FITS image object.
|
* @returns {HiPS} A FITS image object.
|
||||||
*/
|
*/
|
||||||
Aladin.prototype.newImageSurvey = function (id, options) {
|
Aladin.prototype.newImageSurvey = function (id, options) {
|
||||||
return A.imageHiPS(id, options);
|
// a wrapper on createImageSurvey that aggregates all params in an options object
|
||||||
|
return this.createImageSurvey(id,
|
||||||
|
options && options.name,
|
||||||
|
id,
|
||||||
|
options && options.cooFrame,
|
||||||
|
options && options.maxOrder,
|
||||||
|
options
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new HiPS layer to the view on top of the others
|
* Add a new HiPS layer to the view on top of the others
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string|ImageHiPS|Image} [survey="CDS/P/DSS2/color"] - Can be:
|
* @param {string|HiPS|Image} [survey="P/DSS2/color"] - Can be:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>1. An url that refers to a HiPS.</li>
|
* <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>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 A.ImageHiPS} HiPS object created from {@link A.imageHiPS}</li>
|
* <li>3. It can also be an {@link A.HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* By default, the {@link https://alasky.cds.unistra.fr/DSS/DSSColor/|Digital Sky Survey 2} survey will be displayed
|
* 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 (survey = "P/DSS2/color") {
|
||||||
let layerName = Utils.uuidv4();
|
let layerName = Utils.uuidv4();
|
||||||
return this.setOverlayImageLayer(survey, layerName);
|
return this.setOverlayImageLayer(survey, layerName);
|
||||||
};
|
};
|
||||||
@@ -1704,14 +1694,14 @@ export let Aladin = (function () {
|
|||||||
/**
|
/**
|
||||||
* Change the base layer of the view
|
* Change the base layer of the view
|
||||||
*
|
*
|
||||||
* It internally calls {@link Aladin#setBaseImageLayer|Aladin.setBaseImageLayer} with the url/{@link ImageHiPS}/{@link Image} given
|
* It internally calls {@link Aladin#setBaseImageLayer|Aladin.setBaseImageLayer} with the url/{@link HiPS}/{@link Image} given
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string|ImageHiPS|Image} urlOrHiPSOrFITS - Can be:
|
* @param {string|HiPS|Image} urlOrHiPSOrFITS - Can be:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>1. An url that refers to a HiPS.</li>
|
* <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>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 ImageHiPS} HiPS object created from {@link A.imageHiPS}</li>
|
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||||
* <li>4. A {@link Image} FITS image object</li>
|
* <li>4. A {@link Image} FITS image object</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@@ -1722,14 +1712,14 @@ export let Aladin = (function () {
|
|||||||
/**
|
/**
|
||||||
* Change the base layer of the view
|
* Change the base layer of the view
|
||||||
*
|
*
|
||||||
* It internally calls {@link Aladin#setBaseImageLayer|Aladin.setBaseImageLayer} with the url/{@link ImageHiPS}/{@link Image} given
|
* It internally calls {@link Aladin#setBaseImageLayer|Aladin.setBaseImageLayer} with the url/{@link HiPS}/{@link Image} given
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string|ImageHiPS|Image} urlOrHiPSOrFITS - Can be:
|
* @param {string|HiPS|Image} urlOrHiPSOrFITS - Can be:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>1. An url that refers to a HiPS.</li>
|
* <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>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 ImageHiPS} HiPS object created from {@link A.imageHiPS}</li>
|
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||||
* <li>4. A {@link Image} FITS image object</li>
|
* <li>4. A {@link Image} FITS image object</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@@ -1770,11 +1760,11 @@ export let Aladin = (function () {
|
|||||||
* Change the base layer of the view
|
* Change the base layer of the view
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string|ImageHiPS|Image} urlOrHiPSOrFITS - Can be:
|
* @param {string|HiPS|Image} urlOrHiPSOrFITS - Can be:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>1. An url that refers to a HiPS.</li>
|
* <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>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 ImageHiPS} HiPS object created from {@link A.imageHiPS}</li>
|
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||||
* <li>4. A {@link Image} FITS image object</li>
|
* <li>4. A {@link Image} FITS image object</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@@ -1786,7 +1776,7 @@ export let Aladin = (function () {
|
|||||||
* Get the base image layer object
|
* Get the base image layer object
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @returns {ImageHiPS|Image} - Returns the image layer corresponding to the base layer
|
* @returns {HiPS|Image} - Returns the image layer corresponding to the base layer
|
||||||
*/
|
*/
|
||||||
Aladin.prototype.getBaseImageLayer = function () {
|
Aladin.prototype.getBaseImageLayer = function () {
|
||||||
return this.view.getImageLayer("base");
|
return this.view.getImageLayer("base");
|
||||||
@@ -1796,11 +1786,11 @@ export let Aladin = (function () {
|
|||||||
* Add a new HiPS/FITS image layer in the view
|
* Add a new HiPS/FITS image layer in the view
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string|ImageHiPS|Image} urlOrHiPSOrFITS - Can be:
|
* @param {string|HiPS|Image} urlOrHiPSOrFITS - Can be:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>1. An url that refers to a HiPS.</li>
|
* <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>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 ImageHiPS} HiPS object created from {@link A.imageHiPS}</li>
|
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||||
* <li>4. A {@link Image} FITS/jped/png image</li>
|
* <li>4. A {@link Image} FITS/jped/png image</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* @param {string} [layer="overlay"] - A layer name. By default 'overlay' is chosen and it is destined to be plot
|
* @param {string} [layer="overlay"] - A layer name. By default 'overlay' is chosen and it is destined to be plot
|
||||||
@@ -1811,29 +1801,37 @@ export let Aladin = (function () {
|
|||||||
layer = "overlay"
|
layer = "overlay"
|
||||||
) {
|
) {
|
||||||
let imageLayer;
|
let imageLayer;
|
||||||
|
|
||||||
|
let hipsCache = this.hipsCache;
|
||||||
// 1. User gives an ID
|
// 1. User gives an ID
|
||||||
if (typeof urlOrHiPSOrFITS === "string") {
|
if (typeof urlOrHiPSOrFITS === "string") {
|
||||||
const idOrUrl = urlOrHiPSOrFITS;
|
const idOrUrl = urlOrHiPSOrFITS;
|
||||||
|
// many cases here
|
||||||
imageLayer = A.imageHiPS(idOrUrl);
|
// 1/ It has been already added to the cache
|
||||||
// 2. User gives a non resolved promise
|
let cachedLayer = hipsCache.get(idOrUrl)
|
||||||
|
if (cachedLayer) {
|
||||||
|
imageLayer = cachedLayer
|
||||||
|
} else {
|
||||||
|
// 2/ Not in the cache, then we create the hips from this url/id and
|
||||||
|
// go to the case 3
|
||||||
|
imageLayer = A.HiPS(idOrUrl);
|
||||||
|
return this.setOverlayImageLayer(imageLayer, layer);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 3/ It is an image survey.
|
||||||
imageLayer = urlOrHiPSOrFITS;
|
imageLayer = urlOrHiPSOrFITS;
|
||||||
|
|
||||||
|
let cachedLayer = hipsCache.get(imageLayer.id)
|
||||||
|
if (!cachedLayer) {
|
||||||
|
hipsCache.append(imageLayer.id, imageLayer)
|
||||||
|
} else {
|
||||||
|
// first set the options of the cached layer to the one of the user
|
||||||
|
cachedLayer.setOptions(imageLayer.options)
|
||||||
|
// if it is in the cache we get it from the cache
|
||||||
|
imageLayer = cachedLayer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let hipsCache = this.hipsCache;
|
|
||||||
let cachedLayer = hipsCache.get(imageLayer.id)
|
|
||||||
if (cachedLayer && !cachedLayer.added) {
|
|
||||||
imageLayer = cachedLayer
|
|
||||||
} else {
|
|
||||||
this.hipsCache.append(imageLayer.id, imageLayer);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log("cached layer", hipsCache)
|
|
||||||
|
|
||||||
|
|
||||||
return this.view.setOverlayImageLayer(imageLayer, layer);
|
return this.view.setOverlayImageLayer(imageLayer, layer);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1843,7 +1841,7 @@ export let Aladin = (function () {
|
|||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @param {string} [layer="overlay"] - The name of the layer
|
* @param {string} [layer="overlay"] - The name of the layer
|
||||||
|
|
||||||
* @returns {ImageHiPS|Image} - The requested image layer.
|
* @returns {HiPS|Image} - The requested image layer.
|
||||||
*/
|
*/
|
||||||
Aladin.prototype.getOverlayImageLayer = function (layer = "overlay") {
|
Aladin.prototype.getOverlayImageLayer = function (layer = "overlay") {
|
||||||
const survey = this.view.getImageLayer(layer);
|
const survey = this.view.getImageLayer(layer);
|
||||||
@@ -1896,7 +1894,7 @@ export let Aladin = (function () {
|
|||||||
* Get list of overlays layers
|
* Get list of overlays layers
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @returns {MOC[]|Catalog[]|ProgressiveCat[]|GraphicOverlay[]} - Returns the ordered list of image layers. Items can be {@link ImageHiPS} or {@link Image} objects.
|
* @returns {MOC[]|Catalog[]|ProgressiveCat[]|GraphicOverlay[]} - Returns the ordered list of image layers. Items can be {@link HiPS} or {@link Image} objects.
|
||||||
*/
|
*/
|
||||||
Aladin.prototype.getOverlays = function () {
|
Aladin.prototype.getOverlays = function () {
|
||||||
return this.view.allOverlayLayers;
|
return this.view.allOverlayLayers;
|
||||||
@@ -1906,7 +1904,7 @@ export let Aladin = (function () {
|
|||||||
* Get list of layers
|
* Get list of layers
|
||||||
*
|
*
|
||||||
* @memberof Aladin
|
* @memberof Aladin
|
||||||
* @returns {ImageHiPS[]|Image[]} - Returns the ordered list of image layers. Items can be {@link ImageHiPS} or {@link Image} objects.
|
* @returns {HiPS[]|Image[]} - Returns the ordered list of image layers. Items can be {@link HiPS} or {@link Image} objects.
|
||||||
*/
|
*/
|
||||||
Aladin.prototype.getStackLayers = function () {
|
Aladin.prototype.getStackLayers = function () {
|
||||||
return this.view.overlayLayers;
|
return this.view.overlayLayers;
|
||||||
|
|||||||
@@ -101,8 +101,28 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColorCfg.prototype.setOptions = function(options) {
|
||||||
|
if (options.colormap)
|
||||||
|
this.setColormap(options.colormap, options)
|
||||||
|
|
||||||
|
this.setCuts(options.minCut, options.maxCut)
|
||||||
|
|
||||||
|
this.setBrightness(options.brightness)
|
||||||
|
this.setSaturation(options.saturation)
|
||||||
|
this.setContrast(options.contrast)
|
||||||
|
|
||||||
|
this.setGamma(options.gamma)
|
||||||
|
|
||||||
|
this.setOpacity(options.opacity)
|
||||||
|
|
||||||
|
this.setBlendingConfig(options.additive)
|
||||||
|
}
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
ColorCfg.prototype.setBrightness = function(kBrightness) {
|
ColorCfg.prototype.setBrightness = function(kBrightness) {
|
||||||
|
if (kBrightness == null || kBrightness == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
kBrightness = +kBrightness || 0.0; // coerce to number
|
kBrightness = +kBrightness || 0.0; // coerce to number
|
||||||
this.kBrightness = Math.max(-1, Math.min(kBrightness, 1));
|
this.kBrightness = Math.max(-1, Math.min(kBrightness, 1));
|
||||||
};
|
};
|
||||||
@@ -114,6 +134,9 @@
|
|||||||
|
|
||||||
// @api
|
// @api
|
||||||
ColorCfg.prototype.setContrast = function(kContrast) {
|
ColorCfg.prototype.setContrast = function(kContrast) {
|
||||||
|
if (kContrast == null || kContrast == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
kContrast = +kContrast || 0.0; // coerce to number
|
kContrast = +kContrast || 0.0; // coerce to number
|
||||||
this.kContrast = Math.max(-1, Math.min(kContrast, 1));
|
this.kContrast = Math.max(-1, Math.min(kContrast, 1));
|
||||||
};
|
};
|
||||||
@@ -125,6 +148,9 @@
|
|||||||
|
|
||||||
// @api
|
// @api
|
||||||
ColorCfg.prototype.setSaturation = function(kSaturation) {
|
ColorCfg.prototype.setSaturation = function(kSaturation) {
|
||||||
|
if (kSaturation == null || kSaturation == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
kSaturation = +kSaturation || 0.0; // coerce to number
|
kSaturation = +kSaturation || 0.0; // coerce to number
|
||||||
|
|
||||||
this.kSaturation = Math.max(-1, Math.min(kSaturation, 1));
|
this.kSaturation = Math.max(-1, Math.min(kSaturation, 1));
|
||||||
@@ -137,6 +163,9 @@
|
|||||||
|
|
||||||
// @api
|
// @api
|
||||||
ColorCfg.prototype.setGamma = function(gamma) {
|
ColorCfg.prototype.setGamma = function(gamma) {
|
||||||
|
if (gamma == null || gamma == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
gamma = +gamma; // coerce to number
|
gamma = +gamma; // coerce to number
|
||||||
this.kGamma = Math.max(0.1, Math.min(gamma, 10));
|
this.kGamma = Math.max(0.1, Math.min(gamma, 10));
|
||||||
};
|
};
|
||||||
@@ -148,6 +177,9 @@
|
|||||||
|
|
||||||
// @api
|
// @api
|
||||||
ColorCfg.prototype.setOpacity = function(opacity) {
|
ColorCfg.prototype.setOpacity = function(opacity) {
|
||||||
|
if (opacity == null || opacity == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
opacity = +opacity; // coerce to number
|
opacity = +opacity; // coerce to number
|
||||||
this.opacity = Math.max(0, Math.min(opacity, 1));
|
this.opacity = Math.max(0, Math.min(opacity, 1));
|
||||||
};
|
};
|
||||||
@@ -164,7 +196,10 @@
|
|||||||
ColorCfg.prototype.getAlpha = ColorCfg.prototype.getOpacity;
|
ColorCfg.prototype.getAlpha = ColorCfg.prototype.getOpacity;
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
ColorCfg.prototype.setBlendingConfig = function(additive = false) {
|
ColorCfg.prototype.setBlendingConfig = function(additive) {
|
||||||
|
if (additive === null || additive === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
this.additiveBlending = additive;
|
this.additiveBlending = additive;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -189,6 +224,9 @@
|
|||||||
// @api
|
// @api
|
||||||
// Optional arguments,
|
// Optional arguments,
|
||||||
ColorCfg.prototype.setColormap = function(colormap = "native", options) {
|
ColorCfg.prototype.setColormap = function(colormap = "native", options) {
|
||||||
|
if (colormap == null || colormap == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
/// colormap
|
/// colormap
|
||||||
// Make it case insensitive
|
// Make it case insensitive
|
||||||
let cmap = formatColormap(colormap);
|
let cmap = formatColormap(colormap);
|
||||||
@@ -218,40 +256,18 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
ColorCfg.prototype.setCuts = function(lowCut, highCut) {
|
ColorCfg.prototype.setCuts = function(minCut, maxCut) {
|
||||||
this.minCut = lowCut;
|
if (minCut === null || minCut === undefined || maxCut === null || maxCut === undefined) {
|
||||||
this.maxCut = highCut;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.minCut = minCut;
|
||||||
|
this.maxCut = maxCut;
|
||||||
};
|
};
|
||||||
|
|
||||||
ColorCfg.prototype.getCuts = function() {
|
ColorCfg.prototype.getCuts = function() {
|
||||||
return [this.minCut, this.maxCut];
|
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"
|
|
||||||
];*/
|
|
||||||
|
|
||||||
return ColorCfg;
|
return ColorCfg;
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -5,26 +5,27 @@ export let HiPSList = (function () {
|
|||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/DSS2/color",
|
creatorDid: "ivo://CDS/P/DSS2/color",
|
||||||
name: "DSS colored",
|
name: "DSS colored",
|
||||||
id: "CDS/P/DSS2/color",
|
id: "P/DSS2/color",
|
||||||
maxOrder: 9,
|
maxOrder: 9,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "ICRS",
|
cooFrame: "ICRS",
|
||||||
startingUrl: "https://alasky.cds.unistra.fr/DSS/DSSColor/",
|
startUrl: "https://alasky.cds.unistra.fr/DSS/DSSColor",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/2MASS/color",
|
creatorDid: "ivo://CDS/P/2MASS/color",
|
||||||
name: "2MASS colored",
|
name: "2MASS colored",
|
||||||
id: "CDS/P/2MASS/color",
|
id: "P/2MASS/color",
|
||||||
maxOrder: 9,
|
maxOrder: 9,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "ICRS",
|
cooFrame: "ICRS",
|
||||||
|
startUrl: "https://alaskybis.cds.unistra.fr/2MASS/Color",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/DSS2/red",
|
creatorDid: "ivo://CDS/P/DSS2/red",
|
||||||
name: "DSS2 Red (F+R)",
|
name: "DSS2 Red (F+R)",
|
||||||
id: "CDS/P/DSS2/red",
|
id: "P/DSS2/red",
|
||||||
maxOrder: 9,
|
maxOrder: 9,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "fits",
|
imgFormat: "fits",
|
||||||
@@ -36,11 +37,12 @@ export let HiPSList = (function () {
|
|||||||
colormap: "magma",
|
colormap: "magma",
|
||||||
stretch: "Linear",
|
stretch: "Linear",
|
||||||
imgFormat: "fits",
|
imgFormat: "fits",
|
||||||
|
startUrl: "https://alaskybis.cds.unistra.fr/DSS/DSS2Merged",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/DM/I/350/gaiaedr3",
|
creatorDid: "ivo://CDS/P/DM/I/350/gaiaedr3",
|
||||||
name: "Density map for Gaia EDR3 (I/350/gaiaedr3)",
|
name: "Density map for Gaia EDR3 (I/350/gaiaedr3)",
|
||||||
id: "CDS/P/DM/I/350/gaiaedr3",
|
id: "P/DM/I/350/gaiaedr3",
|
||||||
maxOrder: 7,
|
maxOrder: 7,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
numBitsPerPixel: -32,
|
numBitsPerPixel: -32,
|
||||||
@@ -50,11 +52,12 @@ export let HiPSList = (function () {
|
|||||||
stretch: "asinh",
|
stretch: "asinh",
|
||||||
colormap: "rdylbu",
|
colormap: "rdylbu",
|
||||||
imgFormat: "fits",
|
imgFormat: "fits",
|
||||||
|
startUrl: "https://alaskybis.cds.unistra.fr/ancillary/GaiaEDR3/density-map",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/PanSTARRS/DR1/g",
|
creatorDid: "ivo://CDS/P/PanSTARRS/DR1/g",
|
||||||
name: "PanSTARRS DR1 g",
|
name: "PanSTARRS DR1 g",
|
||||||
id: "CDS/P/PanSTARRS/DR1/g",
|
id: "P/PanSTARRS/DR1/g",
|
||||||
maxOrder: 11,
|
maxOrder: 11,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "fits",
|
imgFormat: "fits",
|
||||||
@@ -65,33 +68,37 @@ export let HiPSList = (function () {
|
|||||||
maxCut: 7000,
|
maxCut: 7000,
|
||||||
stretch: "asinh",
|
stretch: "asinh",
|
||||||
colormap: "redtemperature",
|
colormap: "redtemperature",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/Pan-STARRS/DR1/g"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/PanSTARRS/DR1/color-z-zg-g",
|
creatorDid: "ivo://CDS/P/PanSTARRS/DR1/color-z-zg-g",
|
||||||
name: "PanSTARRS DR1 color",
|
name: "PanSTARRS DR1 color",
|
||||||
id: "CDS/P/PanSTARRS/DR1/color-z-zg-g",
|
id: "P/PanSTARRS/DR1/color-z-zg-g",
|
||||||
maxOrder: 11,
|
maxOrder: 11,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "ICRS",
|
cooFrame: "ICRS",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/Pan-STARRS/DR1/color-z-zg-g",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/DECaPS/DR2/color",
|
creatorDid: "ivo://CDS/P/DECaPS/DR2/color",
|
||||||
name: "DECaPS DR2 color",
|
name: "DECaPS DR2 color",
|
||||||
id: "CDS/P/DECaPS/DR2/color",
|
id: "P/DECaPS/DR2/color",
|
||||||
maxOrder: 11,
|
maxOrder: 11,
|
||||||
cooFrame: "equatorial",
|
cooFrame: "equatorial",
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "png",
|
imgFormat: "png",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/DECaPS/DR2/CDS_P_DECaPS_DR2_color"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/Fermi/color",
|
creatorDid: "ivo://CDS/P/Fermi/color",
|
||||||
name: "Fermi color",
|
name: "Fermi color",
|
||||||
id: "CDS/P/Fermi/color",
|
id: "P/Fermi/color",
|
||||||
maxOrder: 3,
|
maxOrder: 3,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
cooFrame: "equatorial",
|
cooFrame: "equatorial",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/Fermi/Color",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/GALEXGR6_7/NUV",
|
creatorDid: "ivo://CDS/P/GALEXGR6_7/NUV",
|
||||||
@@ -101,56 +108,61 @@ export let HiPSList = (function () {
|
|||||||
imgFormat: "png",
|
imgFormat: "png",
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
cooFrame: "equatorial",
|
cooFrame: "equatorial",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/GALEX/GALEXGR6_7_NUV"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/IRIS/color",
|
creatorDid: "ivo://CDS/P/IRIS/color",
|
||||||
id: "CDS/P/IRIS/color",
|
id: "P/IRIS/color",
|
||||||
name: "IRIS colored",
|
name: "IRIS colored",
|
||||||
maxOrder: 3,
|
maxOrder: 3,
|
||||||
tileSize: 256,
|
tileSize: 256,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "galactic",
|
cooFrame: "galactic",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/IRISColor",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/Mellinger/color",
|
creatorDid: "ivo://CDS/P/Mellinger/color",
|
||||||
id: "CDS/P/Mellinger/color",
|
id: "P/Mellinger/color",
|
||||||
name: "Mellinger colored",
|
name: "Mellinger colored",
|
||||||
maxOrder: 4,
|
maxOrder: 4,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "galactic",
|
cooFrame: "galactic",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/MellingerRGB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/SDSS9/color",
|
creatorDid: "ivo://CDS/P/SDSS9/color",
|
||||||
id: "CDS/P/SDSS9/color",
|
id: "P/SDSS9/color",
|
||||||
name: "SDSS9 colored",
|
name: "SDSS9 colored",
|
||||||
maxOrder: 10,
|
maxOrder: 10,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "equatorial",
|
cooFrame: "equatorial",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/SDSS/DR9/color"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/SPITZER/color",
|
creatorDid: "ivo://CDS/P/SPITZER/color",
|
||||||
id: "CDS/P/SPITZER/color",
|
id: "P/SPITZER/color",
|
||||||
name: "IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)",
|
name: "IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)",
|
||||||
maxOrder: 9,
|
maxOrder: 9,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "galactic",
|
cooFrame: "galactic",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/Spitzer/SpitzerI1I2I4color"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/allWISE/color",
|
creatorDid: "ivo://CDS/P/allWISE/color",
|
||||||
id: "CDS/P/allWISE/color",
|
id: "P/SDSS9/g",
|
||||||
name: "AllWISE color",
|
name: "AllWISE color",
|
||||||
maxOrder: 8,
|
maxOrder: 8,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
cooFrame: "equatorial",
|
cooFrame: "equatorial",
|
||||||
startingUrl: "https://alasky.cds.unistra.fr/DSS/DSSColor/"
|
startUrl: "https://alaskybis.cds.unistra.fr/AllWISE/RGB-W4-W2-W1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
creatorDid: "ivo://CDS/P/SDSS9/g",
|
creatorDid: "ivo://CDS/P/SDSS9/g",
|
||||||
id: "CDS/P/SDSS9/g",
|
id: "P/SDSS9/g",
|
||||||
name: "SDSS9 band-g",
|
name: "SDSS9 band-g",
|
||||||
maxOrder: 10,
|
maxOrder: 10,
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
@@ -161,45 +173,36 @@ export let HiPSList = (function () {
|
|||||||
maxCut: 1.8,
|
maxCut: 1.8,
|
||||||
stretch: "linear",
|
stretch: "linear",
|
||||||
colormap: "redtemperature",
|
colormap: "redtemperature",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/SDSS/DR9/band-g"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "CDS/P/Finkbeiner",
|
id: "P/Finkbeiner",
|
||||||
name: "Halpha",
|
name: "Halpha",
|
||||||
maxOrder: 3,
|
maxOrder: 3,
|
||||||
minCut: -10,
|
minCut: -10,
|
||||||
maxCut: 800,
|
maxCut: 800,
|
||||||
colormap: "rdbu",
|
colormap: "rdbu",
|
||||||
imgFormat: "fits",
|
imgFormat: "fits",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/FinkbeinerHalpha"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "CDS/P/VTSS/Ha",
|
id: "P/VTSS/Ha",
|
||||||
name: "VTSS-Ha",
|
name: "VTSS-Ha",
|
||||||
maxOrder: 3,
|
maxOrder: 3,
|
||||||
minCut: -10.0,
|
minCut: -10.0,
|
||||||
maxCut: 100.0,
|
maxCut: 100.0,
|
||||||
colormap: "grayscale",
|
colormap: "grayscale",
|
||||||
imgFormat: "fits",
|
imgFormat: "fits",
|
||||||
|
startUrl: "https://alasky.cds.unistra.fr/VTSS/Ha"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "xcatdb/P/XMM/PN/color",
|
id: "P/GLIMPSE360",
|
||||||
name: "XMM PN colored",
|
|
||||||
maxOrder: 7,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "CDS/P/allWISE/color",
|
|
||||||
name: "AllWISE color",
|
|
||||||
maxOrder: 8,
|
|
||||||
},
|
|
||||||
/*{
|
|
||||||
id: "CDS/P/GLIMPSE360",
|
|
||||||
name: "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",
|
|
||||||
maxOrder: 9,
|
maxOrder: 9,
|
||||||
imgFormat: "jpeg",
|
imgFormat: "jpeg",
|
||||||
minOrder: 3,
|
minOrder: 3,
|
||||||
}*/
|
startUrl: "https://alasky.cds.unistra.fr/IPAC/IPAC_P_GLIMPSE360",
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return HiPSList;
|
return HiPSList;
|
||||||
|
|||||||
873
src/js/HiPS.js
Normal file
873
src/js/HiPS.js
Normal file
@@ -0,0 +1,873 @@
|
|||||||
|
// 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 HiPS
|
||||||
|
*
|
||||||
|
* Authors: Thomas Boch & Matthieu Baumann [CDS]
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
import { ALEvent } from "./events/ALEvent.js";
|
||||||
|
import { ColorCfg } from "./ColorCfg.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;
|
||||||
|
|
||||||
|
// Check if the tile width size is a power of 2
|
||||||
|
if (tileSize & (tileSize - 1 !== 0)) {
|
||||||
|
tileSize = 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tileSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Mandatory frame property
|
||||||
|
PropertyParser.cooFrame = function (properties) {
|
||||||
|
let cooFrame =
|
||||||
|
(properties && properties.hips_body && "ICRSd") ||
|
||||||
|
(properties && properties.hips_frame) ||
|
||||||
|
"ICRS";
|
||||||
|
return cooFrame;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Mandatory maxOrder property
|
||||||
|
PropertyParser.maxOrder = function (properties) {
|
||||||
|
let maxOrder =
|
||||||
|
properties && 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;
|
||||||
|
return minOrder;
|
||||||
|
};
|
||||||
|
|
||||||
|
PropertyParser.formats = function (properties) {
|
||||||
|
let formats = (properties && properties.hips_tile_format) || "jpeg";
|
||||||
|
|
||||||
|
formats = formats.split(" ").map((fmt) => fmt.toLowerCase());
|
||||||
|
|
||||||
|
return formats;
|
||||||
|
};
|
||||||
|
|
||||||
|
PropertyParser.initialFov = function (properties) {
|
||||||
|
let initialFov =
|
||||||
|
properties &&
|
||||||
|
properties.hips_initial_fov &&
|
||||||
|
+properties.hips_initial_fov;
|
||||||
|
|
||||||
|
if (initialFov && initialFov < 0.00002777777) {
|
||||||
|
initialFov = 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
return initialFov;
|
||||||
|
};
|
||||||
|
|
||||||
|
PropertyParser.skyFraction = function (properties) {
|
||||||
|
const skyFraction =
|
||||||
|
(properties &&
|
||||||
|
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(" ");
|
||||||
|
|
||||||
|
const minCutout = cuts && parseFloat(cuts[0]);
|
||||||
|
const maxCutout = cuts && parseFloat(cuts[1]);
|
||||||
|
|
||||||
|
return [minCutout, maxCutout];
|
||||||
|
};
|
||||||
|
|
||||||
|
PropertyParser.bitpix = function (properties) {
|
||||||
|
const bitpix =
|
||||||
|
properties &&
|
||||||
|
properties.hips_pixel_bitpix &&
|
||||||
|
+properties.hips_pixel_bitpix;
|
||||||
|
return bitpix;
|
||||||
|
};
|
||||||
|
|
||||||
|
PropertyParser.isPlanetaryBody = function (properties) {
|
||||||
|
return properties && properties.hips_body !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} HiPSOptions
|
||||||
|
*
|
||||||
|
* @property {string} [name] - The name of the survey to be displayed in the UI
|
||||||
|
* @property {Function} [successCallback] - A callback executed when the HiPS has been loaded
|
||||||
|
* @property {Function} [errorCallback] - A callback executed when the HiPS could not be loaded
|
||||||
|
* @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} [minOrder] - If not given, retrieved from the properties of the survey.
|
||||||
|
* @property {boolean} [longitudeReversed=false] - Set it to True for planetary survey visualization
|
||||||
|
* @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.
|
||||||
|
* @property {boolean} [reversed=false] - If true, the colormap is reversed; otherwise, it is not reversed.
|
||||||
|
* @property {number} [minCut] - The minimum cut value for the color configuration. If not given, 0.0 for JPEG/PNG surveys, the value of the property file for FITS surveys
|
||||||
|
* @property {number} [maxCut] - The maximum cut value for the color configuration. If not given, 1.0 for JPEG/PNG surveys, the value of the property file for FITS surveys
|
||||||
|
* @property {boolean} [additive=false] - If true, additive blending is applied; otherwise, it is not applied.
|
||||||
|
* @property {number} [gamma=1.0] - The gamma correction value for the color configuration.
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
export let HiPS = (function () {
|
||||||
|
/**
|
||||||
|
* The object describing an image survey
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @constructs HiPS
|
||||||
|
*
|
||||||
|
* @param {string} id - Mandatory unique identifier for the layer. Can be an arbitrary name
|
||||||
|
* @param {string} location - Can be:
|
||||||
|
* - an http url <br/>
|
||||||
|
* - a relative path to your HiPS <br/>
|
||||||
|
* - a special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}
|
||||||
|
* @param {HiPSOptions} [options] - The option for the survey
|
||||||
|
*
|
||||||
|
* @description Giving a CDS ID will do a query to the MOCServer first to retrieve metadata. Then it will also check for the presence of faster HiPS nodes to choose a faster url to query to tiles from.
|
||||||
|
*/
|
||||||
|
function HiPS(id, location, options) {
|
||||||
|
this.added = false;
|
||||||
|
// Unique identifier for a survey
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
this.name = (options && options.name) || undefined;
|
||||||
|
this.startUrl = options.startUrl;
|
||||||
|
|
||||||
|
this.url = location;
|
||||||
|
this.maxOrder = options.maxOrder;
|
||||||
|
this.minOrder = options.minOrder || 0;
|
||||||
|
this.cooFrame = options.cooFrame;
|
||||||
|
this.tileSize = options.tileSize;
|
||||||
|
this.skyFraction = options.skyFraction;
|
||||||
|
this.longitudeReversed =
|
||||||
|
options.longitudeReversed === undefined
|
||||||
|
? false
|
||||||
|
: options.longitudeReversed;
|
||||||
|
this.imgFormat = options.imgFormat;
|
||||||
|
this.formats = options.formats;
|
||||||
|
this.defaultFitsMinCut = options.defaultFitsMinCut;
|
||||||
|
this.defaultFitsMaxCut = options.defaultFitsMaxCut;
|
||||||
|
this.numBitsPerPixel = options.numBitsPerPixel;
|
||||||
|
this.creatorDid = options.creatorDid;
|
||||||
|
this.errorCallback = options.errorCallback;
|
||||||
|
this.successCallback = options.successCallback;
|
||||||
|
|
||||||
|
this.colorCfg = new ColorCfg(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
HiPS.prototype._fetchFasterUrlFromProperties = function(properties) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
HiPSProperties.getFasterMirrorUrl(properties)
|
||||||
|
.then((url) => {
|
||||||
|
if (self.url !== url) {
|
||||||
|
console.info(
|
||||||
|
"Change url of ",
|
||||||
|
self.id,
|
||||||
|
" to ",
|
||||||
|
url
|
||||||
|
);
|
||||||
|
|
||||||
|
self.url = 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error(self);
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HiPS.prototype._parseProperties = function(properties) {
|
||||||
|
let self = this;
|
||||||
|
self.creatorDid = properties.creator_did || self.creatorDid;
|
||||||
|
// url
|
||||||
|
|
||||||
|
// Max order
|
||||||
|
self.maxOrder =
|
||||||
|
PropertyParser.maxOrder(properties) || self.maxOrder;
|
||||||
|
|
||||||
|
// Tile size
|
||||||
|
self.tileSize =
|
||||||
|
PropertyParser.tileSize(properties) || self.tileSize;
|
||||||
|
|
||||||
|
// Tile formats
|
||||||
|
self.formats =
|
||||||
|
PropertyParser.formats(properties) || self.formats;
|
||||||
|
|
||||||
|
// min order
|
||||||
|
self.minOrder =
|
||||||
|
PropertyParser.minOrder(properties) || self.minOrder;
|
||||||
|
|
||||||
|
// Frame
|
||||||
|
self.cooFrame =
|
||||||
|
PropertyParser.cooFrame(properties) || self.cooFrame;
|
||||||
|
|
||||||
|
// sky fraction
|
||||||
|
self.skyFraction = PropertyParser.skyFraction(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;
|
||||||
|
|
||||||
|
// Cutouts
|
||||||
|
const cutoutFromProperties = PropertyParser.cutouts(properties);
|
||||||
|
self.defaultFitsMinCut = cutoutFromProperties[0];
|
||||||
|
self.defaultFitsMaxCut = cutoutFromProperties[1];
|
||||||
|
|
||||||
|
// Bitpix
|
||||||
|
self.numBitsPerPixel =
|
||||||
|
PropertyParser.bitpix(properties) || self.numBitsPerPixel;
|
||||||
|
|
||||||
|
// HiPS body
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give a better name if we have the HiPS metadata
|
||||||
|
self.name = self.name || properties.obs_title;
|
||||||
|
|
||||||
|
self.name = self.name || self.id || self.url;
|
||||||
|
self.name = self.name.replace(/ +/g, ' ');
|
||||||
|
|
||||||
|
self.creatorDid = self.creatorDid || self.id || self.url;
|
||||||
|
|
||||||
|
// Image format
|
||||||
|
if (self.imgFormat) {
|
||||||
|
// transform to lower case
|
||||||
|
self.imgFormat = self.imgFormat.toLowerCase();
|
||||||
|
// convert JPG -> JPEG
|
||||||
|
if (self.imgFormat === "jpg") {
|
||||||
|
self.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
|
||||||
|
) {
|
||||||
|
throw self.name + " does not provide fits tiles";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.imgFormat === "webp" &&
|
||||||
|
self.formats &&
|
||||||
|
self.formats.indexOf("webp") < 0
|
||||||
|
) {
|
||||||
|
throw self.name + " does not provide webp tiles";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.imgFormat === "png" &&
|
||||||
|
self.formats &&
|
||||||
|
self.formats.indexOf("png") < 0
|
||||||
|
) {
|
||||||
|
throw self.name + " does not provide png tiles";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.imgFormat === "jpeg" &&
|
||||||
|
self.formats &&
|
||||||
|
self.formats.indexOf("jpeg") < 0
|
||||||
|
) {
|
||||||
|
throw self.name + " does not provide jpeg tiles";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// user wants nothing then we choose one from the properties
|
||||||
|
if (self.formats.indexOf("webp") >= 0) {
|
||||||
|
self.imgFormat = "webp";
|
||||||
|
} else if (self.formats.indexOf("png") >= 0) {
|
||||||
|
self.imgFormat = "png";
|
||||||
|
} else if (self.formats.indexOf("jpeg") >= 0) {
|
||||||
|
self.imgFormat = "jpeg";
|
||||||
|
} else if (self.formats.indexOf("fits") >= 0) {
|
||||||
|
self.imgFormat = "fits";
|
||||||
|
} else {
|
||||||
|
throw (
|
||||||
|
"Unsupported format(s) found in the properties: " +
|
||||||
|
self.formats
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cutouts
|
||||||
|
let minCut, maxCut;
|
||||||
|
if (self.imgFormat === "fits") {
|
||||||
|
// Take into account the default cuts given by the property file (this is true especially for FITS HiPSes)
|
||||||
|
minCut = self.colorCfg.minCut || self.defaultFitsMinCut || 0.0;
|
||||||
|
maxCut = self.colorCfg.maxCut || self.defaultFitsMaxCut || 1.0;
|
||||||
|
} else {
|
||||||
|
minCut = self.colorCfg.minCut || 0.0;
|
||||||
|
maxCut = self.colorCfg.maxCut || 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setOptions({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") {
|
||||||
|
self.cooFrame = "GAL";
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
"Invalid cooframe given: " +
|
||||||
|
self.cooFrame +
|
||||||
|
'. Coordinate systems supported: "ICRS", "ICRSd", "j2000" or "galactic". ICRS is chosen by default'
|
||||||
|
);
|
||||||
|
self.cooFrame = "ICRS";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
self.formats = self.formats || [self.imgFormat];
|
||||||
|
|
||||||
|
self._saveInCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
HiPS.prototype.setView = function (view) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
// do not allow to call setView multiple times otherwise
|
||||||
|
// the querying to the properties and the search to the best
|
||||||
|
// HiPS node will be done again for the same hiPS
|
||||||
|
if (this.view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.view = view;
|
||||||
|
|
||||||
|
let isIncompleteOptions = true;
|
||||||
|
// This is very dirty but it allows me to differentiate the location from
|
||||||
|
// whether an ID or a plain url
|
||||||
|
let isID = this.url.includes("P/") || this.url.includes("C/")
|
||||||
|
|
||||||
|
if (this.imgFormat === "fits") {
|
||||||
|
// a fits is given
|
||||||
|
isIncompleteOptions = !(
|
||||||
|
this.maxOrder &&
|
||||||
|
(!isID && this.url) &&
|
||||||
|
this.imgFormat &&
|
||||||
|
this.tileSize &&
|
||||||
|
this.cooFrame &&
|
||||||
|
this.numBitsPerPixel
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
isIncompleteOptions = !(
|
||||||
|
this.maxOrder &&
|
||||||
|
(!isID && this.url) &&
|
||||||
|
this.imgFormat &&
|
||||||
|
this.tileSize &&
|
||||||
|
this.cooFrame
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.query = (async () => {
|
||||||
|
if (isIncompleteOptions) {
|
||||||
|
// ID typed url
|
||||||
|
if (self.startUrl && isID) {
|
||||||
|
// First download the properties from the start url
|
||||||
|
await HiPSProperties.fetchFromUrl(self.startUrl)
|
||||||
|
.then((p) => {
|
||||||
|
self._parseProperties(p);
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
self.url = self.startUrl;
|
||||||
|
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
HiPSProperties.fetchFromID(id)
|
||||||
|
.then((p) => {
|
||||||
|
self.url = self.startUrl;
|
||||||
|
self._fetchFasterUrlFromProperties(p);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else if (!this.startUrl && isID) {
|
||||||
|
try {
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
await HiPSProperties.fetchFromID(id)
|
||||||
|
.then((p) => {
|
||||||
|
self.url = p.hips_service_url;
|
||||||
|
|
||||||
|
self._parseProperties(p);
|
||||||
|
self._fetchFasterUrlFromProperties(p);
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await HiPSProperties.fetchFromUrl(self.url)
|
||||||
|
.then((p) => {
|
||||||
|
self._parseProperties(p);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self._parseProperties({
|
||||||
|
hips_order: this.maxOrder,
|
||||||
|
hips_service_url: this.url,
|
||||||
|
hips_tile_width: this.tileSize,
|
||||||
|
hips_frame: this.cooFrame
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
})()
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Precondition: view is attached */
|
||||||
|
HiPS.prototype._saveInCache = function () {
|
||||||
|
let self = this;
|
||||||
|
let hipsCache = this.view.aladin.hipsCache;
|
||||||
|
|
||||||
|
if (hipsCache.contains(self.id)) {
|
||||||
|
hipsCache.append(self.id, this)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the HiPS represents a planetary body.
|
||||||
|
*
|
||||||
|
* This method returns a boolean indicating whether the HiPS corresponds to a planetary body, e.g. the earth or a celestial body.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @returns {boolean} Returns true if the HiPS represents a planetary body; otherwise, returns false.
|
||||||
|
*/
|
||||||
|
HiPS.prototype.isPlanetaryBody = function () {
|
||||||
|
return this.hipsBody !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the image format for the HiPS.
|
||||||
|
*
|
||||||
|
* This method updates the image format of the HiPS, performs format validation, and triggers the update of metadata.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {string} format - The desired image format. Should be one of ["fits", "png", "jpg", "webp"].
|
||||||
|
*
|
||||||
|
* @throws {string} Throws an error if the provided format is not one of the supported formats or if the format is not available for the specific HiPS.
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setImageFormat = function (format) {
|
||||||
|
let self = this;
|
||||||
|
self.query.then(() => {
|
||||||
|
let imgFormat = format.toLowerCase();
|
||||||
|
|
||||||
|
if (
|
||||||
|
imgFormat !== "fits" &&
|
||||||
|
imgFormat !== "png" &&
|
||||||
|
imgFormat !== "jpg" &&
|
||||||
|
imgFormat !== "jpeg" &&
|
||||||
|
imgFormat !== "webp"
|
||||||
|
) {
|
||||||
|
throw 'Formats must lie in ["fits", "png", "jpg", "webp"]';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imgFormat === "jpg") {
|
||||||
|
imgFormat = "jpeg";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Passed the check, we erase the image format with the new one
|
||||||
|
// We do nothing if the imgFormat is the same
|
||||||
|
if (self.imgFormat === imgFormat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
// 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
imgFormat === "webp" &&
|
||||||
|
availableFormats.indexOf("webp") < 0
|
||||||
|
) {
|
||||||
|
throw self.id + " does not provide webp tiles";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
imgFormat === "png" &&
|
||||||
|
availableFormats.indexOf("png") < 0
|
||||||
|
) {
|
||||||
|
throw self.id + " does not provide png tiles";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
imgFormat === "jpeg" &&
|
||||||
|
availableFormats.indexOf("jpeg") < 0
|
||||||
|
) {
|
||||||
|
throw self.id + " does not provide jpeg tiles";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch from png/webp/jpeg to fits
|
||||||
|
if (
|
||||||
|
(self.imgFormat === "png" ||
|
||||||
|
self.imgFormat === "webp" ||
|
||||||
|
self.imgFormat === "jpeg") &&
|
||||||
|
imgFormat === "fits"
|
||||||
|
) {
|
||||||
|
if (Number.isFinite(self.defaultFitsMinCut) && Number.isFinite(self.defaultFitsMaxCut)) {
|
||||||
|
// reset cuts to those given from the properties
|
||||||
|
self.setCuts(self.defaultFitsMinCut, self.defaultFitsMaxCut);
|
||||||
|
}
|
||||||
|
// Switch from fits to png/webp/jpeg
|
||||||
|
} else if (self.imgFormat === "fits") {
|
||||||
|
self.setCuts(0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it is a fits
|
||||||
|
self.imgFormat = imgFormat;
|
||||||
|
|
||||||
|
self._updateMetadata();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the opacity factor when rendering the HiPS
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
HiPS.prototype.getAvailableFormats = function () {
|
||||||
|
return this.formats;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the opacity factor when rendering the HiPS
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {number} opacity - Opacity of the survey to set. Between 0 and 1
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setOpacity = function (opacity) {
|
||||||
|
this.setOptions({opacity})
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the blending mode when rendering the HiPS
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {boolean} [additive=false] -
|
||||||
|
*
|
||||||
|
* @description Two rendering modes are availables i.e. the default one and the additive one.
|
||||||
|
* When rendering this survey on top of the already rendered ones, the final color of the screen is computed like:
|
||||||
|
* <br>
|
||||||
|
* <br>opacity * this_survey_color + (1 - opacity) * already_rendered_color for the default mode
|
||||||
|
* <br>opacity * this_survey_color + already_rendered_color for the additive mode
|
||||||
|
* <br>
|
||||||
|
* <br>
|
||||||
|
* Additive mode allows you to do linear survey color combination i.e. let's define 3 surveys named s1, s2, s3. Each could be associated to one color channel, i.e. s1 with red, s2 with green and s3 with the blue color channel.
|
||||||
|
* If the additive blending mode is enabled, then the final pixel color of your screen will be: rgb = [s1_opacity * s1_color; s2_opacity * s2_color; s3_opacity * s3_color]
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setBlendingConfig = function (additive = false) {
|
||||||
|
this.setOptions({additive});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the colormap when rendering the HiPS.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {string} [colormap="grayscale"] - The colormap label to use. See {@link https://matplotlib.org/stable/users/explain/colors/colormaps.html|here} for more info about colormaps.
|
||||||
|
* Possible values are:
|
||||||
|
* <br>"blues"
|
||||||
|
* <br>"cividis"
|
||||||
|
* <br>"cubehelix"
|
||||||
|
* <br>"eosb"
|
||||||
|
* <br>"grayscale"
|
||||||
|
* <br>"inferno"
|
||||||
|
* <br>"magma"
|
||||||
|
* <br>"native"
|
||||||
|
* <br>"parula"
|
||||||
|
* <br>"plasma"
|
||||||
|
* <br>"rainbow"
|
||||||
|
* <br>"rdbu"
|
||||||
|
* <br>"rdylbu"
|
||||||
|
* <br>"redtemperature"
|
||||||
|
* <br>"sinebow"
|
||||||
|
* <br>"spectral"
|
||||||
|
* <br>"summer"
|
||||||
|
* <br>"viridis"
|
||||||
|
* <br>"ylgnbu"
|
||||||
|
* <br>"ylorbr"
|
||||||
|
* <br>"red"
|
||||||
|
* <br>"green"
|
||||||
|
* <br>"blue"
|
||||||
|
* @param {Object} [options] - Options for the colormap
|
||||||
|
* @param {string} [options.stretch] - Stretching function of the colormap. Possible values are 'linear', 'asinh', 'log', 'sqrt', 'pow'. If no given, will not change it.
|
||||||
|
* @param {boolean} [options.reversed=false] - Reverse the colormap axis.
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setColormap = function (colormap, options) {
|
||||||
|
this.setOptions({colormap, ...options})
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gamma correction factor for the HiPS.
|
||||||
|
*
|
||||||
|
* This method updates the gamma of the HiPS.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {number} minCut - The low cut value to set for the HiPS.
|
||||||
|
* @param {number} maxCut - The high cut value to set for the HiPS.
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setCuts = function (minCut, maxCut) {
|
||||||
|
this.setOptions({minCut, maxCut})
|
||||||
|
};
|
||||||
|
|
||||||
|
HiPS.prototype.getCuts = function () {
|
||||||
|
return this.colorCfg.getCuts();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gamma correction factor for the HiPS.
|
||||||
|
*
|
||||||
|
* This method updates the gamma of the HiPS.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {number} gamma - The saturation value to set for the HiPS. Between 0.1 and 10
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setGamma = function (gamma) {
|
||||||
|
this.setOptions({gamma})
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the saturation for the HiPS.
|
||||||
|
*
|
||||||
|
* This method updates the saturation of the HiPS.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {number} saturation - The saturation value to set for the HiPS. Between 0 and 1
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setSaturation = function (saturation) {
|
||||||
|
this.setOptions({saturation})
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the brightness for the HiPS.
|
||||||
|
*
|
||||||
|
* This method updates the brightness of the HiPS.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {number} brightness - The brightness value to set for the HiPS. Between 0 and 1
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setBrightness = function (brightness) {
|
||||||
|
this.setOptions({brightness})
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the contrast for the HiPS.
|
||||||
|
*
|
||||||
|
* This method updates the contrast of the HiPS and triggers the update of metadata.
|
||||||
|
*
|
||||||
|
* @memberof HiPS
|
||||||
|
*
|
||||||
|
* @param {number} contrast - The contrast value to set for the HiPS. Between 0 and 1
|
||||||
|
*/
|
||||||
|
HiPS.prototype.setContrast = function (contrast) {
|
||||||
|
this.setOptions({contrast})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Private method for updating the backend with the new meta
|
||||||
|
HiPS.prototype._updateMetadata = function () {
|
||||||
|
try {
|
||||||
|
if (this.added) {
|
||||||
|
this.view.wasm.setImageMetadata(this.layer, {
|
||||||
|
...this.colorCfg.get(),
|
||||||
|
longitudeReversed: this.longitudeReversed,
|
||||||
|
imgFormat: this.imgFormat,
|
||||||
|
});
|
||||||
|
// once the meta have been well parsed, we can set the meta
|
||||||
|
ALEvent.HIPS_LAYER_CHANGED.dispatchedTo(this.view.aladinDiv, {
|
||||||
|
layer: this,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save it in the JS HiPS cache
|
||||||
|
this._saveInCache();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Display the error message
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HiPS.prototype.setOptions = function(options) {
|
||||||
|
this.colorCfg.setOptions(options);
|
||||||
|
this.options = {...this.options, ...options};
|
||||||
|
|
||||||
|
this._updateMetadata();
|
||||||
|
};
|
||||||
|
|
||||||
|
HiPS.prototype.add = function (layer) {
|
||||||
|
this.layer = layer;
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
this.view.wasm.addHiPS({
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve(this)
|
||||||
|
.then((hips) => {
|
||||||
|
if (hips.successCallback) {
|
||||||
|
hips.successCallback(hips)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hips
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// @api
|
||||||
|
HiPS.prototype.toggle = function () {
|
||||||
|
const opacity = this.getOpacity()
|
||||||
|
if (opacity != 0.0) {
|
||||||
|
this.prevOpacity = opacity;
|
||||||
|
this.setOpacity(0.0);
|
||||||
|
} else {
|
||||||
|
this.setOpacity(this.prevOpacity);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// @oldapi
|
||||||
|
HiPS.prototype.setAlpha = HiPS.prototype.setOpacity;
|
||||||
|
|
||||||
|
HiPS.prototype.setColorCfg = function (colorCfg) {
|
||||||
|
this.colorCfg = colorCfg;
|
||||||
|
|
||||||
|
this._updateMetadata();
|
||||||
|
};
|
||||||
|
|
||||||
|
// @api
|
||||||
|
HiPS.prototype.getColorCfg = function () {
|
||||||
|
return this.colorCfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @api
|
||||||
|
HiPS.prototype.getOpacity = function () {
|
||||||
|
return this.colorCfg.getOpacity();
|
||||||
|
};
|
||||||
|
|
||||||
|
HiPS.prototype.getAlpha = HiPS.prototype.getOpacity;
|
||||||
|
|
||||||
|
// @api
|
||||||
|
HiPS.prototype.readPixel = function (x, y) {
|
||||||
|
return this.view.wasm.readPixel(x, y, this.layer);
|
||||||
|
};
|
||||||
|
|
||||||
|
HiPS.DEFAULT_SURVEY_ID = "P/DSS2/color";
|
||||||
|
|
||||||
|
return HiPS;
|
||||||
|
})();
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Aladin Lite project
|
* Aladin Lite project
|
||||||
*
|
*
|
||||||
* File ImageHiPS
|
* File HiPS
|
||||||
*
|
*
|
||||||
* Authors: Thomas Boch & Matthieu Baumann [CDS]
|
* Authors: Thomas Boch & Matthieu Baumann [CDS]
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
|
HiPSProperties.getFasterMirrorUrl = function (metadata) {
|
||||||
const pingHiPSServiceUrl = async (baseUrl) => {
|
const pingHiPSServiceUrl = async (baseUrl) => {
|
||||||
baseUrl = Utils.fixURLForHTTPS(baseUrl);
|
baseUrl = Utils.fixURLForHTTPS(baseUrl);
|
||||||
|
|
||||||
@@ -161,7 +161,6 @@ HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
|
|||||||
});
|
});
|
||||||
const duration = performance.now() - startRequestTime;//the time needed to do the request
|
const duration = performance.now() - startRequestTime;//the time needed to do the request
|
||||||
|
|
||||||
|
|
||||||
return {duration, validRequest, baseUrl};
|
return {duration, validRequest, baseUrl};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -181,7 +180,11 @@ HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
|
|||||||
|
|
||||||
urls.push(curUrl)
|
urls.push(curUrl)
|
||||||
}
|
}
|
||||||
console.log(promises)
|
|
||||||
|
if (numHiPSServiceURL === 1) {
|
||||||
|
return Promise.resolve(urls[0]);
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
.then((responses) => {
|
.then((responses) => {
|
||||||
// filter the ones that failed to not choose them
|
// filter the ones that failed to not choose them
|
||||||
@@ -198,7 +201,6 @@ HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
|
|||||||
return r1.duration - r2.duration;
|
return r1.duration - r2.duration;
|
||||||
});
|
});
|
||||||
|
|
||||||
//console.log(validResponses)
|
|
||||||
let newUrlResp;
|
let newUrlResp;
|
||||||
|
|
||||||
if (validResponses.length >= 2) {
|
if (validResponses.length >= 2) {
|
||||||
@@ -215,9 +217,10 @@ HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
|
|||||||
// no valid response => we return an error
|
// no valid response => we return an error
|
||||||
return Promise.reject('All mirrors urls have been tested:' + urls)
|
return Promise.reject('All mirrors urls have been tested:' + urls)
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
// check if there is a big difference from the current one
|
// check if there is a big difference from the current one
|
||||||
let currUrlResp = validResponses.find((r) => r.baseUrl === currUrl)
|
let currUrlResp = validResponses.find((r) => r.baseUrl === currUrl)
|
||||||
|
|
||||||
// it may happen that the url requested by the user is too slow hence discarded
|
// it may happen that the url requested by the user is too slow hence discarded
|
||||||
// for these cases, we automatically switch to the new fastest url.
|
// for these cases, we automatically switch to the new fastest url.
|
||||||
let urlChosen;
|
let urlChosen;
|
||||||
@@ -229,9 +232,10 @@ HiPSProperties.getFasterMirrorUrl = function (metadata, currUrl) {
|
|||||||
urlChosen = newUrlResp.baseUrl;
|
urlChosen = newUrlResp.baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log('curr url', currUrlResp, ', new ', newUrlResp)
|
|
||||||
|
|
||||||
urlChosen = Utils.fixURLForHTTPS(urlChosen)
|
urlChosen = Utils.fixURLForHTTPS(urlChosen)
|
||||||
|
*/
|
||||||
|
let urlChosen = newUrlResp.baseUrl;
|
||||||
return urlChosen;
|
return urlChosen;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
585
src/js/Image.js
585
src/js/Image.js
@@ -25,11 +25,11 @@
|
|||||||
* Authors: Matthieu Baumann [CDS]
|
* Authors: Matthieu Baumann [CDS]
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
import { ALEvent } from "./events/ALEvent.js";
|
|
||||||
import { ColorCfg } from "./ColorCfg.js";
|
import { ColorCfg } from "./ColorCfg.js";
|
||||||
import { Aladin } from "./Aladin.js";
|
import { Aladin } from "./Aladin.js";
|
||||||
import { Utils } from "./Utils";
|
import { Utils } from "./Utils";
|
||||||
import { AVM } from "./libs/avm.js";
|
import { AVM } from "./libs/avm.js";
|
||||||
|
import { HiPS } from "./HiPS.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} ImageOptions
|
* @typedef {Object} ImageOptions
|
||||||
@@ -97,7 +97,7 @@ export let Image = (function () {
|
|||||||
* @param {ImageOptions} [options] - The option for the survey
|
* @param {ImageOptions} [options] - The option for the survey
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function Image(url, options) {
|
let Image = function(url, options) {
|
||||||
// Name of the layer
|
// Name of the layer
|
||||||
this.layer = null;
|
this.layer = null;
|
||||||
this.added = false;
|
this.added = false;
|
||||||
@@ -110,11 +110,8 @@ export let Image = (function () {
|
|||||||
// callbacks
|
// callbacks
|
||||||
this.successCallback = options && options.successCallback;
|
this.successCallback = options && options.successCallback;
|
||||||
this.errorCallback = options && options.errorCallback;
|
this.errorCallback = options && options.errorCallback;
|
||||||
// initialize the color meta data here
|
|
||||||
// set a asinh stretch by default if there is none
|
this.longitudeReversed = false;
|
||||||
/*if (options) {
|
|
||||||
options.stretch = options.stretch || "asinh";
|
|
||||||
}*/
|
|
||||||
|
|
||||||
this.colorCfg = new ColorCfg(options);
|
this.colorCfg = new ColorCfg(options);
|
||||||
this.options = options || {};
|
this.options = options || {};
|
||||||
@@ -124,374 +121,296 @@ export let Image = (function () {
|
|||||||
this.query = Promise.resolve(self);
|
this.query = Promise.resolve(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Precondition: view is already attached */
|
Image.prototype = {
|
||||||
Image.prototype._saveInCache = function () {
|
/* Precondition: view is already attached */
|
||||||
let hipsCache = this.view.aladin.hipsCache;
|
_saveInCache: HiPS.prototype._saveInCache,
|
||||||
if (hipsCache.contains(self.id)) {
|
|
||||||
hipsCache.append(this.id, this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Image.prototype.setView = function (view) {
|
// @api
|
||||||
this.view = view;
|
getCuts: HiPS.prototype.getCuts,
|
||||||
|
|
||||||
this._saveInCache();
|
// @api
|
||||||
};
|
setOpacity: HiPS.prototype.setOpacity,
|
||||||
|
|
||||||
// @api
|
|
||||||
Image.prototype.setOpacity = function (opacity) {
|
|
||||||
let self = this;
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
self.colorCfg.setOpacity(opacity);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
Image.prototype.setBlendingConfig = function (additive = false) {
|
setOptions: HiPS.prototype.setOptions,
|
||||||
this._updateMetadata(() => {
|
// @api
|
||||||
this.colorCfg.setBlendingConfig(additive);
|
setBlendingConfig: HiPS.prototype.setBlendingConfig,
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
Image.prototype.setColormap = function (colormap, options) {
|
setColormap: HiPS.prototype.setColormap,
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setColormap(colormap, options);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
Image.prototype.setCuts = function (lowCut, highCut) {
|
setCuts: HiPS.prototype.setCuts,
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setCuts(lowCut, highCut);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
Image.prototype.setGamma = function (gamma) {
|
setGamma: HiPS.prototype.setGamma,
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setGamma(gamma);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
Image.prototype.setSaturation = function (saturation) {
|
setSaturation: HiPS.prototype.setSaturation,
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setSaturation(saturation);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Image.prototype.setBrightness = function (brightness) {
|
setBrightness: HiPS.prototype.setBrightness,
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setBrightness(brightness);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Image.prototype.setContrast = function (contrast) {
|
setContrast: HiPS.prototype.setContrast,
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setContrast(contrast);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Private method for updating the view with the new meta
|
// @api
|
||||||
Image.prototype._updateMetadata = function (callback) {
|
toggle: HiPS.prototype.toggle,
|
||||||
if (callback) {
|
// @oldapi
|
||||||
callback();
|
setAlpha: HiPS.prototype.setOpacity,
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the view its meta have changed
|
setColorCfg: HiPS.prototype.setColorCfg,
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// save it in the JS HiPS cache
|
// @api
|
||||||
|
getColorCfg: HiPS.prototype.getColorCfg,
|
||||||
|
|
||||||
|
// @api
|
||||||
|
getOpacity: HiPS.prototype.getOpacity,
|
||||||
|
getAlpha: HiPS.prototype.getOpacity,
|
||||||
|
|
||||||
|
// @api
|
||||||
|
readPixel: HiPS.prototype.readPixel,
|
||||||
|
|
||||||
|
// Private method for updating the view with the new meta
|
||||||
|
_updateMetadata: HiPS.prototype._updateMetadata,
|
||||||
|
|
||||||
|
setView: function (view) {
|
||||||
|
this.view = view;
|
||||||
this._saveInCache();
|
this._saveInCache();
|
||||||
} catch (e) {
|
},
|
||||||
// Display the error message
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Image.prototype._addFITS = function(layer) {
|
_addFITS: function(layer) {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
return Utils.fetch({
|
return Utils.fetch({
|
||||||
url: this.url,
|
url: this.url,
|
||||||
dataType: 'readableStream',
|
dataType: 'readableStream',
|
||||||
success: (stream) => {
|
success: (stream) => {
|
||||||
return self.view.wasm.addImageFITS(
|
return self.view.wasm.addImageFITS(
|
||||||
stream,
|
stream,
|
||||||
{
|
{
|
||||||
...self.colorCfg.get(),
|
...self.colorCfg.get(),
|
||||||
longitudeReversed: false,
|
longitudeReversed: this.longitudeReversed,
|
||||||
imgFormat: 'fits',
|
imgFormat: 'fits',
|
||||||
},
|
},
|
||||||
layer
|
layer
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
error: (e) => {
|
error: (e) => {
|
||||||
// try as cors
|
// try as cors
|
||||||
const url = Aladin.JSONP_PROXY + '?url=' + self.url;
|
const url = Aladin.JSONP_PROXY + '?url=' + self.url;
|
||||||
|
|
||||||
return Utils.fetch({
|
return Utils.fetch({
|
||||||
url: url,
|
url: url,
|
||||||
dataType: 'readableStream',
|
dataType: 'readableStream',
|
||||||
success: (stream) => {
|
success: (stream) => {
|
||||||
return self.view.wasm.addImageFITS(
|
return self.view.wasm.addImageFITS(
|
||||||
stream,
|
stream,
|
||||||
{
|
{
|
||||||
...self.colorCfg.get(),
|
...self.colorCfg.get(),
|
||||||
longitudeReversed: false,
|
longitudeReversed: this.longitudeReversed,
|
||||||
imgFormat: 'fits',
|
imgFormat: 'fits',
|
||||||
},
|
},
|
||||||
layer
|
layer
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((imageParams) => {
|
|
||||||
self.imgFormat = 'fits';
|
|
||||||
|
|
||||||
return Promise.resolve(imageParams);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Image.prototype._addJPGOrPNG = function(layer) {
|
|
||||||
let self = this;
|
|
||||||
let img = document.createElement('img');
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
img.src = this.url;
|
|
||||||
img.crossOrigin = "Anonymous";
|
|
||||||
img.onload = () => {
|
|
||||||
const img2Blob = () => {
|
|
||||||
var canvas = document.createElement("canvas");
|
|
||||||
|
|
||||||
canvas.width = img.width;
|
|
||||||
canvas.height = img.height;
|
|
||||||
|
|
||||||
// Copy the image contents to the canvas
|
|
||||||
var ctx = canvas.getContext("2d");
|
|
||||||
ctx.drawImage(img, 0, 0, img.width, img.height);
|
|
||||||
|
|
||||||
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
|
||||||
|
|
||||||
const blob = new Blob([imageData.data]);
|
|
||||||
const stream = blob.stream(1024);
|
|
||||||
|
|
||||||
resolve(stream)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!self.options.wcs) {
|
|
||||||
/* look for avm tags if no wcs is given */
|
|
||||||
let avm = new AVM(img);
|
|
||||||
|
|
||||||
avm.load((obj) => {
|
|
||||||
// obj contains the following information:
|
|
||||||
// obj.id (string) = The ID provided for the image
|
|
||||||
// obj.img (object) = The image object
|
|
||||||
// obj.xmp (string) = The raw XMP header
|
|
||||||
// obj.wcsdata (Boolean) = If WCS have been loaded
|
|
||||||
// obj.tags (object) = An array containing all the loaded tags e.g. obj.tags['Headline']
|
|
||||||
// obj.wcs (object) = The wcs parsed from the image
|
|
||||||
if (obj.wcsdata) {
|
|
||||||
if (img.width !== obj.wcs.NAXIS1) {
|
|
||||||
obj.wcs.NAXIS1 = img.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (img.height !== obj.wcs.NAXIS2) {
|
|
||||||
obj.wcs.NAXIS2 = img.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.options.wcs = obj.wcs;
|
|
||||||
|
|
||||||
img2Blob()
|
|
||||||
} else {
|
|
||||||
// no tags found
|
|
||||||
reject('No WCS have been found in the image')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
img2Blob()
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.then((imageParams) => {
|
||||||
|
self.imgFormat = 'fits';
|
||||||
|
|
||||||
let proxyUsed = false;
|
return Promise.resolve(imageParams);
|
||||||
img.onerror = (e) => {
|
})
|
||||||
// use proxy
|
},
|
||||||
if (proxyUsed) {
|
|
||||||
console.error(e);
|
|
||||||
|
|
||||||
reject('Error parsing image located at: ' + self.url)
|
_addJPGOrPNG: function(layer) {
|
||||||
return;
|
let self = this;
|
||||||
}
|
let img = document.createElement('img');
|
||||||
|
|
||||||
proxyUsed = true;
|
return new Promise((resolve, reject) => {
|
||||||
img.src = Aladin.JSONP_PROXY + '?url=' + self.url;
|
img.src = this.url;
|
||||||
}
|
img.crossOrigin = "Anonymous";
|
||||||
})
|
img.onload = () => {
|
||||||
.then((readableStream) => {
|
const img2Blob = () => {
|
||||||
let wcs = self.options && self.options.wcs;
|
var canvas = document.createElement("canvas");
|
||||||
wcs.NAXIS1 = wcs.NAXIS1 || img.width;
|
|
||||||
wcs.NAXIS2 = wcs.NAXIS2 || img.height;
|
|
||||||
|
|
||||||
return self.view.wasm
|
canvas.width = img.width;
|
||||||
.addImageWithWCS(
|
canvas.height = img.height;
|
||||||
readableStream,
|
|
||||||
wcs,
|
|
||||||
{
|
|
||||||
...self.colorCfg.get(),
|
|
||||||
longitudeReversed: false,
|
|
||||||
imgFormat: 'jpeg',
|
|
||||||
},
|
|
||||||
layer
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.then((imageParams) => {
|
|
||||||
self.imgFormat = 'jpeg';
|
|
||||||
return Promise.resolve(imageParams);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
img.remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Image.prototype.add = function (layer) {
|
// Copy the image contents to the canvas
|
||||||
this.layer = layer;
|
var ctx = canvas.getContext("2d");
|
||||||
|
ctx.drawImage(img, 0, 0, img.width, img.height);
|
||||||
|
|
||||||
let self = this;
|
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
||||||
let promise;
|
|
||||||
|
|
||||||
if (this.imgFormat === 'fits') {
|
const blob = new Blob([imageData.data]);
|
||||||
promise = this._addFITS(layer)
|
const stream = blob.stream(1024);
|
||||||
.catch(e => {
|
|
||||||
console.error(`Image located at ${this.url} could not be parsed as fits file. Is the imgFormat specified correct?`)
|
resolve(stream)
|
||||||
return Promise.reject(e)
|
};
|
||||||
})
|
|
||||||
} else if (this.imgFormat === 'jpeg' || this.imgFormat === 'png') {
|
if (!self.options.wcs) {
|
||||||
promise = this._addJPGOrPNG(layer)
|
/* look for avm tags if no wcs is given */
|
||||||
.catch(e => {
|
let avm = new AVM(img);
|
||||||
console.error(`Image located at ${this.url} could not be parsed as a ${this.imgFormat} file. Is the imgFormat specified correct?`);
|
|
||||||
return Promise.reject(e)
|
avm.load((obj) => {
|
||||||
})
|
// obj contains the following information:
|
||||||
} else {
|
// obj.id (string) = The ID provided for the image
|
||||||
// imgformat not defined we will try first supposing it is a fits file and then use the jpg heuristic
|
// obj.img (object) = The image object
|
||||||
promise = self._addFITS(layer)
|
// obj.xmp (string) = The raw XMP header
|
||||||
.catch(e => {
|
// obj.wcsdata (Boolean) = If WCS have been loaded
|
||||||
return self._addJPGOrPNG(layer)
|
// obj.tags (object) = An array containing all the loaded tags e.g. obj.tags['Headline']
|
||||||
.catch(e => {
|
// obj.wcs (object) = The wcs parsed from the image
|
||||||
console.error(`Image located at ${self.url} could not be parsed as jpg/png/tif image file. Aborting...`)
|
if (obj.wcsdata) {
|
||||||
return Promise.reject(e);
|
if (img.width !== obj.wcs.NAXIS1) {
|
||||||
|
obj.wcs.NAXIS1 = img.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img.height !== obj.wcs.NAXIS2) {
|
||||||
|
obj.wcs.NAXIS2 = img.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.options.wcs = obj.wcs;
|
||||||
|
|
||||||
|
img2Blob()
|
||||||
|
} else {
|
||||||
|
// no tags found
|
||||||
|
reject('No WCS have been found in the image')
|
||||||
|
return;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
} else {
|
||||||
}
|
img2Blob()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
promise = promise.then((imageParams) => {
|
let proxyUsed = false;
|
||||||
self.formats = [self.imgFormat];
|
img.onerror = (e) => {
|
||||||
|
// use proxy
|
||||||
|
if (proxyUsed) {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
// There is at least one entry in imageParams
|
reject('Error parsing image located at: ' + self.url)
|
||||||
self.added = true;
|
return;
|
||||||
self.setView(self.view);
|
}
|
||||||
|
|
||||||
// Set the automatic computed cuts
|
proxyUsed = true;
|
||||||
let [minCut, maxCut] = self.getCuts();
|
img.src = Aladin.JSONP_PROXY + '?url=' + self.url;
|
||||||
minCut = minCut || imageParams.min_cut;
|
}
|
||||||
maxCut = maxCut || imageParams.max_cut;
|
})
|
||||||
self.setCuts(
|
.then((readableStream) => {
|
||||||
minCut,
|
let wcs = self.options && self.options.wcs;
|
||||||
maxCut
|
wcs.NAXIS1 = wcs.NAXIS1 || img.width;
|
||||||
);
|
wcs.NAXIS2 = wcs.NAXIS2 || img.height;
|
||||||
|
|
||||||
self.ra = imageParams.centered_fov.ra;
|
return self.view.wasm
|
||||||
self.dec = imageParams.centered_fov.dec;
|
.addImageWithWCS(
|
||||||
self.fov = imageParams.centered_fov.fov;
|
readableStream,
|
||||||
|
wcs,
|
||||||
|
{
|
||||||
|
...self.colorCfg.get(),
|
||||||
|
longitudeReversed: this.longitudeReversed,
|
||||||
|
imgFormat: 'jpeg',
|
||||||
|
},
|
||||||
|
layer
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.then((imageParams) => {
|
||||||
|
self.imgFormat = 'jpeg';
|
||||||
|
return Promise.resolve(imageParams);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
img.remove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// Call the success callback on the first HDU image parsed
|
add: function (layer) {
|
||||||
if (self.successCallback) {
|
this.layer = layer;
|
||||||
self.successCallback(
|
|
||||||
self.ra,
|
let self = this;
|
||||||
self.dec,
|
let promise;
|
||||||
self.fov,
|
|
||||||
self
|
if (this.imgFormat === 'fits') {
|
||||||
);
|
promise = this._addFITS(layer)
|
||||||
|
.catch(e => {
|
||||||
|
console.error(`Image located at ${this.url} could not be parsed as fits file. Is the imgFormat specified correct?`)
|
||||||
|
return Promise.reject(e)
|
||||||
|
})
|
||||||
|
} else if (this.imgFormat === 'jpeg' || this.imgFormat === 'png') {
|
||||||
|
promise = this._addJPGOrPNG(layer)
|
||||||
|
.catch(e => {
|
||||||
|
console.error(`Image located at ${this.url} could not be parsed as a ${this.imgFormat} file. Is the imgFormat specified correct?`);
|
||||||
|
return Promise.reject(e)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// imgformat not defined we will try first supposing it is a fits file and then use the jpg heuristic
|
||||||
|
promise = self._addFITS(layer)
|
||||||
|
.catch(e => {
|
||||||
|
return self._addJPGOrPNG(layer)
|
||||||
|
.catch(e => {
|
||||||
|
console.error(`Image located at ${self.url} could not be parsed as jpg/png/tif image file. Aborting...`)
|
||||||
|
return Promise.reject(e);
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
promise = promise.then((imageParams) => {
|
||||||
})
|
self.formats = [self.imgFormat];
|
||||||
.catch((e) => {
|
|
||||||
// This error result from a promise
|
|
||||||
// If I throw it, it will not be catched because
|
|
||||||
// it is run async
|
|
||||||
self.view.removeImageLayer(layer);
|
|
||||||
|
|
||||||
return Promise.reject(e);
|
// There is at least one entry in imageParams
|
||||||
});
|
self.added = true;
|
||||||
|
self.setView(self.view);
|
||||||
|
|
||||||
return promise;
|
// Set the automatic computed cuts
|
||||||
};
|
let [minCut, maxCut] = self.getCuts();
|
||||||
|
minCut = minCut || imageParams.min_cut;
|
||||||
|
maxCut = maxCut || imageParams.max_cut;
|
||||||
|
self.setCuts(
|
||||||
|
minCut,
|
||||||
|
maxCut
|
||||||
|
);
|
||||||
|
|
||||||
// @api
|
self.ra = imageParams.centered_fov.ra;
|
||||||
Image.prototype.toggle = function () {
|
self.dec = imageParams.centered_fov.dec;
|
||||||
if (this.colorCfg.getOpacity() != 0.0) {
|
self.fov = imageParams.centered_fov.fov;
|
||||||
this.colorCfg.setOpacity(0.0);
|
|
||||||
} else {
|
|
||||||
this.colorCfg.setOpacity(this.prevOpacity);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// FITS images does not mean to be used for storing planetary data
|
// Call the success callback on the first HDU image parsed
|
||||||
Image.prototype.isPlanetaryBody = function () {
|
if (self.successCallback) {
|
||||||
return false;
|
self.successCallback(
|
||||||
};
|
self.ra,
|
||||||
|
self.dec,
|
||||||
|
self.fov,
|
||||||
|
self
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// @api
|
return self;
|
||||||
Image.prototype.focusOn = function () {
|
})
|
||||||
// ensure the fits have been parsed
|
.catch((e) => {
|
||||||
if (this.added) {
|
// This error result from a promise
|
||||||
this.view.aladin.gotoRaDec(this.ra, this.dec);
|
// If I throw it, it will not be catched because
|
||||||
this.view.aladin.setFoV(this.fov);
|
// it is run async
|
||||||
}
|
self.view.removeImageLayer(layer);
|
||||||
};
|
|
||||||
|
|
||||||
// @oldapi
|
return Promise.reject(e);
|
||||||
Image.prototype.setAlpha = Image.prototype.setOpacity;
|
});
|
||||||
|
|
||||||
Image.prototype.setColorCfg = function (colorCfg) {
|
return promise;
|
||||||
this._updateMetadata(() => {
|
},
|
||||||
this.colorCfg = colorCfg;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
// FITS images does not mean to be used for storing planetary data
|
||||||
Image.prototype.getColorCfg = function () {
|
isPlanetaryBody: function () {
|
||||||
return this.colorCfg;
|
return false;
|
||||||
};
|
},
|
||||||
|
|
||||||
// @api
|
// @api
|
||||||
Image.prototype.getCuts = function () {
|
focusOn: function () {
|
||||||
return this.colorCfg.getCuts();
|
// ensure the fits have been parsed
|
||||||
};
|
if (this.added) {
|
||||||
|
this.view.aladin.gotoRaDec(this.ra, this.dec);
|
||||||
// @api
|
this.view.aladin.setFoV(this.fov);
|
||||||
Image.prototype.getOpacity = function () {
|
}
|
||||||
return this.colorCfg.getOpacity();
|
},
|
||||||
};
|
|
||||||
|
|
||||||
Image.prototype.getAlpha = Image.prototype.getOpacity;
|
|
||||||
|
|
||||||
// @api
|
|
||||||
Image.prototype.readPixel = function (x, y) {
|
|
||||||
return this.view.wasm.readPixel(x, y, this.layer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Image;
|
return Image;
|
||||||
|
|||||||
@@ -1,878 +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 ImageHiPS
|
|
||||||
*
|
|
||||||
* Authors: Thomas Boch & Matthieu Baumann [CDS]
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
import { Utils } from "./Utils";
|
|
||||||
import { ALEvent } from "./events/ALEvent.js";
|
|
||||||
import { ColorCfg } from "./ColorCfg.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;
|
|
||||||
|
|
||||||
// Check if the tile width size is a power of 2
|
|
||||||
if (tileSize & (tileSize - 1 !== 0)) {
|
|
||||||
tileSize = 512;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tileSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Mandatory frame property
|
|
||||||
PropertyParser.cooFrame = function (properties) {
|
|
||||||
let cooFrame =
|
|
||||||
(properties && properties.hips_body && "ICRSd") ||
|
|
||||||
(properties && properties.hips_frame) ||
|
|
||||||
"ICRS";
|
|
||||||
return cooFrame;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Mandatory maxOrder property
|
|
||||||
PropertyParser.maxOrder = function (properties) {
|
|
||||||
let maxOrder =
|
|
||||||
properties && 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;
|
|
||||||
return minOrder;
|
|
||||||
};
|
|
||||||
|
|
||||||
PropertyParser.formats = function (properties) {
|
|
||||||
let formats = (properties && properties.hips_tile_format) || "jpeg";
|
|
||||||
|
|
||||||
formats = formats.split(" ").map((fmt) => fmt.toLowerCase());
|
|
||||||
|
|
||||||
return formats;
|
|
||||||
};
|
|
||||||
|
|
||||||
PropertyParser.initialFov = function (properties) {
|
|
||||||
let initialFov =
|
|
||||||
properties &&
|
|
||||||
properties.hips_initial_fov &&
|
|
||||||
+properties.hips_initial_fov;
|
|
||||||
|
|
||||||
if (initialFov && initialFov < 0.00002777777) {
|
|
||||||
initialFov = 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
return initialFov;
|
|
||||||
};
|
|
||||||
|
|
||||||
PropertyParser.skyFraction = function (properties) {
|
|
||||||
const skyFraction =
|
|
||||||
(properties &&
|
|
||||||
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(" ");
|
|
||||||
|
|
||||||
const minCutout = cuts && parseFloat(cuts[0]);
|
|
||||||
const maxCutout = cuts && parseFloat(cuts[1]);
|
|
||||||
|
|
||||||
return [minCutout, maxCutout];
|
|
||||||
};
|
|
||||||
|
|
||||||
PropertyParser.bitpix = function (properties) {
|
|
||||||
const bitpix =
|
|
||||||
properties &&
|
|
||||||
properties.hips_pixel_bitpix &&
|
|
||||||
+properties.hips_pixel_bitpix;
|
|
||||||
return bitpix;
|
|
||||||
};
|
|
||||||
|
|
||||||
PropertyParser.isPlanetaryBody = function (properties) {
|
|
||||||
return properties && properties.hips_body !== undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} HiPSOptions
|
|
||||||
*
|
|
||||||
* @property {string} [name] - The name of the survey to be displayed in the UI
|
|
||||||
* @property {Function} [successCallback] - A callback executed when the HiPS has been loaded
|
|
||||||
* @property {Function} [errorCallback] - A callback executed when the HiPS could not be loaded
|
|
||||||
* @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} [minOrder] - If not given, retrieved from the properties of the survey.
|
|
||||||
* @property {boolean} [longitudeReversed=false] - Set it to True for planetary survey visualization
|
|
||||||
* @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.
|
|
||||||
* @property {boolean} [reversed=false] - If true, the colormap is reversed; otherwise, it is not reversed.
|
|
||||||
* @property {number} [minCut] - The minimum cut value for the color configuration. If not given, 0.0 for JPEG/PNG surveys, the value of the property file for FITS surveys
|
|
||||||
* @property {number} [maxCut] - The maximum cut value for the color configuration. If not given, 1.0 for JPEG/PNG surveys, the value of the property file for FITS surveys
|
|
||||||
* @property {boolean} [additive=false] - If true, additive blending is applied; otherwise, it is not applied.
|
|
||||||
* @property {number} [gamma=1.0] - The gamma correction value for the color configuration.
|
|
||||||
* @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.
|
|
||||||
*/
|
|
||||||
export let ImageHiPS = (function () {
|
|
||||||
/**
|
|
||||||
* The object describing an image survey
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructs ImageHiPS
|
|
||||||
*
|
|
||||||
* @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 {HiPSOptions} [options] - The option for the survey
|
|
||||||
*
|
|
||||||
* @description Giving a CDS ID will do a query to the MOCServer first to retrieve metadata. Then it will also check for the presence of faster HiPS nodes to choose a faster url to query to tiles from.
|
|
||||||
*/
|
|
||||||
function ImageHiPS(id, url, options) {
|
|
||||||
this.added = false;
|
|
||||||
// Unique identifier for a survey
|
|
||||||
this.id = id;
|
|
||||||
this.name = (options && options.name) || undefined;
|
|
||||||
this.url = url;
|
|
||||||
this.maxOrder = options.maxOrder;
|
|
||||||
this.minOrder = options.minOrder || 0;
|
|
||||||
this.cooFrame = options.cooFrame;
|
|
||||||
this.tileSize = options.tileSize;
|
|
||||||
this.skyFraction = options.skyFraction;
|
|
||||||
this.startingUrl = options.startingUrl;
|
|
||||||
this.longitudeReversed =
|
|
||||||
options.longitudeReversed === undefined
|
|
||||||
? false
|
|
||||||
: options.longitudeReversed;
|
|
||||||
this.imgFormat = options.imgFormat;
|
|
||||||
this.formats = options.formats;
|
|
||||||
this.defaultFitsMinCut = options.defaultFitsMinCut;
|
|
||||||
this.defaultFitsMaxCut = options.defaultFitsMaxCut;
|
|
||||||
this.numBitsPerPixel = options.numBitsPerPixel;
|
|
||||||
this.creatorDid = options.creatorDid;
|
|
||||||
this.errorCallback = options.errorCallback;
|
|
||||||
this.successCallback = options.successCallback;
|
|
||||||
|
|
||||||
this.colorCfg = new ColorCfg(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageHiPS.prototype.setView = function (view) {
|
|
||||||
let self = this;
|
|
||||||
|
|
||||||
// do not allow to call setView multiple times otherwise
|
|
||||||
// the querying to the properties and the search to the best
|
|
||||||
// HiPS node will be done again for the same imageHiPS
|
|
||||||
if (this.view) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.view = view;
|
|
||||||
|
|
||||||
let isIncompleteOptions = true;
|
|
||||||
if (this.imgFormat === "fits") {
|
|
||||||
// a fits is given
|
|
||||||
isIncompleteOptions = !(
|
|
||||||
this.maxOrder &&
|
|
||||||
this.url &&
|
|
||||||
this.imgFormat &&
|
|
||||||
this.tileSize &&
|
|
||||||
this.cooFrame &&
|
|
||||||
this.numBitsPerPixel
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
isIncompleteOptions = !(
|
|
||||||
this.maxOrder &&
|
|
||||||
this.url &&
|
|
||||||
this.imgFormat &&
|
|
||||||
this.tileSize &&
|
|
||||||
this.cooFrame
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.query = (async () => {
|
|
||||||
if (isIncompleteOptions) {
|
|
||||||
let isCDSId = false;
|
|
||||||
|
|
||||||
let fetchBestUrl = (p) => {
|
|
||||||
self.url = p.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(p, self.url)
|
|
||||||
.then((url) => {
|
|
||||||
if (self.url !== url) {
|
|
||||||
console.info(
|
|
||||||
"Change url of ",
|
|
||||||
self.id,
|
|
||||||
" from ",
|
|
||||||
self.url,
|
|
||||||
" to ",
|
|
||||||
url
|
|
||||||
);
|
|
||||||
|
|
||||||
self.url = url;
|
|
||||||
|
|
||||||
// save the new url to the cache
|
|
||||||
self._saveInCache();
|
|
||||||
|
|
||||||
// If added to the backend, then we need to tell it the url has changed
|
|
||||||
if (self.added) {
|
|
||||||
self.view.wasm.setHiPSUrl(
|
|
||||||
self.creatorDid,
|
|
||||||
url
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(self);
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
let properties = await HiPSProperties.fetchFromUrl(self.url)
|
|
||||||
/*.catch((e) => {
|
|
||||||
// special case for glimpse if I remember right
|
|
||||||
// try with the proxy
|
|
||||||
url = Utils.handleCORSNotSameOrigin(url).href;
|
|
||||||
|
|
||||||
return HiPSProperties.fetchFromUrl(url);
|
|
||||||
})*/
|
|
||||||
.catch(async (e) => {
|
|
||||||
// url not valid so we try with the id
|
|
||||||
try {
|
|
||||||
isCDSId = true;
|
|
||||||
// the url stores a "CDS ID" we take it prioritaly
|
|
||||||
// if the url is null, take the id, this is for some tests
|
|
||||||
// to pass because some users might just give null as url param and a "CDS ID" as id param
|
|
||||||
let id = self.url || self.id;
|
|
||||||
// a starting url stored into the default hips list so that we do not wait
|
|
||||||
// the query to the mocserver
|
|
||||||
//console.log("cds id")
|
|
||||||
return await HiPSProperties.fetchFromID(id)
|
|
||||||
} catch (e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fetchBestUrl(properties);
|
|
||||||
|
|
||||||
self.creatorDid = properties.creator_did || self.creatorDid;
|
|
||||||
// url
|
|
||||||
|
|
||||||
// Max order
|
|
||||||
self.maxOrder =
|
|
||||||
PropertyParser.maxOrder(properties) || self.maxOrder;
|
|
||||||
|
|
||||||
// Tile size
|
|
||||||
self.tileSize =
|
|
||||||
PropertyParser.tileSize(properties) || self.tileSize;
|
|
||||||
|
|
||||||
// Tile formats
|
|
||||||
self.formats =
|
|
||||||
PropertyParser.formats(properties) || self.formats;
|
|
||||||
|
|
||||||
// min order
|
|
||||||
self.minOrder =
|
|
||||||
PropertyParser.minOrder(properties) || self.minOrder;
|
|
||||||
|
|
||||||
// Frame
|
|
||||||
self.cooFrame =
|
|
||||||
PropertyParser.cooFrame(properties) || self.cooFrame;
|
|
||||||
|
|
||||||
// sky fraction
|
|
||||||
self.skyFraction = PropertyParser.skyFraction(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;
|
|
||||||
|
|
||||||
// Cutouts
|
|
||||||
const cutoutFromProperties = PropertyParser.cutouts(properties);
|
|
||||||
self.defaultFitsMinCut = cutoutFromProperties[0];
|
|
||||||
self.defaultFitsMaxCut = cutoutFromProperties[1];
|
|
||||||
|
|
||||||
// Bitpix
|
|
||||||
self.numBitsPerPixel =
|
|
||||||
PropertyParser.bitpix(properties) || self.numBitsPerPixel;
|
|
||||||
|
|
||||||
// HiPS body
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give a better name if we have the HiPS metadata
|
|
||||||
self.name = self.name || properties.obs_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.name = self.name || self.id || self.url;
|
|
||||||
self.name = self.name.replace(/ +/g, ' ');
|
|
||||||
|
|
||||||
self.creatorDid = self.creatorDid || self.id || self.url;
|
|
||||||
|
|
||||||
// Image format
|
|
||||||
if (self.imgFormat) {
|
|
||||||
// transform to lower case
|
|
||||||
self.imgFormat = self.imgFormat.toLowerCase();
|
|
||||||
// convert JPG -> JPEG
|
|
||||||
if (self.imgFormat === "jpg") {
|
|
||||||
self.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
|
|
||||||
) {
|
|
||||||
throw self.name + " does not provide fits tiles";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
self.imgFormat === "webp" &&
|
|
||||||
self.formats &&
|
|
||||||
self.formats.indexOf("webp") < 0
|
|
||||||
) {
|
|
||||||
throw self.name + " does not provide webp tiles";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
self.imgFormat === "png" &&
|
|
||||||
self.formats &&
|
|
||||||
self.formats.indexOf("png") < 0
|
|
||||||
) {
|
|
||||||
throw self.name + " does not provide png tiles";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
self.imgFormat === "jpeg" &&
|
|
||||||
self.formats &&
|
|
||||||
self.formats.indexOf("jpeg") < 0
|
|
||||||
) {
|
|
||||||
throw self.name + " does not provide jpeg tiles";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// user wants nothing then we choose one from the properties
|
|
||||||
if (self.formats.indexOf("webp") >= 0) {
|
|
||||||
self.imgFormat = "webp";
|
|
||||||
} else if (self.formats.indexOf("png") >= 0) {
|
|
||||||
self.imgFormat = "png";
|
|
||||||
} else if (self.formats.indexOf("jpeg") >= 0) {
|
|
||||||
self.imgFormat = "jpeg";
|
|
||||||
} else if (self.formats.indexOf("fits") >= 0) {
|
|
||||||
self.imgFormat = "fits";
|
|
||||||
} else {
|
|
||||||
throw (
|
|
||||||
"Unsupported format(s) found in the properties: " +
|
|
||||||
self.formats
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cutouts
|
|
||||||
let minCut, maxCut;
|
|
||||||
if (self.imgFormat === "fits") {
|
|
||||||
// Take into account the default cuts given by the property file (this is true especially for FITS HiPSes)
|
|
||||||
minCut = self.colorCfg.minCut || self.defaultFitsMinCut || 0.0;
|
|
||||||
maxCut = self.colorCfg.maxCut || self.defaultFitsMaxCut || 1.0;
|
|
||||||
} else {
|
|
||||||
minCut = self.colorCfg.minCut || 0.0;
|
|
||||||
maxCut = self.colorCfg.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") {
|
|
||||||
self.cooFrame = "GAL";
|
|
||||||
} else {
|
|
||||||
console.warn(
|
|
||||||
"Invalid cooframe given: " +
|
|
||||||
self.cooFrame +
|
|
||||||
'. Coordinate systems supported: "ICRS", "ICRSd", "j2000" or "galactic". ICRS is chosen by default'
|
|
||||||
);
|
|
||||||
self.cooFrame = "ICRS";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
self.formats = self.formats || [self.imgFormat];
|
|
||||||
|
|
||||||
self._saveInCache();
|
|
||||||
|
|
||||||
return self;
|
|
||||||
})()
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Precondition: view is attached */
|
|
||||||
ImageHiPS.prototype._saveInCache = function () {
|
|
||||||
let self = this;
|
|
||||||
/*let colorOpt = Object.fromEntries(Object.entries(this.colorCfg));
|
|
||||||
let surveyOpt = {
|
|
||||||
id: self.id,
|
|
||||||
creatorDid: self.creatorDid,
|
|
||||||
name: self.name,
|
|
||||||
url: self.url,
|
|
||||||
skyFraction: self.skyFraction,
|
|
||||||
cooFrame: self.cooFrame,
|
|
||||||
maxOrder: self.maxOrder,
|
|
||||||
tileSize: self.tileSize,
|
|
||||||
formats: self.formats,
|
|
||||||
imgFormat: self.imgFormat,
|
|
||||||
successCallback: self.successCallback,
|
|
||||||
errorCallback: self.errorCallback,
|
|
||||||
defaultFitsMinCut: self.defaultFitsMinCut,
|
|
||||||
defaultFitsMaxCut: self.defaultFitsMaxCut,
|
|
||||||
...colorOpt,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (self.numBitsPerPixel) {
|
|
||||||
surveyOpt.numBitsPerPixel = self.numBitsPerPixel;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let hipsCache = this.view.aladin.hipsCache;
|
|
||||||
|
|
||||||
|
|
||||||
if (hipsCache.contains(self.id)) {
|
|
||||||
/*HiPSCache.append(self.id, {
|
|
||||||
// Erase by the cache already put values which is considered
|
|
||||||
// as the ground truth
|
|
||||||
...HiPSCache.get[self.id],
|
|
||||||
// append new important infos from the properties queried
|
|
||||||
...surveyOpt,
|
|
||||||
});*/
|
|
||||||
hipsCache.append(self.id, this)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the ImageHiPS represents a planetary body.
|
|
||||||
*
|
|
||||||
* This method returns a boolean indicating whether the ImageHiPS corresponds to a planetary body, e.g. the earth or a celestial body.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @returns {boolean} Returns true if the ImageHiPS represents a planetary body; otherwise, returns false.
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.isPlanetaryBody = function () {
|
|
||||||
return this.hipsBody !== undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the image format for the ImageHiPS.
|
|
||||||
*
|
|
||||||
* This method updates the image format of the ImageHiPS, performs format validation, and triggers the update of metadata.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {string} format - The desired image format. Should be one of ["fits", "png", "jpg", "webp"].
|
|
||||||
*
|
|
||||||
* @throws {string} Throws an error if the provided format is not one of the supported formats or if the format is not available for the specific ImageHiPS.
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setImageFormat = function (format) {
|
|
||||||
let self = this;
|
|
||||||
self.query.then(() => {
|
|
||||||
self._updateMetadata(() => {
|
|
||||||
let imgFormat = format.toLowerCase();
|
|
||||||
|
|
||||||
if (
|
|
||||||
imgFormat !== "fits" &&
|
|
||||||
imgFormat !== "png" &&
|
|
||||||
imgFormat !== "jpg" &&
|
|
||||||
imgFormat !== "jpeg" &&
|
|
||||||
imgFormat !== "webp"
|
|
||||||
) {
|
|
||||||
throw 'Formats must lie in ["fits", "png", "jpg", "webp"]';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imgFormat === "jpg") {
|
|
||||||
imgFormat = "jpeg";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Passed the check, we erase the image format with the new one
|
|
||||||
// We do nothing if the imgFormat is the same
|
|
||||||
if (self.imgFormat === imgFormat) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
// 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";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
imgFormat === "webp" &&
|
|
||||||
availableFormats.indexOf("webp") < 0
|
|
||||||
) {
|
|
||||||
throw self.id + " does not provide webp tiles";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
imgFormat === "png" &&
|
|
||||||
availableFormats.indexOf("png") < 0
|
|
||||||
) {
|
|
||||||
throw self.id + " does not provide png tiles";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
imgFormat === "jpeg" &&
|
|
||||||
availableFormats.indexOf("jpeg") < 0
|
|
||||||
) {
|
|
||||||
throw self.id + " does not provide jpeg tiles";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch from png/webp/jpeg to fits
|
|
||||||
if (
|
|
||||||
(self.imgFormat === "png" ||
|
|
||||||
self.imgFormat === "webp" ||
|
|
||||||
self.imgFormat === "jpeg") &&
|
|
||||||
imgFormat === "fits"
|
|
||||||
) {
|
|
||||||
if (Number.isFinite(self.defaultFitsMinCut) && Number.isFinite(self.defaultFitsMaxCut)) {
|
|
||||||
// reset cuts to those given from the properties
|
|
||||||
self.setCuts(self.defaultFitsMinCut, self.defaultFitsMaxCut);
|
|
||||||
}
|
|
||||||
// Switch from fits to png/webp/jpeg
|
|
||||||
} else if (self.imgFormat === "fits") {
|
|
||||||
self.setCuts(0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if it is a fits
|
|
||||||
self.imgFormat = imgFormat;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the opacity factor when rendering the ImageHiPS
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @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.
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.getAvailableFormats = function () {
|
|
||||||
return this.formats;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the opacity factor when rendering the ImageHiPS
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {number} opacity - Opacity of the survey to set. Between 0 and 1
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setOpacity = function (opacity) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setOpacity(opacity);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the blending mode when rendering the ImageHiPS
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {boolean} [additive=false] -
|
|
||||||
*
|
|
||||||
* @description Two rendering modes are availables i.e. the default one and the additive one.
|
|
||||||
* When rendering this survey on top of the already rendered ones, the final color of the screen is computed like:
|
|
||||||
* <br>
|
|
||||||
* <br>opacity * this_survey_color + (1 - opacity) * already_rendered_color for the default mode
|
|
||||||
* <br>opacity * this_survey_color + already_rendered_color for the additive mode
|
|
||||||
* <br>
|
|
||||||
* <br>
|
|
||||||
* Additive mode allows you to do linear survey color combination i.e. let's define 3 surveys named s1, s2, s3. Each could be associated to one color channel, i.e. s1 with red, s2 with green and s3 with the blue color channel.
|
|
||||||
* If the additive blending mode is enabled, then the final pixel color of your screen will be: rgb = [s1_opacity * s1_color; s2_opacity * s2_color; s3_opacity * s3_color]
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setBlendingConfig = function (additive = false) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setBlendingConfig(additive);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the colormap when rendering the ImageHiPS.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {string} [colormap="grayscale"] - The colormap label to use. See {@link https://matplotlib.org/stable/users/explain/colors/colormaps.html|here} for more info about colormaps.
|
|
||||||
* Possible values are:
|
|
||||||
* <br>"blues"
|
|
||||||
* <br>"cividis"
|
|
||||||
* <br>"cubehelix"
|
|
||||||
* <br>"eosb"
|
|
||||||
* <br>"grayscale"
|
|
||||||
* <br>"inferno"
|
|
||||||
* <br>"magma"
|
|
||||||
* <br>"native"
|
|
||||||
* <br>"parula"
|
|
||||||
* <br>"plasma"
|
|
||||||
* <br>"rainbow"
|
|
||||||
* <br>"rdbu"
|
|
||||||
* <br>"rdylbu"
|
|
||||||
* <br>"redtemperature"
|
|
||||||
* <br>"sinebow"
|
|
||||||
* <br>"spectral"
|
|
||||||
* <br>"summer"
|
|
||||||
* <br>"viridis"
|
|
||||||
* <br>"ylgnbu"
|
|
||||||
* <br>"ylorbr"
|
|
||||||
* <br>"red"
|
|
||||||
* <br>"green"
|
|
||||||
* <br>"blue"
|
|
||||||
* @param {Object} [options] - Options for the colormap
|
|
||||||
* @param {string} [options.stretch] - Stretching function of the colormap. Possible values are 'linear', 'asinh', 'log', 'sqrt', 'pow'. If no given, will not change it.
|
|
||||||
* @param {boolean} [options.reversed=false] - Reverse the colormap axis.
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setColormap = function (colormap, options) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setColormap(colormap, options);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the gamma correction factor for the ImageHiPS.
|
|
||||||
*
|
|
||||||
* This method updates the gamma of the ImageHiPS.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {number} lowCut - The low cut value to set for the ImageHiPS.
|
|
||||||
* @param {number} highCut - The high cut value to set for the ImageHiPS.
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setCuts = function (lowCut, highCut) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setCuts(lowCut, highCut);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the gamma correction factor for the ImageHiPS.
|
|
||||||
*
|
|
||||||
* This method updates the gamma of the ImageHiPS.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {number} gamma - The saturation value to set for the ImageHiPS. Between 0.1 and 10
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setGamma = function (gamma) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setGamma(gamma);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the saturation for the ImageHiPS.
|
|
||||||
*
|
|
||||||
* This method updates the saturation of the ImageHiPS.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {number} saturation - The saturation value to set for the ImageHiPS. Between 0 and 1
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setSaturation = function (saturation) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setSaturation(saturation);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the brightness for the ImageHiPS.
|
|
||||||
*
|
|
||||||
* This method updates the brightness of the ImageHiPS.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {number} brightness - The brightness value to set for the ImageHiPS. Between 0 and 1
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setBrightness = function (brightness) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setBrightness(brightness);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the contrast for the ImageHiPS.
|
|
||||||
*
|
|
||||||
* This method updates the contrast of the ImageHiPS and triggers the update of metadata.
|
|
||||||
*
|
|
||||||
* @memberof ImageHiPS
|
|
||||||
*
|
|
||||||
* @param {number} contrast - The contrast value to set for the ImageHiPS. Between 0 and 1
|
|
||||||
*/
|
|
||||||
ImageHiPS.prototype.setContrast = function (contrast) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg.setContrast(contrast);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Private method for updating the backend with the new meta
|
|
||||||
ImageHiPS.prototype._updateMetadata = function (callback) {
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the view its meta have changed
|
|
||||||
try {
|
|
||||||
if (this.added) {
|
|
||||||
this.view.wasm.setImageMetadata(this.layer, {
|
|
||||||
...this.colorCfg.get(),
|
|
||||||
longitudeReversed: this.longitudeReversed,
|
|
||||||
imgFormat: this.imgFormat,
|
|
||||||
});
|
|
||||||
// once the meta have been well parsed, we can set the meta
|
|
||||||
ALEvent.HIPS_LAYER_CHANGED.dispatchedTo(this.view.aladinDiv, {
|
|
||||||
layer: this,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// save it in the JS HiPS cache
|
|
||||||
this._saveInCache();
|
|
||||||
} catch (e) {
|
|
||||||
// Display the error message
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ImageHiPS.prototype.add = function (layer) {
|
|
||||||
this.layer = layer;
|
|
||||||
let self = this;
|
|
||||||
|
|
||||||
this.view.wasm.addImageHiPS({
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.resolve(this)
|
|
||||||
.then((hips) => {
|
|
||||||
if (hips.successCallback) {
|
|
||||||
hips.successCallback(hips)
|
|
||||||
}
|
|
||||||
|
|
||||||
return hips
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
|
||||||
ImageHiPS.prototype.toggle = function () {
|
|
||||||
if (this.colorCfg.getOpacity() != 0.0) {
|
|
||||||
this.colorCfg.setOpacity(0.0);
|
|
||||||
} else {
|
|
||||||
this.colorCfg.setOpacity(this.prevOpacity);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// @oldapi
|
|
||||||
ImageHiPS.prototype.setAlpha = ImageHiPS.prototype.setOpacity;
|
|
||||||
|
|
||||||
ImageHiPS.prototype.setColorCfg = function (colorCfg) {
|
|
||||||
this._updateMetadata(() => {
|
|
||||||
this.colorCfg = colorCfg;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
|
||||||
ImageHiPS.prototype.getColorCfg = function () {
|
|
||||||
return this.colorCfg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// @api
|
|
||||||
ImageHiPS.prototype.getOpacity = function () {
|
|
||||||
return this.colorCfg.getOpacity();
|
|
||||||
};
|
|
||||||
|
|
||||||
ImageHiPS.prototype.getAlpha = ImageHiPS.prototype.getOpacity;
|
|
||||||
|
|
||||||
// @api
|
|
||||||
ImageHiPS.prototype.readPixel = function (x, y) {
|
|
||||||
return this.view.wasm.readPixel(x, y, this.layer);
|
|
||||||
};
|
|
||||||
|
|
||||||
ImageHiPS.DEFAULT_SURVEY_ID = "CDS/P/DSS2/color";
|
|
||||||
|
|
||||||
return ImageHiPS;
|
|
||||||
})();
|
|
||||||
@@ -47,7 +47,7 @@ import { ObsCore } from "./vo/ObsCore.js";
|
|||||||
import { DefaultActionsForContextMenu } from "./DefaultActionsForContextMenu.js";
|
import { DefaultActionsForContextMenu } from "./DefaultActionsForContextMenu.js";
|
||||||
import { Layout } from "./gui/Layout.js";
|
import { Layout } from "./gui/Layout.js";
|
||||||
import { SAMPActionButton } from "./gui/Button/SAMP.js";
|
import { SAMPActionButton } from "./gui/Button/SAMP.js";
|
||||||
import { ImageHiPS } from "./ImageHiPS.js";
|
import { HiPS } from "./HiPS.js";
|
||||||
import { Image } from "./Image.js";
|
import { Image } from "./Image.js";
|
||||||
|
|
||||||
export let View = (function () {
|
export let View = (function () {
|
||||||
@@ -490,6 +490,16 @@ export let View = (function () {
|
|||||||
ctx.drawImage(canvas, 0, 0, c.width, c.height);
|
ctx.drawImage(canvas, 0, 0, c.width, c.height);
|
||||||
ctx.drawImage(this.catalogCanvas, 0, 0, c.width, c.height);
|
ctx.drawImage(this.catalogCanvas, 0, 0, c.width, c.height);
|
||||||
|
|
||||||
|
// draw the reticle if it is on the view
|
||||||
|
let reticle = this.aladin.reticle;
|
||||||
|
if (reticle.isVisible()) {
|
||||||
|
var svgBlob = new Blob([reticle.el.innerHTML], {type: 'image/svg+xml;charset=utf-8'});
|
||||||
|
const reticleImg = await loadImage(URL.createObjectURL(svgBlob));
|
||||||
|
|
||||||
|
const posX = (c.width - reticleImg.width)/2.0;
|
||||||
|
const posY = (c.height - reticleImg.height)/2.0;
|
||||||
|
ctx.drawImage(reticleImg, posX, posY);
|
||||||
|
}
|
||||||
|
|
||||||
if(withLogo) {
|
if(withLogo) {
|
||||||
const logo = await loadImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI4AAABTCAMAAAB+g8/LAAACx1BMVEVMaXGBYYSWk5i7ur1fGUW0Fzbi4OP////Qz9K2s7f////qyseffX7TxczMytBXU1ndrahOWXi0o7RaH0v///+1GjfYkY29srb///+1GTe0Fzajn6RgFkFdHkni3+GLV3PU0dXMubr6+vpmIktUJVKiGDqGcX7p5ujLwMJgFkFgFkFNOWnp1tZaHUi0FzaEZohkX2VVKVXUwcvy8vI4U4tQMWBXIk+NGT9ZIEx+Wn5vF0EUYqF3c3lgFkL5+PkUYqH///////9lFkG0FzYUYqFeNF/BwMs2WpP6+vrBv8JSJ1TNy85TJlO0FzaJhYsUYqF5GEEUYqF2Zo60FzazFza0FzYUYqGWdIsrWpWTGj6jGDp3Kk58Y4S0FzZgFkFXIU2OiY+vmqVhGENlGEJqQ2z///9SKFJTJlP///9pF0GOjpd0Ol6rFzi9sbm0Fza0FzYUYqGXmLp3TXJmHkhLSXy/jJBVK1ivrLDu7e7l5OYLCw6AYYRpFkGCIUYVYqGAZoqJfofez9hZPGtcW4phFkIUYqGVbG1BToTFw8ZqZGr4+PmIGkAWYqD6+vpaHUoUYqGEZoh5ZH2ceYAbGyCmFzmgGjsUYqGAYIOuiJJ3SW1PZJlNM0OliJ+MQF5uF0Gcmp8kXZpSKFWEZojDwcXq1tQzVY9pN2CyFzbZlZFHbKOZgpWjnaRlMlsUYqGHGD9FRElaHUiZfpfW1dddW2HMtsJ3k8NTJlPDT1WlMElcGkY6UYjMa2tDSH3IpKOEZoiFTWqni54DAwQsLDGsqa3Pu8cUFBnEtr8gHyU4Nz3cwsMKDA/GV1tGRUtCKjDczM7NfXzMvcza1Nv///+9PUmhfZRxY2y2KT/15eLo4ud5fKXCXmTnu7ekZ3pgFkFTJlOEZoiUGT5aHkp8GEBzF0G0FzadGDtKQnNeJ1JqJk5fGEReGkaDGT8UYqGlSw8iAAAAwXRSTlMA87vu8R/SwN6iQP7+/vf9/J75s4DT/v0gokr33vzj++7+9/Hz8/3u1tFw9P4f5nP9cvl0/vb+/vL79HH9++WPMFA7s1r++vRhscXEiWT9PvLQ+Ffzih/9/vb+9z3Enn7N/cWI/RDWPND+9/38gTx6uPj5/fn+/efauu7k8fnl0+ro/f33wvj7meDU2PeaZquWH9jJ1O0QrPfC0vXo+uHj+J7ETZvkpfzI+6e44qCorUr22cpX3xDd9VdUvtb6V9z+sGF5dwAACP1JREFUeF7s011r01AcBvATON8gFCgkV+2AFrKSm5MGCEKlDIqCgEgpXYUaOkanQLrtpupgCxTY8A3EDWToYBNlgFeiIOIX+f/z0pe96IcwSZtRxY0ByXaT3204nIfnPCHXLJFIJBKJgoe8LLyp/+fbPXJ16mvW3k7XsjiOs3xGd+1FoVAn12Hh1g7HqcYqMsdxGAZ0K8B15avOUkGPQymFvm0Plb6InrKOuqEbqoHVd1vPSfxk+fvT/VZRpBQ0aoLPtRW7VptRKD0VGTKcmNva/0biJPmVjDZUtXN8egKBXIM3IeC64NEohHlGvV6WxOcTj4hHhmq015dHyASh0ciXSKjUhAka5in21AMSi0ev3v7UEfEEjM5Rtbd+mPssSeQfz8JEIgZoR7VIHB6ubFvj4WqQ4xvnTqIkgE+j6KPQiSHOe54vlx0Krj38BYJ08bp27UUAcZyHQibiOJIsV9DXV4a1mrKYk8jFSndn+qCJwXuJZmYt2mKy6HvyemlJ8Zd7iSO3Bx8ANKCITDONQpTVtNCzam2vfHVBOK+OvLek/FRpmy4ABWBIob0X5TsF1Th6FY/NHC9NN5BOzadvzg5m06ldmGiSiQYAOCYwBpmNHyQaX+QW+ljbPDjkH5CJheCnnx+MDZU7j+FMcyqOSDU0Ye5jNL1UshhwaNvwo4SK4mYqNQjZGvzl/lkck1GKsPz7xiUu+0Nq2b+2VYVx/NDZJTYmnV2TpuvMsiJNhbSUZmMwSpssENJl7XSmrrDNpkpn3dqO4eraoqXFMmddBWcVncImDpgOMKiiImJu3t+Wl9a54UiccOxA8keY+5xzc25ugiTx+9s5fHL55D7nPM9dk5FY6NpO1wVgJ8g0pVIpv793mWLP31JEeiMKiCa5yeu8CRIeP8STySzLIMv5VSrl+e1YLne0Ap3BMMcnNE/XdV5Ybyer+lcOZyGeIsyKn+AxSDR8qcVwq9X6Lj+sDuwlm8FMJsiJ4o2fSX9fyeeXuY2D6MrpvDz1KEtylmIG/uh2Y6ZDlOomGxBaxx86CzovybniRG12VEEMUaCXLGV03svSPPaMXsBG8jKCDssHc3aE1BgLOj9OCzoshoYKdExxYL3zpTpuODZbo6+f7hKw0A5e5sBDqQ63MGcfwkxnHZXqeL+pQEd7kbpLdY5kwebt0f1HeGwbwYy8zsGMC7Ain9UfmE5va32pDqfXVuCjCwB73Vys0wUy+0f3fV6EeWLqkRn0U13QR9MTEOql4HXI5nZE304Ilo2E6KmkWnYCh9eKdMhI2LpxwU2xaYp10lZsdWKsbj138klVD/X55Q+Mnc/mOyC0bKLjvf3c4sBJB7mX8ekKdCb0rFpMh7ThrcPCNJhRK9kVrG/txkKGkMvHQe48wOpdu1dop6Q6j6N8Glxs8R9pgNAyXDSLdIJZyE4B+zkWS4QE7Fw33oyRYKxGyEWLYVTXmz/5jn+kGY0FRQYT8kp0tJPNfDb6AI6bpDrURtt/U6PRzArYTX5IaXZo+NzDGI+g99NE5/ivu5ebIbKxv1rEBhXpmL6F0yYn1YrqpDpjFHsHsCaKJUR9JwI66Dp5cY2fHaL3SZ75p3qd1QV4yLSDlkEr0mE2XcYQYF9RbHyzSMeaR66SpnS6GcmFrvzIVq2OthMgn9YyTP6cSawj2LhPJGCnrYAlxTrOeoROXSKH52umc2FfVTqsCFE9QgagAw6RztNuavNG8i7s5DE9wSIiHesuNNONP/ZKdFS5RXm1Oqtwo8KDhbGun0DIRXUKNlNGKab8HXRo8x5xYkyP8m1LQWcAVauj1QEz/AVC5jOkDHbk7mAzi9hsklr1ibAk04GBOksb4by2y8bRn1elw2rFqWACwLwOda6/WqTjXpnCyR6GGQAL7FWfuspuFk7aomRK9L+40lKzzhwUIQBNfzAOvOpgRqxzaOVvjCMi7HJc6N91gs7DE+M+OrWW9mSequ3tsFo19svymWwjFdlT0OF3dRGFIpkog1kEnZag0hfmSO4YX9u6UrOOqYcrSWic6LB4H5TDHENwdooSMB6/AfepNh2olTTpEh1jOUyJS3QCCU/uygCqUQfmeGmGz0p0wvfLYjGpTih9/ti1F1CtOvCVU5qwR/KZd7etLDbbIcHaz+euIVS7jiPAlYsKziiLr688tsSwhU877tu+XDyK/ofOxIZMHH3KD4m0D6q2QVpINu4p8lHyiQCRUCh6lYb2tUkZRJdI+5v+fCs38BGCyGgQaofHqC7DtrD4tx07aGkbDAM4/hTmB5gFhqAILAFs0SHYpqaMwkwRhtBWtmp0FobFURqw1uJlaQdO6SVMB0zZmNCeelLmbd1p32CXIjj2BNNkZUnyIZa0tKlujAFtveR3ed/b++fhvbwv/JcvDVFDmaSQg7YzSrkhile6MjW3OQQt4Ekkxp/PhsPJmRgDvZQp3mdlXVE4Bdo8tP36pqI0z/MP8d1T6FIdVWeXxEDW9TICPRUXfFwFzRzliZ0T/UnV63XqyhqL5Y77EXR58D5dW/KryUXXIfTY6TzBss2cNTsHdVlOIVIcRSPi3vq1lmNXdrx2guF548NbgJ4PR02lsG7mjEDHKCJP0/wen5hITEK3Y5crvY1oxRRC0HMHMyparudA1T0x0SmxTbqzaTTtzhvCaRx6blLwYTtnCv5paHPkbNSKGcuVDCF4BH1QXg50cuzx/GlzZO3iG5nO1jBcNIxCEPpjoyFhE0WSCgd/88IzZ/26kT++tq6MEItAv2yI2u4YoqZpiKR+8x+9ulB+TIiSTHKsjL+aVybGHEH/lEXMhRElUULUFZ1f94DlzfT0gntjJ5kVTX5JRZ0lKyclI8NAX00TGiKqhN9cUmSF06Mpmq7L2wHRxq5UFOXzyetMKA79RgQQ0TycCEgqpnRdJ/NsXkaU8kvnH4fvnSe9Oe9qfnXZ2I/DAHwq5cY0QrT4Ec0d4feLor5y8X14a+vycnExFotlQgwMSkQo+cRWD2EuLTve3LIh7L86fAaDFr/rbRgzXsuOz+fzFnNFo3AQZODWMJmCYdsPReDWMXEm2NTd4nA4HA6H4zc5mbo+QO8AVQAAAABJRU5ErkJggg==")
|
const logo = await loadImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI4AAABTCAMAAAB+g8/LAAACx1BMVEVMaXGBYYSWk5i7ur1fGUW0Fzbi4OP////Qz9K2s7f////qyseffX7TxczMytBXU1ndrahOWXi0o7RaH0v///+1GjfYkY29srb///+1GTe0Fzajn6RgFkFdHkni3+GLV3PU0dXMubr6+vpmIktUJVKiGDqGcX7p5ujLwMJgFkFgFkFNOWnp1tZaHUi0FzaEZohkX2VVKVXUwcvy8vI4U4tQMWBXIk+NGT9ZIEx+Wn5vF0EUYqF3c3lgFkL5+PkUYqH///////9lFkG0FzYUYqFeNF/BwMs2WpP6+vrBv8JSJ1TNy85TJlO0FzaJhYsUYqF5GEEUYqF2Zo60FzazFza0FzYUYqGWdIsrWpWTGj6jGDp3Kk58Y4S0FzZgFkFXIU2OiY+vmqVhGENlGEJqQ2z///9SKFJTJlP///9pF0GOjpd0Ol6rFzi9sbm0Fza0FzYUYqGXmLp3TXJmHkhLSXy/jJBVK1ivrLDu7e7l5OYLCw6AYYRpFkGCIUYVYqGAZoqJfofez9hZPGtcW4phFkIUYqGVbG1BToTFw8ZqZGr4+PmIGkAWYqD6+vpaHUoUYqGEZoh5ZH2ceYAbGyCmFzmgGjsUYqGAYIOuiJJ3SW1PZJlNM0OliJ+MQF5uF0Gcmp8kXZpSKFWEZojDwcXq1tQzVY9pN2CyFzbZlZFHbKOZgpWjnaRlMlsUYqGHGD9FRElaHUiZfpfW1dddW2HMtsJ3k8NTJlPDT1WlMElcGkY6UYjMa2tDSH3IpKOEZoiFTWqni54DAwQsLDGsqa3Pu8cUFBnEtr8gHyU4Nz3cwsMKDA/GV1tGRUtCKjDczM7NfXzMvcza1Nv///+9PUmhfZRxY2y2KT/15eLo4ud5fKXCXmTnu7ekZ3pgFkFTJlOEZoiUGT5aHkp8GEBzF0G0FzadGDtKQnNeJ1JqJk5fGEReGkaDGT8UYqGlSw8iAAAAwXRSTlMA87vu8R/SwN6iQP7+/vf9/J75s4DT/v0gokr33vzj++7+9/Hz8/3u1tFw9P4f5nP9cvl0/vb+/vL79HH9++WPMFA7s1r++vRhscXEiWT9PvLQ+Ffzih/9/vb+9z3Enn7N/cWI/RDWPND+9/38gTx6uPj5/fn+/efauu7k8fnl0+ro/f33wvj7meDU2PeaZquWH9jJ1O0QrPfC0vXo+uHj+J7ETZvkpfzI+6e44qCorUr22cpX3xDd9VdUvtb6V9z+sGF5dwAACP1JREFUeF7s011r01AcBvATON8gFCgkV+2AFrKSm5MGCEKlDIqCgEgpXYUaOkanQLrtpupgCxTY8A3EDWToYBNlgFeiIOIX+f/z0pe96IcwSZtRxY0ByXaT3204nIfnPCHXLJFIJBKJgoe8LLyp/+fbPXJ16mvW3k7XsjiOs3xGd+1FoVAn12Hh1g7HqcYqMsdxGAZ0K8B15avOUkGPQymFvm0Plb6InrKOuqEbqoHVd1vPSfxk+fvT/VZRpBQ0aoLPtRW7VptRKD0VGTKcmNva/0biJPmVjDZUtXN8egKBXIM3IeC64NEohHlGvV6WxOcTj4hHhmq015dHyASh0ciXSKjUhAka5in21AMSi0ev3v7UEfEEjM5Rtbd+mPssSeQfz8JEIgZoR7VIHB6ubFvj4WqQ4xvnTqIkgE+j6KPQiSHOe54vlx0Krj38BYJ08bp27UUAcZyHQibiOJIsV9DXV4a1mrKYk8jFSndn+qCJwXuJZmYt2mKy6HvyemlJ8Zd7iSO3Bx8ANKCITDONQpTVtNCzam2vfHVBOK+OvLek/FRpmy4ABWBIob0X5TsF1Th6FY/NHC9NN5BOzadvzg5m06ldmGiSiQYAOCYwBpmNHyQaX+QW+ljbPDjkH5CJheCnnx+MDZU7j+FMcyqOSDU0Ye5jNL1UshhwaNvwo4SK4mYqNQjZGvzl/lkck1GKsPz7xiUu+0Nq2b+2VYVx/NDZJTYmnV2TpuvMsiJNhbSUZmMwSpssENJl7XSmrrDNpkpn3dqO4eraoqXFMmddBWcVncImDpgOMKiiImJu3t+Wl9a54UiccOxA8keY+5xzc25ugiTx+9s5fHL55D7nPM9dk5FY6NpO1wVgJ8g0pVIpv793mWLP31JEeiMKiCa5yeu8CRIeP8STySzLIMv5VSrl+e1YLne0Ap3BMMcnNE/XdV5Ybyer+lcOZyGeIsyKn+AxSDR8qcVwq9X6Lj+sDuwlm8FMJsiJ4o2fSX9fyeeXuY2D6MrpvDz1KEtylmIG/uh2Y6ZDlOomGxBaxx86CzovybniRG12VEEMUaCXLGV03svSPPaMXsBG8jKCDssHc3aE1BgLOj9OCzoshoYKdExxYL3zpTpuODZbo6+f7hKw0A5e5sBDqQ63MGcfwkxnHZXqeL+pQEd7kbpLdY5kwebt0f1HeGwbwYy8zsGMC7Ain9UfmE5va32pDqfXVuCjCwB73Vys0wUy+0f3fV6EeWLqkRn0U13QR9MTEOql4HXI5nZE304Ilo2E6KmkWnYCh9eKdMhI2LpxwU2xaYp10lZsdWKsbj138klVD/X55Q+Mnc/mOyC0bKLjvf3c4sBJB7mX8ekKdCb0rFpMh7ThrcPCNJhRK9kVrG/txkKGkMvHQe48wOpdu1dop6Q6j6N8Glxs8R9pgNAyXDSLdIJZyE4B+zkWS4QE7Fw33oyRYKxGyEWLYVTXmz/5jn+kGY0FRQYT8kp0tJPNfDb6AI6bpDrURtt/U6PRzArYTX5IaXZo+NzDGI+g99NE5/ivu5ebIbKxv1rEBhXpmL6F0yYn1YrqpDpjFHsHsCaKJUR9JwI66Dp5cY2fHaL3SZ75p3qd1QV4yLSDlkEr0mE2XcYQYF9RbHyzSMeaR66SpnS6GcmFrvzIVq2OthMgn9YyTP6cSawj2LhPJGCnrYAlxTrOeoROXSKH52umc2FfVTqsCFE9QgagAw6RztNuavNG8i7s5DE9wSIiHesuNNONP/ZKdFS5RXm1Oqtwo8KDhbGun0DIRXUKNlNGKab8HXRo8x5xYkyP8m1LQWcAVauj1QEz/AVC5jOkDHbk7mAzi9hsklr1ibAk04GBOksb4by2y8bRn1elw2rFqWACwLwOda6/WqTjXpnCyR6GGQAL7FWfuspuFk7aomRK9L+40lKzzhwUIQBNfzAOvOpgRqxzaOVvjCMi7HJc6N91gs7DE+M+OrWW9mSequ3tsFo19svymWwjFdlT0OF3dRGFIpkog1kEnZag0hfmSO4YX9u6UrOOqYcrSWic6LB4H5TDHENwdooSMB6/AfepNh2olTTpEh1jOUyJS3QCCU/uygCqUQfmeGmGz0p0wvfLYjGpTih9/ti1F1CtOvCVU5qwR/KZd7etLDbbIcHaz+euIVS7jiPAlYsKziiLr688tsSwhU877tu+XDyK/ofOxIZMHH3KD4m0D6q2QVpINu4p8lHyiQCRUCh6lYb2tUkZRJdI+5v+fCs38BGCyGgQaofHqC7DtrD4tx07aGkbDAM4/hTmB5gFhqAILAFs0SHYpqaMwkwRhtBWtmp0FobFURqw1uJlaQdO6SVMB0zZmNCeelLmbd1p32CXIjj2BNNkZUnyIZa0tKlujAFtveR3ed/b++fhvbwv/JcvDVFDmaSQg7YzSrkhile6MjW3OQQt4Ekkxp/PhsPJmRgDvZQp3mdlXVE4Bdo8tP36pqI0z/MP8d1T6FIdVWeXxEDW9TICPRUXfFwFzRzliZ0T/UnV63XqyhqL5Y77EXR58D5dW/KryUXXIfTY6TzBss2cNTsHdVlOIVIcRSPi3vq1lmNXdrx2guF548NbgJ4PR02lsG7mjEDHKCJP0/wen5hITEK3Y5crvY1oxRRC0HMHMyparudA1T0x0SmxTbqzaTTtzhvCaRx6blLwYTtnCv5paHPkbNSKGcuVDCF4BH1QXg50cuzx/GlzZO3iG5nO1jBcNIxCEPpjoyFhE0WSCgd/88IzZ/26kT++tq6MEItAv2yI2u4YoqZpiKR+8x+9ulB+TIiSTHKsjL+aVybGHEH/lEXMhRElUULUFZ1f94DlzfT0gntjJ5kVTX5JRZ0lKyclI8NAX00TGiKqhN9cUmSF06Mpmq7L2wHRxq5UFOXzyetMKA79RgQQ0TycCEgqpnRdJ/NsXkaU8kvnH4fvnSe9Oe9qfnXZ2I/DAHwq5cY0QrT4Ec0d4feLor5y8X14a+vycnExFotlQgwMSkQo+cRWD2EuLTve3LIh7L86fAaDFr/rbRgzXsuOz+fzFnNFo3AQZODWMJmCYdsPReDWMXEm2NTd4nA4HA6H4zc5mbo+QO8AVQAAAABJRU5ErkJggg==")
|
||||||
@@ -499,7 +509,6 @@ export let View = (function () {
|
|||||||
ctx.drawImage(logo, offX, offY);
|
ctx.drawImage(logo, offX, offY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,14 +625,17 @@ export let View = (function () {
|
|||||||
var objClickedFunction = view.aladin.callbacksByEventName['objectClicked'];
|
var objClickedFunction = view.aladin.callbacksByEventName['objectClicked'];
|
||||||
var footprintClickedFunction = view.aladin.callbacksByEventName['footprintClicked'];
|
var footprintClickedFunction = view.aladin.callbacksByEventName['footprintClicked'];
|
||||||
|
|
||||||
|
let objsByCats = {};
|
||||||
for (let o of objs) {
|
for (let o of objs) {
|
||||||
// footprint selection code adapted from Fabrizio Giordano dev. from Serco for ESA/ESDC
|
// classify the different objects by catalog
|
||||||
/*
|
let cat = o.getCatalog && o.getCatalog();
|
||||||
if (view.lastClickedObject) {
|
if (cat && cat.name) {
|
||||||
view.lastClickedObject.actionOtherObjectClicked
|
if (!objsByCats[cat.name]) {
|
||||||
view.lastClickedObject.actionOtherObjectClicked();
|
objsByCats[cat.name] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
objsByCats[cat.name].push(o);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
(typeof objClickedFunction === 'function') && objClickedFunction(o, xy);
|
(typeof objClickedFunction === 'function') && objClickedFunction(o, xy);
|
||||||
|
|
||||||
@@ -634,23 +646,15 @@ export let View = (function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view.selectObjects([objs]);
|
// rewrite objs
|
||||||
|
objs = Array.from(Object.values(objsByCats));
|
||||||
|
view.selectObjects(objs);
|
||||||
view.lastClickedObject = objs;
|
view.lastClickedObject = objs;
|
||||||
} else {
|
} else {
|
||||||
// If there is a past clicked object
|
// If there is a past clicked object
|
||||||
if (view.lastClickedObject) {
|
if (view.lastClickedObject) {
|
||||||
//view.aladin.measurementTable.hide();
|
|
||||||
//view.aladin.sodaForm.hide();
|
|
||||||
view.aladin.popup.hide();
|
view.aladin.popup.hide();
|
||||||
|
|
||||||
// Deselect the last clicked object
|
|
||||||
/*if (view.lastClickedObject instanceof Ellipse || view.lastClickedObject instanceof Circle || view.lastClickedObject instanceof Polyline) {
|
|
||||||
view.lastClickedObject.deselect();
|
|
||||||
} else {
|
|
||||||
// Case where lastClickedObject is a Source
|
|
||||||
view.lastClickedObject.actionOtherObjectClicked();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// TODO: do we need to keep that triggering ?
|
// TODO: do we need to keep that triggering ?
|
||||||
var objClickedFunction = view.aladin.callbacksByEventName['objectClicked'];
|
var objClickedFunction = view.aladin.callbacksByEventName['objectClicked'];
|
||||||
(typeof objClickedFunction === 'function') && objClickedFunction(null, xy);
|
(typeof objClickedFunction === 'function') && objClickedFunction(null, xy);
|
||||||
@@ -740,7 +744,7 @@ export let View = (function () {
|
|||||||
view.setCursor('move');
|
view.setCursor('move');
|
||||||
}
|
}
|
||||||
|
|
||||||
view.wasm.pressLeftMouseButton(view.dragCoo.x, view.dragCoo.y);
|
view.wasm.pressLeftMouseButton();
|
||||||
|
|
||||||
if (view.mode === View.SELECT) {
|
if (view.mode === View.SELECT) {
|
||||||
view.selector.dispatch('mousedown', {coo: xymouse})
|
view.selector.dispatch('mousedown', {coo: xymouse})
|
||||||
@@ -899,7 +903,7 @@ export let View = (function () {
|
|||||||
view.refreshProgressiveCats();
|
view.refreshProgressiveCats();
|
||||||
|
|
||||||
//view.requestRedraw();
|
//view.requestRedraw();
|
||||||
view.wasm.releaseLeftButtonMouse(xymouse.x, xymouse.y);
|
view.wasm.releaseLeftButtonMouse();
|
||||||
|
|
||||||
if (view.mode === View.SELECT && e.type === "click") {
|
if (view.mode === View.SELECT && e.type === "click") {
|
||||||
view.selector.dispatch('click', {coo: xymouse})
|
view.selector.dispatch('click', {coo: xymouse})
|
||||||
@@ -1208,37 +1212,20 @@ export let View = (function () {
|
|||||||
if (isTouchPad) {
|
if (isTouchPad) {
|
||||||
if (!view.throttledTouchPadZoom) {
|
if (!view.throttledTouchPadZoom) {
|
||||||
//let radec;
|
//let radec;
|
||||||
view.throttledTouchPadZoom = Utils.throttle(() => {
|
view.throttledTouchPadZoom = () => {
|
||||||
/*if (!view.zoom.isZooming && !view.wheelTriggered) {
|
/*if (!view.zoom.isZooming && !view.wheelTriggered) {
|
||||||
// start zooming detected
|
// start zooming detected
|
||||||
radec = view.aladin.pix2world(view.xy.x, view.xy.y);
|
radec = view.aladin.pix2world(view.xy.x, view.xy.y);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
const factor = 4;
|
const factor = 2.0;
|
||||||
let newFov = view.delta > 0 ? view.fov * factor : view.fov / factor;
|
let newFov = view.delta > 0 ? view.fov * factor : view.fov / factor;
|
||||||
|
|
||||||
view.zoom.apply({
|
view.zoom.apply({
|
||||||
stop: newFov,
|
stop: newFov,
|
||||||
duration: 300
|
duration: 100
|
||||||
});
|
});
|
||||||
|
};
|
||||||
/*if (amount > 0 && radec) {
|
|
||||||
let sRaDec = view.aladin.getRaDec();
|
|
||||||
|
|
||||||
let moveTo = function() {
|
|
||||||
const t = 1 - (view.x - view.x1) / (view.x2 - view.x1);
|
|
||||||
|
|
||||||
let ra = (0.5 + t*0.5) * sRaDec[0] + (0.5 - t*0.5) * radec[0]
|
|
||||||
let dec = (0.5 + t*0.5) * sRaDec[1] + (0.5 - t*0.5) * radec[1]
|
|
||||||
|
|
||||||
view.aladin.gotoRaDec(ra, dec)
|
|
||||||
|
|
||||||
if (t >= 1e-2)
|
|
||||||
requestAnimFrame(moveTo)
|
|
||||||
}
|
|
||||||
//requestAnimFrame(moveTo)
|
|
||||||
}*/
|
|
||||||
}, 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view.throttledTouchPadZoom();
|
view.throttledTouchPadZoom();
|
||||||
@@ -1488,6 +1475,11 @@ export let View = (function () {
|
|||||||
objListPerCatalog.forEach((obj) => {
|
objListPerCatalog.forEach((obj) => {
|
||||||
obj.select();
|
obj.select();
|
||||||
|
|
||||||
|
if (!obj.getCatalog) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// For objects belonging a catalog
|
||||||
|
|
||||||
let cat = obj.getCatalog();
|
let cat = obj.getCatalog();
|
||||||
|
|
||||||
// trigger the non action clicked if it does not show the table
|
// trigger the non action clicked if it does not show the table
|
||||||
@@ -1503,6 +1495,10 @@ export let View = (function () {
|
|||||||
// show the objects from catalogs having the onClick = "showTable" field
|
// show the objects from catalogs having the onClick = "showTable" field
|
||||||
let tables = this.selection
|
let tables = this.selection
|
||||||
.filter(objList => {
|
.filter(objList => {
|
||||||
|
if (!objList[0].getCatalog) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let cat = objList[0].getCatalog();
|
let cat = objList[0].getCatalog();
|
||||||
return cat && cat.onClick && cat.onClick == 'showTable';
|
return cat && cat.onClick && cat.onClick == 'showTable';
|
||||||
})
|
})
|
||||||
@@ -1712,7 +1708,7 @@ export let View = (function () {
|
|||||||
Promise.allSettled(this.promises)
|
Promise.allSettled(this.promises)
|
||||||
.then(() => imageLayerPromise)
|
.then(() => imageLayerPromise)
|
||||||
// The promise is resolved and we now have access
|
// The promise is resolved and we now have access
|
||||||
// to the image layer objet (whether it is an ImageHiPS or an Image)
|
// to the image layer objet (whether it is an HiPS or an Image)
|
||||||
.then((imageLayer) => {
|
.then((imageLayer) => {
|
||||||
// Add to the backend
|
// Add to the backend
|
||||||
const promise = imageLayer.add(layer);
|
const promise = imageLayer.add(layer);
|
||||||
@@ -1860,7 +1856,7 @@ export let View = (function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
View.prototype.contains = function(survey) {
|
View.prototype.contains = function(survey) {
|
||||||
if (survey instanceof ImageHiPS || survey instanceof Image) {
|
if (survey instanceof HiPS || survey instanceof Image) {
|
||||||
if (survey.added === true) {
|
if (survey.added === true) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,9 +51,12 @@ export class HiPSBrowserBox extends Box {
|
|||||||
let self;
|
let self;
|
||||||
|
|
||||||
MocServer.getAllHiPSes().then((HiPSes) => {
|
MocServer.getAllHiPSes().then((HiPSes) => {
|
||||||
|
HiPSBrowserBox.HiPSList = {}
|
||||||
// Fill the HiPSList from the MOCServer
|
// Fill the HiPSList from the MOCServer
|
||||||
HiPSes.forEach((h) => {
|
HiPSes.forEach((h) => {
|
||||||
HiPSBrowserBox.HiPSList[h.obs_title] = h;
|
let name = h.obs_title;
|
||||||
|
name = name.replace(/:|\'/g, '');
|
||||||
|
HiPSBrowserBox.HiPSList[name] = h;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize the autocompletion without any filtering
|
// Initialize the autocompletion without any filtering
|
||||||
@@ -70,7 +73,6 @@ export class HiPSBrowserBox extends Box {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Or he can select a HiPS from the list given
|
// Or he can select a HiPS from the list given
|
||||||
const hips = HiPSBrowserBox.HiPSList[value];
|
const hips = HiPSBrowserBox.HiPSList[value];
|
||||||
|
|
||||||
if (hips) {
|
if (hips) {
|
||||||
image = hips.ID || hips.hips_service_url;
|
image = hips.ID || hips.hips_service_url;
|
||||||
} else {
|
} else {
|
||||||
@@ -304,14 +306,16 @@ export class HiPSBrowserBox extends Box {
|
|||||||
|
|
||||||
for (var key in HiPSBrowserBox.HiPSList) {
|
for (var key in HiPSBrowserBox.HiPSList) {
|
||||||
let HiPS = HiPSBrowserBox.HiPSList[key];
|
let HiPS = HiPSBrowserBox.HiPSList[key];
|
||||||
|
|
||||||
// apply filtering
|
// apply filtering
|
||||||
if (
|
if (
|
||||||
self.filterCallback &&
|
self.filterCallback &&
|
||||||
self.filterCallback(HiPS, params)
|
self.filterCallback(HiPS, params)
|
||||||
) {
|
) {
|
||||||
// search with the name or id
|
// search with the name or id
|
||||||
HiPSIDs.push(HiPS.obs_title);
|
let name = HiPS.obs_title;
|
||||||
|
name = name.replace(/:|\'/g, "");
|
||||||
|
|
||||||
|
HiPSIDs.push(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -528,7 +528,7 @@ export class OverlayStackBox extends Box {
|
|||||||
position: self.position,
|
position: self.position,
|
||||||
});*/
|
});*/
|
||||||
self.aladin.addNewImageLayer(
|
self.aladin.addNewImageLayer(
|
||||||
A.imageHiPS('CDS/P/DSS2/color', {
|
A.imageHiPS('P/DSS2/color', {
|
||||||
errorCallback: (e) => {
|
errorCallback: (e) => {
|
||||||
aladin.addStatusBarMessage({
|
aladin.addStatusBarMessage({
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import { Utils } from "../../Utils";
|
|||||||
import { Layout } from "../Layout";
|
import { Layout } from "../Layout";
|
||||||
import infoIconUrl from '../../../../assets/icons/info.svg';
|
import infoIconUrl from '../../../../assets/icons/info.svg';
|
||||||
import tooltipIconUrl from '../../../../assets/icons/tooltip.svg';
|
import tooltipIconUrl from '../../../../assets/icons/tooltip.svg';
|
||||||
|
import aladinLogoGif from '../../../../assets/aladin-logo.gif';
|
||||||
|
|
||||||
import { Icon } from "../Widgets/Icon";
|
import { Icon } from "../Widgets/Icon";
|
||||||
|
|
||||||
export class StatusBarBox extends Box {
|
export class StatusBarBox extends Box {
|
||||||
@@ -143,7 +145,7 @@ export class StatusBarBox extends Box {
|
|||||||
loading: (() => {
|
loading: (() => {
|
||||||
let icon = new Icon({
|
let icon = new Icon({
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
url: "https://raw.githubusercontent.com/cds-astro/aladin-lite/master/assets/aladin-logo.gif",
|
url: aladinLogoGif,
|
||||||
cssStyle: {
|
cssStyle: {
|
||||||
cursor: "help",
|
cursor: "help",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import { Utils } from "../../Utils";
|
|||||||
import { DOMElement } from "./Widget";
|
import { DOMElement } from "./Widget";
|
||||||
import { Layout } from "../Layout";
|
import { Layout } from "../Layout";
|
||||||
import { ActionButton } from "./ActionButton";
|
import { ActionButton } from "./ActionButton";
|
||||||
|
import { Footprint } from "../../Footprint";
|
||||||
/**
|
/**
|
||||||
* Class representing a Tabs layout
|
* Class representing a Tabs layout
|
||||||
* @extends DOMElement
|
* @extends DOMElement
|
||||||
@@ -120,8 +121,15 @@ export class Tabs extends DOMElement {
|
|||||||
|
|
||||||
return s;
|
return s;
|
||||||
};
|
};
|
||||||
|
let entry = aladin.view.selection[self.tabSelectedIdx][0];
|
||||||
|
let source;
|
||||||
|
if (entry instanceof Footprint) {
|
||||||
|
source = entry.source
|
||||||
|
} else {
|
||||||
|
source = entry;
|
||||||
|
}
|
||||||
|
|
||||||
let fieldNames = Object.keys(aladin.view.selection[self.tabSelectedIdx][0].data).join(";");
|
let fieldNames = Object.keys(source.data).join(";");
|
||||||
var lineArray = [fieldNames];
|
var lineArray = [fieldNames];
|
||||||
|
|
||||||
aladin.view.selection[self.tabSelectedIdx].forEach((obj) => {
|
aladin.view.selection[self.tabSelectedIdx].forEach((obj) => {
|
||||||
|
|||||||
@@ -145,7 +145,10 @@ export class DOMElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const aladinDiv = options && options.aladin && options.aladin.aladinDiv;
|
let aladinDiv = options && options.aladin && options.aladin.aladinDiv;
|
||||||
|
if (!aladinDiv) {
|
||||||
|
aladinDiv = el.closest('.aladin-container');
|
||||||
|
}
|
||||||
let innerWidth = aladinDiv && aladinDiv.offsetWidth;
|
let innerWidth = aladinDiv && aladinDiv.offsetWidth;
|
||||||
let innerHeight = aladinDiv && aladinDiv.offsetHeight;
|
let innerHeight = aladinDiv && aladinDiv.offsetHeight;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user