mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-04-30 04:38:57 -07:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4781ffdef2 | ||
|
|
0a48b016f9 | ||
|
|
b699a4bc12 | ||
|
|
95dfcc2cff | ||
|
|
c3eca21aee | ||
|
|
4524586145 | ||
|
|
13c5dc1aa1 | ||
|
|
b84a444634 | ||
|
|
e16f34fdad | ||
|
|
c7fcf3d451 | ||
|
|
7960ef9bde | ||
|
|
c2e7838930 | ||
|
|
601928bc8c | ||
|
|
feb892fa03 | ||
|
|
60022b2659 | ||
|
|
c69aa990b6 | ||
|
|
42209b166e |
@@ -12,6 +12,14 @@
|
||||
* [fix] layer opacity restored when switching from not visible to visible <https://github.com/cds-astro/aladin-lite/issues/332>
|
||||
* [feat] dark/light mode for the interface
|
||||
* [fix] polylines shapes size not consistent w.r.t to div size <https://github.com/cds-astro/aladin-lite/issues/331>
|
||||
* [feat] 'stackChanged' new event informing when a layer has been added, removed or swapped.
|
||||
* [ui] a new HiPS browser window to search and find HiPS among the HiPS worldwide network.
|
||||
* [ui] new settings panel for Catalog overlays to change the size, color or shapes of sources
|
||||
* [ui] possibility to swap 2 layers. Functional but not definitive, it would be better to allow drag and drop amond the layers.
|
||||
* [fix] fix local HiPS loading.
|
||||
* [ui] WIP. A toolbar object
|
||||
* [fix] fix selection of footprints. In the future allow a skew selection mode and a additive selection shortkey.
|
||||
* [fix] inertia bug when zooming in/out
|
||||
|
||||
### 3.7.0-beta
|
||||
|
||||
|
||||
17
assets/icons/enlarge.svg
Normal file
17
assets/icons/enlarge.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="-9 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
|
||||
<title>arrow-up-down</title>
|
||||
<desc>Created with Sketch Beta.</desc>
|
||||
<defs>
|
||||
|
||||
</defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="Icon-Set-Filled" sketch:type="MSLayerGroup" transform="translate(-213.000000, -1193.000000)" fill="#000000">
|
||||
<path d="M225,1217 L222,1217 L222,1201 L225,1201 C225.643,1201 226.293,1201.02 226.687,1200.62 C227.08,1200.23 227.08,1199.6 226.687,1199.2 L220.747,1193.28 C220.537,1193.07 220.259,1192.98 219.984,1193 C219.71,1192.98 219.432,1193.07 219.222,1193.28 L213.283,1199.2 C212.89,1199.6 212.89,1200.23 213.283,1200.62 C213.676,1201.02 214.294,1201 215,1201 L218,1201 L218,1217 L215,1217 C214.357,1217 213.676,1216.98 213.283,1217.38 C212.89,1217.77 212.89,1218.4 213.283,1218.8 L219.222,1224.72 C219.432,1224.93 219.71,1225.02 219.984,1225 C220.259,1225.02 220.537,1224.93 220.747,1224.72 L226.687,1218.8 C227.08,1218.4 227.08,1217.77 226.687,1217.38 C226.293,1216.98 225.737,1217 225,1217" id="arrow-up-down" sketch:type="MSShapeGroup">
|
||||
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
6
assets/icons/tree.svg
Normal file
6
assets/icons/tree.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 36 36" version="1.1" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>tree-view-line</title>
|
||||
<path d="M15,32H11a1,1,0,0,1-1-1V27a1,1,0,0,1,1-1h4a1,1,0,0,1,1,1v4A1,1,0,0,1,15,32Zm-3-2h2V28H12Z" class="clr-i-outline clr-i-outline-path-1"></path><path d="M15,16H11a1,1,0,0,0-1,1v1.2H5.8V12H7a1,1,0,0,0,1-1V7A1,1,0,0,0,7,6H3A1,1,0,0,0,2,7v4a1,1,0,0,0,1,1H4.2V29.8h6.36a.8.8,0,0,0,0-1.6H5.8V19.8H10V21a1,1,0,0,0,1,1h4a1,1,0,0,0,1-1V17A1,1,0,0,0,15,16ZM4,8H6v2H4ZM14,20H12V18h2Z" class="clr-i-outline clr-i-outline-path-2"></path><path d="M34,9a1,1,0,0,0-1-1H10v2H33A1,1,0,0,0,34,9Z" class="clr-i-outline clr-i-outline-path-3"></path><path d="M33,18H18v2H33a1,1,0,0,0,0-2Z" class="clr-i-outline clr-i-outline-path-4"></path><path d="M33,28H18v2H33a1,1,0,0,0,0-2Z" class="clr-i-outline clr-i-outline-path-5"></path>
|
||||
<rect x="0" y="0" width="36" height="36" fill-opacity="0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -4,13 +4,16 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="aladin-lite-div" style="width: 512px; height: 512px"></div>
|
||||
<div id="aladin-lite-div" style="width: 512px; height: 512px">
|
||||
<div id="toolbar"></div>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import showUrl from './../assets/icons/show.svg';
|
||||
import A from '../src/js/A.js';
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {samp: true, survey: "data/hips/PanSTARRS_DR1_color-z-zg-g", fov:2.0, target: "22 35 58.39 +33 57 57.8", showSettingsControl: true, log: false});
|
||||
aladin = A.aladin('#aladin-lite-div', {toolbar: {divSelector: '#toolbar'}, samp: true, survey: "data/hips/PanSTARRS_DR1_color-z-zg-g", fov:2.0, target: "22 35 58.39 +33 57 57.8", showSettingsControl: true, log: false});
|
||||
aladin.setProjection('AIT');
|
||||
let cfht = aladin.createImageSurvey("CFHT", "CFHT MegaCam u+g+r", "./data/hips/CFHT", "equatorial", 10, {imgFormat: 'png'});
|
||||
let jwst1 = aladin.createImageSurvey("CDS/P/JWST/Stephans-Quintet/NIRCam+MIRI", "JWST NIRCam+MIRI", "data/hips/JWST_NIRCam_MIRI", null, null, {imgFormat: 'png'});
|
||||
@@ -20,6 +23,16 @@
|
||||
aladin.setOverlayImageLayer('JWST2', 'overlay_JWST2');
|
||||
aladin.getOverlayImageLayer('overlay_JWST1').setAlpha(0.0);
|
||||
aladin.getOverlayImageLayer('overlay_JWST2').setAlpha(0.0);
|
||||
|
||||
aladin.toolbar.add('action_custom', {
|
||||
icon: {
|
||||
url: showUrl,
|
||||
size: "medium"
|
||||
},
|
||||
action(_) {
|
||||
console.log("do a thing")
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-1.10.1.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
let aladin;
|
||||
@@ -38,8 +37,8 @@
|
||||
<!-- fin temporaire gestion cercle -->
|
||||
|
||||
<b>Orientation</b><br>
|
||||
<button id="hips-coronelli" class="pure-button" name="ref-hips" onclick="longitudeReversed = false; aladin.reverseLongitude(longitudeReversed)">Normal</button><br>
|
||||
<button id="hips-illenoroc" class="pure-button" name="ref-hips" onclick="longitudeReversed = true; aladin.reverseLongitude(longitudeReversed)">Inversé</button>
|
||||
<button id="hips-coronelli" class="pure-button" name="ref-hips" onclick="aladin.reverseLongitude(false)">Normal</button><br>
|
||||
<button id="hips-illenoroc" class="pure-button" name="ref-hips" onclick="aladin.reverseLongitude(true);">Inversé</button>
|
||||
<br><br>
|
||||
|
||||
<b>Constellations</b>
|
||||
@@ -75,6 +74,13 @@
|
||||
<a href="#"><img id="coronelli-stars-red" class="catcoro coro-star" src="star_red.png"></a>
|
||||
<a href="#"><img id="coronelli-stars-blue" class="catcoro coro-star" src="star_blue.png"></a>
|
||||
</div>
|
||||
<div>Coronelli2<br>
|
||||
<!--a id="coronelli-stars" class="pure-button catcoro" href="#">Coronelli</a-->
|
||||
<a href="#"><img id="coronelli-stars-white" class="catcoro coro-star" src="star_white.png"></a>
|
||||
<a href="#"><img id="coronelli-stars-yellow" class="catcoro coro-star" src="star_yellow.png"></a><br>
|
||||
<a href="#"><img id="coronelli-stars-red" class="catcoro coro-star" src="star_red.png"></a>
|
||||
<a href="#"><img id="coronelli-stars-blue" class="catcoro coro-star" src="star_blue.png"></a>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<b>Navigation</b> <br><button id="stop">Stop</button>
|
||||
@@ -99,6 +105,14 @@
|
||||
<a class="pure-button nav-button nav-goto" href="#">Halley</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
<div id="coo_halley">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Halley</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
<div id="coo_halley">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Halley</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css"> .aladin-reticleColor { color: rgb(178, 50, 178); font-weight:bold;} </style>
|
||||
@@ -231,11 +245,10 @@
|
||||
import {Utils} from '../src/js/Utils';
|
||||
|
||||
A.init.then(() => {
|
||||
var hipsDir="http://alasky.u-strasbg.fr/CDS_P_Coronelli";
|
||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, expandLayersControl: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||
aladin.createImageSurvey('Coronelli', 'Coronelli', hipsDir, 'equatorial', 4, {imgFormat: 'jpg'});
|
||||
aladin.setImageSurvey('Coronelli');
|
||||
|
||||
var hipsDir="http://alasky.cds.unistra.fr/CDS_P_Coronelli";
|
||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, lockNorthUp: true, reverseLongitude: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||
aladin.createImageSurvey('Coronelli', 'Coronelli', hipsDir, 'equatorial', 4, {imgFormat: 'jpg', minOrder: 3});
|
||||
aladin.setImageSurvey('Coronelli')
|
||||
$('#layersControlLeft').show();
|
||||
$('#layersCL2').show();
|
||||
$('#layersControlRight').show();
|
||||
@@ -344,14 +357,14 @@
|
||||
|
||||
// listen click on navigation buttons
|
||||
$('.nav-button').click(function() {
|
||||
var cooTarget = $(this).parent().attr('id');
|
||||
var cooTarget = $(this).parent().attr('id');
|
||||
|
||||
if ($(this).hasClass("nav-goto")) {
|
||||
aladin.gotoRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec);
|
||||
}
|
||||
else if ($(this).hasClass("nav-flyto")) {
|
||||
aladin.animateToRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec, cooNav[cooTarget].time);
|
||||
}
|
||||
if ($(this).hasClass("nav-goto")) {
|
||||
aladin.gotoRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec);
|
||||
}
|
||||
else if ($(this).hasClass("nav-flyto")) {
|
||||
aladin.animateToRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec, cooNav[cooTarget].time);
|
||||
}
|
||||
});
|
||||
|
||||
// stop animations
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
console.log(pos)
|
||||
});
|
||||
|
||||
aladin.on('layerChanged', function(imageLayer, layer, state){
|
||||
console.log(imageLayer, layer, state)
|
||||
aladin.on('stackChanged', function(state) {
|
||||
console.log(state)
|
||||
});
|
||||
|
||||
cat.sources[0].actionClicked();
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
aladin = A.aladin(
|
||||
'#aladin-lite-div',
|
||||
{
|
||||
toolbar: {
|
||||
vertical: false,
|
||||
},
|
||||
showSimbadPointerControl: true,
|
||||
survey: 'https://skies.esac.esa.int/AKARI/color/', // set initial image survey
|
||||
projection: 'AIT', // set a projection
|
||||
@@ -23,6 +26,8 @@
|
||||
reticleSize: 64, // change reticle size
|
||||
showContextMenu: true,
|
||||
showShareControl: true,
|
||||
showCooGridControl: true,
|
||||
showColorPickerControl: true,
|
||||
showFrame: true,
|
||||
showZoomControl:true,
|
||||
showSettingsControl:true,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"homepage": "https://aladin.cds.unistra.fr/",
|
||||
"name": "aladin-lite",
|
||||
"type": "module",
|
||||
"version": "3.7.3-beta",
|
||||
"version": "3.8.0-beta",
|
||||
"description": "An astronomical HiPS visualizer in the browser",
|
||||
"author": "Thomas Boch and Matthieu Baumann",
|
||||
"license": "GPL-3",
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "aladin-lite"
|
||||
description = "Aladin Lite v3 introduces a new graphical engine written in Rust with the use of WebGL"
|
||||
license = "BSD-3-Clause"
|
||||
repository = "https://github.com/cds-astro/aladin-lite"
|
||||
version = "3.7.3-beta"
|
||||
version = "3.8.0-beta"
|
||||
authors = [ "baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr",]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "al-api"
|
||||
version = "3.7.0"
|
||||
version = "3.8.0"
|
||||
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -180,11 +180,11 @@ impl HiPSProperties {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ImageExt {
|
||||
Fits,
|
||||
#[serde(alias = "fits.fz")]
|
||||
FitsFz,
|
||||
Jpeg,
|
||||
Png,
|
||||
Webp,
|
||||
#[serde(alias = "fits.fz")]
|
||||
FitsFz,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "al-core"
|
||||
version = "3.7.0"
|
||||
version = "3.8.0"
|
||||
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1605,6 +1605,10 @@ impl App {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.vel_history.len() < 5 {
|
||||
return;
|
||||
}
|
||||
|
||||
let now = Time::now();
|
||||
let avg_vel = self.vel_history.iter().copied().sum::<f32>() / self.vel_history.len() as f32;
|
||||
|
||||
@@ -1650,6 +1654,11 @@ impl App {
|
||||
// For the moment, no animation is triggered.
|
||||
// The fov is directly set
|
||||
self.camera.set_aperture(fov, &self.projection);
|
||||
|
||||
// reset the parameters that determine if an inertia is needed
|
||||
self.vel_history.clear();
|
||||
self.dist_dragging = 0.0;
|
||||
|
||||
self.request_for_new_tiles = true;
|
||||
self.request_redraw = true;
|
||||
}
|
||||
@@ -1807,6 +1816,10 @@ impl App {
|
||||
pub(crate) fn set_zoom_factor(&mut self, zoom_factor: f64) {
|
||||
self.camera.set_zoom_factor(zoom_factor, &self.projection);
|
||||
|
||||
// reset the parameters that determine if an inertia is needed
|
||||
self.vel_history.clear();
|
||||
self.dist_dragging = 0.0;
|
||||
|
||||
self._update_hips_location();
|
||||
|
||||
self.request_for_new_tiles = true;
|
||||
|
||||
@@ -224,6 +224,8 @@ impl CameraViewPort {
|
||||
self.view_hpx_cells.get_cells(depth, frame)
|
||||
}
|
||||
|
||||
// This method has the role to determine the render mode based on the fov
|
||||
// For large FoV, raytracing drawing mode, rasterizer otherwise
|
||||
pub fn is_raytracing(&self, proj: &ProjectionType) -> bool {
|
||||
// Check whether the tile depth is 0 for square projection
|
||||
// definition domains i.e. Mercator
|
||||
@@ -240,6 +242,7 @@ impl CameraViewPort {
|
||||
ProjectionType::Ait(_) => self.aperture >= 100.0_f64.to_radians(),
|
||||
ProjectionType::Mol(_) => self.aperture >= 100.0_f64.to_radians(),
|
||||
ProjectionType::Zea(_) => self.aperture >= 140.0_f64.to_radians(),
|
||||
_ => self.aperture >= 140.0_f64.to_radians(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ impl WebClient {
|
||||
"ZEA" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Zea(mapproj::zenithal::zea::Zea::new())), /* Equal-area */
|
||||
/*"FEYE" => self
|
||||
"FEYE" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Feye(mapproj::zenithal::feye::Feye::new())),
|
||||
"AIR" => {
|
||||
@@ -239,19 +239,19 @@ impl WebClient {
|
||||
//air_proj.set_n_iter(10);
|
||||
//air_proj.set_eps(1e-12);
|
||||
self.app.set_projection(ProjectionType::Air(air_proj))
|
||||
}*/
|
||||
}
|
||||
//"AZP",
|
||||
/*"ARC" => self
|
||||
"ARC" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Arc(mapproj::zenithal::arc::Arc::new())),
|
||||
"NCP" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Ncp(mapproj::zenithal::ncp::Ncp::new())),*/
|
||||
.set_projection(ProjectionType::Ncp(mapproj::zenithal::ncp::Ncp::new())),
|
||||
// Cylindrical
|
||||
"MER" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Mer(mapproj::cylindrical::mer::Mer::new())),
|
||||
/*"CAR" => self
|
||||
"CAR" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Car(mapproj::cylindrical::car::Car::new())),
|
||||
"CEA" => self
|
||||
@@ -259,17 +259,17 @@ impl WebClient {
|
||||
.set_projection(ProjectionType::Cea(mapproj::cylindrical::cea::Cea::new())),
|
||||
"CYP" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Cyp(mapproj::cylindrical::cyp::Cyp::new())),*/
|
||||
.set_projection(ProjectionType::Cyp(mapproj::cylindrical::cyp::Cyp::new())),
|
||||
// Pseudo-cylindrical
|
||||
"AIT" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Ait(mapproj::pseudocyl::ait::Ait::new())),
|
||||
/*"PAR" => self
|
||||
"PAR" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Par(mapproj::pseudocyl::par::Par::new())),
|
||||
"SFL" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Sfl(mapproj::pseudocyl::sfl::Sfl::new())),*/
|
||||
.set_projection(ProjectionType::Sfl(mapproj::pseudocyl::sfl::Sfl::new())),
|
||||
"MOL" => {
|
||||
let mut mol_proj = mapproj::pseudocyl::mol::Mol::new();
|
||||
mol_proj.set_n_iter(10);
|
||||
@@ -277,13 +277,13 @@ impl WebClient {
|
||||
|
||||
self.app.set_projection(ProjectionType::Mol(mol_proj))
|
||||
} // Conic
|
||||
/*"COD" => self
|
||||
"COD" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Cod(mapproj::conic::cod::Cod::new())),
|
||||
// Hybrid
|
||||
"HPX" => self
|
||||
.app
|
||||
.set_projection(ProjectionType::Hpx(mapproj::hybrid::hpx::Hpx::new())),*/
|
||||
.set_projection(ProjectionType::Hpx(mapproj::hybrid::hpx::Hpx::new())),
|
||||
_ => Err(JsValue::from_str(
|
||||
"Not a valid projection name. AIT, ZEA, SIN, STG, TAN, MOL and MER are accepted",
|
||||
)),
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// World space
|
||||
use crate::camera::CameraViewPort;
|
||||
use crate::domain::sdf::ProjDefType;
|
||||
use crate::math::rotation::Rotation;
|
||||
|
||||
use coo_space::XYZModel;
|
||||
//use crate::num_traits::FloatConst;
|
||||
@@ -22,7 +23,7 @@ pub mod domain;
|
||||
use crate::math::angle::ToAngle;
|
||||
|
||||
use crate::math::angle::Angle;
|
||||
use domain::{basic, full::FullScreen};
|
||||
use domain::{basic, cod::Cod, full::FullScreen, hpx::Hpx, par::Par};
|
||||
/* S <-> NDC space conversion methods */
|
||||
pub fn screen_to_ndc_space(
|
||||
pos_screen_space: &XYScreen<f64>,
|
||||
@@ -114,15 +115,15 @@ pub enum ProjectionType {
|
||||
/* ZEA, Equal-area */
|
||||
Zea(mapproj::zenithal::zea::Zea),
|
||||
/* FEYE, Fish-eyes */
|
||||
//Feye(mapproj::zenithal::feye::Feye),
|
||||
Feye(mapproj::zenithal::feye::Feye),
|
||||
/* AIR, */
|
||||
//Air(mapproj::zenithal::air::Air),
|
||||
Air(mapproj::zenithal::air::Air),
|
||||
//AZP: {fov: 180},
|
||||
//Azp(mapproj::zenithal::azp::Azp),
|
||||
/* ARC, */
|
||||
//Arc(mapproj::zenithal::arc::Arc),
|
||||
Arc(mapproj::zenithal::arc::Arc),
|
||||
/* NCP, */
|
||||
//Ncp(mapproj::zenithal::ncp::Ncp),
|
||||
Ncp(mapproj::zenithal::ncp::Ncp),
|
||||
|
||||
// Pseudo-cylindrical projections
|
||||
/* AIT, Aitoff */
|
||||
@@ -130,26 +131,26 @@ pub enum ProjectionType {
|
||||
// MOL, Mollweide */
|
||||
Mol(mapproj::pseudocyl::mol::Mol),
|
||||
// PAR, */
|
||||
//Par(mapproj::pseudocyl::par::Par),
|
||||
Par(mapproj::pseudocyl::par::Par),
|
||||
// SFL, */
|
||||
//Sfl(mapproj::pseudocyl::sfl::Sfl),
|
||||
Sfl(mapproj::pseudocyl::sfl::Sfl),
|
||||
|
||||
// Cylindrical projections
|
||||
// MER, Mercator */
|
||||
Mer(mapproj::cylindrical::mer::Mer),
|
||||
// CAR, */
|
||||
//Car(mapproj::cylindrical::car::Car),
|
||||
Car(mapproj::cylindrical::car::Car),
|
||||
// CEA, */
|
||||
//Cea(mapproj::cylindrical::cea::Cea),
|
||||
Cea(mapproj::cylindrical::cea::Cea),
|
||||
// CYP, */
|
||||
//Cyp(mapproj::cylindrical::cyp::Cyp),
|
||||
Cyp(mapproj::cylindrical::cyp::Cyp),
|
||||
|
||||
// Conic projections
|
||||
// COD, */
|
||||
//Cod(mapproj::conic::cod::Cod),
|
||||
Cod(mapproj::conic::cod::Cod),
|
||||
|
||||
// HEALPix hybrid projection
|
||||
//Hpx(mapproj::hybrid::hpx::Hpx),
|
||||
Hpx(mapproj::hybrid::hpx::Hpx),
|
||||
}
|
||||
|
||||
use crate::math::lonlat::LonLat;
|
||||
@@ -305,38 +306,38 @@ impl ProjectionType {
|
||||
/* ZEA, Equal-area */
|
||||
ProjectionType::Zea(_) => 1.0,
|
||||
/* FEYE, Fish-eyes */
|
||||
//ProjectionType::Feye(_) => 1.0,
|
||||
ProjectionType::Feye(_) => 1.0,
|
||||
/* AIR, */
|
||||
//ProjectionType::Air(_) => 1.0,
|
||||
ProjectionType::Air(_) => 1.0,
|
||||
//AZP: {fov: 180},
|
||||
//Azp(mapproj::zenithal::azp::Azp),
|
||||
/* ARC, */
|
||||
//ProjectionType::Arc(_) => 1.0,
|
||||
ProjectionType::Arc(_) => 1.0,
|
||||
/* NCP, */
|
||||
//ProjectionType::Ncp(_) => 1.0,
|
||||
ProjectionType::Ncp(_) => 1.0,
|
||||
// Pseudo-cylindrical projections
|
||||
/* AIT, Aitoff */
|
||||
ProjectionType::Ait(_) => 2.0,
|
||||
// MOL, Mollweide */
|
||||
ProjectionType::Mol(_) => 2.0,
|
||||
// PAR, */
|
||||
//ProjectionType::Par(_) => 2.0,
|
||||
ProjectionType::Par(_) => 2.0,
|
||||
// SFL, */
|
||||
//ProjectionType::Sfl(_) => 2.0,
|
||||
ProjectionType::Sfl(_) => 2.0,
|
||||
// Cylindrical projections
|
||||
// MER, Mercator */
|
||||
ProjectionType::Mer(_) => 1.0,
|
||||
// CAR, */
|
||||
//ProjectionType::Car(_) => 1.0,
|
||||
ProjectionType::Car(_) => 1.0,
|
||||
// CEA, */
|
||||
//ProjectionType::Cea(_) => 1.0,
|
||||
ProjectionType::Cea(_) => 1.0,
|
||||
// CYP, */
|
||||
//ProjectionType::Cyp(_) => 1.0,
|
||||
ProjectionType::Cyp(_) => 1.0,
|
||||
// Conic projections
|
||||
// COD, */
|
||||
//ProjectionType::Cod(_) => 1.0,
|
||||
ProjectionType::Cod(_) => 1.0,
|
||||
// HEALPix hybrid projection
|
||||
//ProjectionType::Hpx(_) => 2.0,
|
||||
ProjectionType::Hpx(_) => 2.0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,15 +353,15 @@ impl ProjectionType {
|
||||
/* ZEA, Equal-area */
|
||||
ProjectionType::Zea(_) => 359.9_f64.to_radians().to_angle(),
|
||||
/* FEYE, Fish-eyes */
|
||||
//ProjectionType::Feye(_) => 190.0,
|
||||
ProjectionType::Feye(_) => 190.0_f64.to_radians().to_angle(),
|
||||
/* AIR, */
|
||||
//ProjectionType::Air(_) => 360.0,
|
||||
ProjectionType::Air(_) => 360.0_f64.to_radians().to_angle(),
|
||||
//AZP: {fov: 180},
|
||||
//Azp(mapproj::zenithal::azp::Azp),
|
||||
//ProjectionType::Azp(mapproj::zenithal::azp::Azp),
|
||||
/* ARC, */
|
||||
//ProjectionType::Arc(_) => 360.0,
|
||||
ProjectionType::Arc(_) => 360.0_f64.to_radians().to_angle(),
|
||||
/* NCP, */
|
||||
//ProjectionType::Ncp(_) => 180.0,
|
||||
ProjectionType::Ncp(_) => 180.0_f64.to_radians().to_angle(),
|
||||
|
||||
// Pseudo-cylindrical projections
|
||||
/* AIT, Aitoff */
|
||||
@@ -368,26 +369,26 @@ impl ProjectionType {
|
||||
// MOL, Mollweide */
|
||||
ProjectionType::Mol(_) => 360.0_f64.to_radians().to_angle(),
|
||||
// PAR, */
|
||||
//ProjectionType::Par(_) => 360.0,
|
||||
ProjectionType::Par(_) => 360.0_f64.to_radians().to_angle(),
|
||||
// SFL, */
|
||||
//ProjectionType::Sfl(_) => 360.0,
|
||||
ProjectionType::Sfl(_) => 360.0_f64.to_radians().to_angle(),
|
||||
|
||||
// Cylindrical projections
|
||||
// MER, Mercator */
|
||||
ProjectionType::Mer(_) => 360.0_f64.to_radians().to_angle(),
|
||||
// CAR, */
|
||||
//ProjectionType::Car(_) => 360.0,
|
||||
ProjectionType::Car(_) => 360.0_f64.to_radians().to_angle(),
|
||||
// CEA, */
|
||||
//ProjectionType::Cea(_) => 360.0,
|
||||
ProjectionType::Cea(_) => 360.0_f64.to_radians().to_angle(),
|
||||
// CYP, */
|
||||
//ProjectionType::Cyp(_) => 360.0,
|
||||
ProjectionType::Cyp(_) => 360.0_f64.to_radians().to_angle(),
|
||||
|
||||
// Conic projections
|
||||
// COD, */
|
||||
//ProjectionType::Cod(_) => 330.0,
|
||||
ProjectionType::Cod(_) => 330.0_f64.to_radians().to_angle(),
|
||||
|
||||
// HEALPix hybrid projection
|
||||
//ProjectionType::Hpx(_) => 360.0,
|
||||
ProjectionType::Hpx(_) => 360.0_f64.to_radians().to_angle(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,27 +416,27 @@ impl ProjectionType {
|
||||
&DISK
|
||||
}
|
||||
/* FEYE, Fish-eyes */
|
||||
/*ProjectionType::Feye(_) => {
|
||||
ProjectionType::Feye(_) => {
|
||||
const DISK: ProjDefType = ProjDefType::Disk(basic::disk::Disk { radius: 1.0 });
|
||||
&DISK
|
||||
}*/
|
||||
}
|
||||
/* AIR, */
|
||||
/*ProjectionType::Air(_) => {
|
||||
ProjectionType::Air(_) => {
|
||||
const DISK: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&DISK
|
||||
}*/
|
||||
}
|
||||
//AZP: {fov: 180},
|
||||
//Azp(mapproj::zenithal::azp::Azp),
|
||||
/* ARC, */
|
||||
/*ProjectionType::Arc(_) => {
|
||||
ProjectionType::Arc(_) => {
|
||||
const DISK: ProjDefType = ProjDefType::Disk(basic::disk::Disk { radius: 1.0 });
|
||||
&DISK
|
||||
}*/
|
||||
}
|
||||
/* NCP, */
|
||||
/*ProjectionType::Ncp(_) => {
|
||||
ProjectionType::Ncp(_) => {
|
||||
const DISK: ProjDefType = ProjDefType::Disk(basic::disk::Disk { radius: 1.0 });
|
||||
&DISK
|
||||
}*/
|
||||
}
|
||||
|
||||
// Pseudo-cylindrical projections
|
||||
/* AIT, Aitoff */
|
||||
@@ -449,15 +450,15 @@ impl ProjectionType {
|
||||
&ELLIPSE
|
||||
}
|
||||
// PAR, */
|
||||
/*ProjectionType::Par(_) => {
|
||||
ProjectionType::Par(_) => {
|
||||
const PAR: ProjDefType = ProjDefType::Par(Par);
|
||||
&PAR
|
||||
}*/
|
||||
}
|
||||
// SFL, */
|
||||
/*ProjectionType::Sfl(_) => {
|
||||
ProjectionType::Sfl(_) => {
|
||||
const PAR: ProjDefType = ProjDefType::Par(Par);
|
||||
&PAR
|
||||
}*/
|
||||
}
|
||||
|
||||
// Cylindrical projections
|
||||
// MER, Mercator */
|
||||
@@ -465,32 +466,32 @@ impl ProjectionType {
|
||||
const FULL_SCREEN: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&FULL_SCREEN
|
||||
} // CAR, */
|
||||
/*ProjectionType::Car(_) => {
|
||||
const FULL_SCREEN: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&FULL_SCREEN
|
||||
}*/
|
||||
// CEA, */
|
||||
/*ProjectionType::Cea(_) => {
|
||||
const FULL_SCREEN: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&FULL_SCREEN
|
||||
}*/
|
||||
// CYP, */
|
||||
/*ProjectionType::Cyp(_) => {
|
||||
const FULL_SCREEN: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&FULL_SCREEN
|
||||
}*/
|
||||
ProjectionType::Car(_) => {
|
||||
const FULL_SCREEN: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&FULL_SCREEN
|
||||
}
|
||||
// CEA, */
|
||||
ProjectionType::Cea(_) => {
|
||||
const FULL_SCREEN: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&FULL_SCREEN
|
||||
}
|
||||
// CYP, */
|
||||
ProjectionType::Cyp(_) => {
|
||||
const FULL_SCREEN: ProjDefType = ProjDefType::FullScreen(FullScreen);
|
||||
&FULL_SCREEN
|
||||
}
|
||||
|
||||
// Conic projections
|
||||
// COD, */
|
||||
/*ProjectionType::Cod(_) => {
|
||||
const CONIC: ProjDefType = ProjDefType::Cod(Cod::new());
|
||||
&CONIC
|
||||
}*/
|
||||
// HEALPix hybrid projection
|
||||
/*ProjectionType::Hpx(_) => {
|
||||
const HPX_DEF_REG: ProjDefType = ProjDefType::Hpx(Hpx);
|
||||
&HPX_DEF_REG
|
||||
}*/
|
||||
// Conic projections
|
||||
// COD, */
|
||||
ProjectionType::Cod(_) => {
|
||||
const CONIC: ProjDefType = ProjDefType::Cod(Cod::new());
|
||||
&CONIC
|
||||
}
|
||||
// HEALPix hybrid projection
|
||||
ProjectionType::Hpx(_) => {
|
||||
const HPX_DEF_REG: ProjDefType = ProjDefType::Hpx(Hpx);
|
||||
&HPX_DEF_REG
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -509,15 +510,15 @@ impl Projection for ProjectionType {
|
||||
/* ZEA, Equal-area */
|
||||
ProjectionType::Zea(zea) => zea.clip_to_world_space(xy),
|
||||
/* FEYE, Fish-eyes */
|
||||
//ProjectionType::Feye(feye) => feye.clip_to_world_space(xy),
|
||||
ProjectionType::Feye(feye) => feye.clip_to_world_space(xy),
|
||||
/* AIR, */
|
||||
//ProjectionType::Air(air) => air.clip_to_world_space(xy),
|
||||
ProjectionType::Air(air) => air.clip_to_world_space(xy),
|
||||
//AZP: {fov: 180},
|
||||
//Azp(mapproj::zenithal::azp::Azp),
|
||||
/* ARC, */
|
||||
//ProjectionType::Arc(arc) => arc.clip_to_world_space(xy),
|
||||
ProjectionType::Arc(arc) => arc.clip_to_world_space(xy),
|
||||
/* NCP, */
|
||||
//ProjectionType::Ncp(ncp) => ncp.clip_to_world_space(xy),
|
||||
ProjectionType::Ncp(ncp) => ncp.clip_to_world_space(xy),
|
||||
|
||||
// Pseudo-cylindrical projections
|
||||
/* AIT, Aitoff */
|
||||
@@ -525,30 +526,34 @@ impl Projection for ProjectionType {
|
||||
// MOL, Mollweide */
|
||||
ProjectionType::Mol(mol) => mol.clip_to_world_space(xy),
|
||||
// PAR, */
|
||||
//ProjectionType::Par(par) => par.clip_to_world_space(xy),
|
||||
ProjectionType::Par(par) => par.clip_to_world_space(xy),
|
||||
// SFL, */
|
||||
//ProjectionType::Sfl(sfl) => sfl.clip_to_world_space(xy),
|
||||
ProjectionType::Sfl(sfl) => sfl.clip_to_world_space(xy),
|
||||
|
||||
// Cylindrical projections
|
||||
// MER, Mercator */
|
||||
ProjectionType::Mer(mer) => mer.clip_to_world_space(xy),
|
||||
// CAR, */
|
||||
//ProjectionType::Car(car) => car.clip_to_world_space(xy),
|
||||
ProjectionType::Car(car) => car.clip_to_world_space(xy),
|
||||
// CEA, */
|
||||
//ProjectionType::Cea(cea) => cea.clip_to_world_space(xy),
|
||||
ProjectionType::Cea(cea) => cea.clip_to_world_space(xy),
|
||||
// CYP, */
|
||||
//ProjectionType::Cyp(cyp) => cyp.clip_to_world_space(xy),
|
||||
ProjectionType::Cyp(cyp) => cyp.clip_to_world_space(xy),
|
||||
|
||||
// Conic projections
|
||||
// COD, */
|
||||
/*ProjectionType::Cod(cod) => cod.clip_to_world_space(xy).map(|xyz| {
|
||||
ProjectionType::Cod(cod) => cod.clip_to_world_space(xy).map(|xyz| {
|
||||
let rot = Rotation::from_sky_position(
|
||||
&LonLatT::new(0.0_f64.to_angle(), (HALF_PI * 0.5).to_angle()).vector(),
|
||||
&LonLatT::new(
|
||||
0.0_f64.to_angle(),
|
||||
(mapproj::math::HALF_PI * 0.5).to_angle(),
|
||||
)
|
||||
.vector(),
|
||||
);
|
||||
rot.inv_rotate(&xyz)
|
||||
}),*/
|
||||
}),
|
||||
// HEALPix hybrid projection
|
||||
//ProjectionType::Hpx(hpx) => hpx.clip_to_world_space(xy),
|
||||
ProjectionType::Hpx(hpx) => hpx.clip_to_world_space(xy),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,15 +570,15 @@ impl Projection for ProjectionType {
|
||||
/* ZEA, Equal-area */
|
||||
ProjectionType::Zea(zea) => zea.world_to_clip_space(xyz),
|
||||
/* FEYE, Fish-eyes */
|
||||
//ProjectionType::Feye(feye) => feye.world_to_clip_space(xyz),
|
||||
ProjectionType::Feye(feye) => feye.world_to_clip_space(xyz),
|
||||
/* AIR, */
|
||||
//ProjectionType::Air(air) => air.world_to_clip_space(xyz),
|
||||
ProjectionType::Air(air) => air.world_to_clip_space(xyz),
|
||||
//AZP: {fov: 180},
|
||||
//Azp(mapproj::zenithal::azp::Azp),
|
||||
/* ARC, */
|
||||
//ProjectionType::Arc(arc) => arc.world_to_clip_space(xyz),
|
||||
ProjectionType::Arc(arc) => arc.world_to_clip_space(xyz),
|
||||
/* NCP, */
|
||||
//ProjectionType::Ncp(ncp) => ncp.world_to_clip_space(xyz),
|
||||
ProjectionType::Ncp(ncp) => ncp.world_to_clip_space(xyz),
|
||||
|
||||
// Pseudo-cylindrical projections
|
||||
/* AIT, Aitoff */
|
||||
@@ -581,30 +586,34 @@ impl Projection for ProjectionType {
|
||||
// MOL, Mollweide */
|
||||
ProjectionType::Mol(mol) => mol.world_to_clip_space(xyz),
|
||||
// PAR, */
|
||||
//ProjectionType::Par(par) => par.world_to_clip_space(xyz),
|
||||
ProjectionType::Par(par) => par.world_to_clip_space(xyz),
|
||||
// SFL, */
|
||||
//ProjectionType::Sfl(sfl) => sfl.world_to_clip_space(xyz),
|
||||
ProjectionType::Sfl(sfl) => sfl.world_to_clip_space(xyz),
|
||||
|
||||
// Cylindrical projections
|
||||
// MER, Mercator */
|
||||
ProjectionType::Mer(mer) => mer.world_to_clip_space(xyz),
|
||||
// CAR, */
|
||||
//ProjectionType::Car(car) => car.world_to_clip_space(xyz),
|
||||
ProjectionType::Car(car) => car.world_to_clip_space(xyz),
|
||||
// CEA, */
|
||||
//ProjectionType::Cea(cea) => cea.world_to_clip_space(xyz),
|
||||
ProjectionType::Cea(cea) => cea.world_to_clip_space(xyz),
|
||||
// CYP, */
|
||||
//ProjectionType::Cyp(cyp) => cyp.world_to_clip_space(xyz),
|
||||
ProjectionType::Cyp(cyp) => cyp.world_to_clip_space(xyz),
|
||||
// Conic projections
|
||||
// COD, */
|
||||
/*ProjectionType::Cod(cod) => {
|
||||
ProjectionType::Cod(cod) => {
|
||||
// The Cod projection is centered on (0, 45 deg)
|
||||
let rot = Rotation::from_sky_position(
|
||||
&LonLatT::new(0.0_f64.to_angle(), (HALF_PI * 0.5).to_angle()).vector(),
|
||||
&LonLatT::new(
|
||||
0.0_f64.to_angle(),
|
||||
(mapproj::math::HALF_PI * 0.5).to_angle(),
|
||||
)
|
||||
.vector(),
|
||||
);
|
||||
cod.world_to_clip_space(&rot.rotate(&xyz))
|
||||
}*/
|
||||
cod.world_to_clip_space(&rot.rotate(xyz))
|
||||
}
|
||||
// HEALPix hybrid projection
|
||||
//ProjectionType::Hpx(hpx) => hpx.world_to_clip_space(xyz),
|
||||
ProjectionType::Hpx(hpx) => hpx.world_to_clip_space(xyz),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -634,6 +643,7 @@ impl UniformType for ProjectionType {
|
||||
// Cylindrical projections
|
||||
// MER, Mercator */
|
||||
ProjectionType::Mer(_) => gl.uniform1i(location, 6),
|
||||
_ => gl.uniform1i(location, 6),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -808,7 +818,7 @@ mod tests {
|
||||
"./../img/zea.jpg",
|
||||
ProjectionType::Zea(mapproj::zenithal::zea::Zea),
|
||||
);
|
||||
/*generate_projection_map(
|
||||
generate_projection_map(
|
||||
"./../img/feye.png",
|
||||
ProjectionType::Feye(mapproj::zenithal::feye::Feye),
|
||||
);
|
||||
@@ -823,14 +833,14 @@ mod tests {
|
||||
generate_projection_map(
|
||||
"./../img/air.png",
|
||||
ProjectionType::Air(mapproj::zenithal::air::Air::new()),
|
||||
);*/
|
||||
);
|
||||
|
||||
// Cylindrical
|
||||
generate_projection_map(
|
||||
"./../img/mer.jpg",
|
||||
ProjectionType::Mer(mapproj::cylindrical::mer::Mer),
|
||||
);
|
||||
/*generate_projection_map(
|
||||
generate_projection_map(
|
||||
"./../img/car.png",
|
||||
ProjectionType::Car(mapproj::cylindrical::car::Car),
|
||||
);
|
||||
@@ -841,26 +851,26 @@ mod tests {
|
||||
generate_projection_map(
|
||||
"./../img/cyp.png",
|
||||
ProjectionType::Cyp(mapproj::cylindrical::cyp::Cyp::new()),
|
||||
);*/
|
||||
);
|
||||
// Pseudo-cylindrical
|
||||
generate_projection_map(
|
||||
"./../img/ait.jpg",
|
||||
ProjectionType::Ait(mapproj::pseudocyl::ait::Ait),
|
||||
);
|
||||
/*generate_projection_map(
|
||||
generate_projection_map(
|
||||
"./../img/car.png",
|
||||
ProjectionType::Par(mapproj::pseudocyl::par::Par),
|
||||
);
|
||||
generate_projection_map(
|
||||
"./../img/cea.png",
|
||||
ProjectionType::Sfl(mapproj::pseudocyl::sfl::Sfl),
|
||||
);*/
|
||||
);
|
||||
generate_projection_map(
|
||||
"./../img/mol.jpg",
|
||||
ProjectionType::Mol(mapproj::pseudocyl::mol::Mol::new()),
|
||||
);
|
||||
// Conic
|
||||
/*generate_projection_map(
|
||||
generate_projection_map(
|
||||
"./../img/cod.png",
|
||||
ProjectionType::Cod(mapproj::conic::cod::Cod::new()),
|
||||
);
|
||||
@@ -868,6 +878,6 @@ mod tests {
|
||||
generate_projection_map(
|
||||
"./../img/hpx.png",
|
||||
ProjectionType::Hpx(mapproj::hybrid::hpx::Hpx),
|
||||
);*/
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
12456
src/core/src/shaders.rs
12456
src/core/src/shaders.rs
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,6 @@
|
||||
|
||||
/* Aladin lite default color */
|
||||
--aladin-color: #b232b2;
|
||||
--aladin-color-border: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
@@ -37,14 +36,14 @@
|
||||
--hover-color: green;
|
||||
--toggle-color: dodgerblue;
|
||||
--border-size: 2px;
|
||||
--valid-color: greenyellow;
|
||||
--valid-color: green;
|
||||
--error-color: red;
|
||||
}
|
||||
|
||||
.aladin-tree {
|
||||
width: 100%;
|
||||
border-top: 1px solid var(--border-color);
|
||||
border-bottom: 2px solid var(--border-color);
|
||||
height: calc(100% - 130px);
|
||||
border-bottom: var(--border-size) solid var(--border-color);
|
||||
}
|
||||
|
||||
.aladin-tree .aladin-directory-path {
|
||||
@@ -57,26 +56,62 @@
|
||||
.aladin-tree ul {
|
||||
padding:0;
|
||||
margin:0;
|
||||
overflow-y: scroll;
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
height: calc(100% - 37px);
|
||||
}
|
||||
.aladin-link {
|
||||
list-style-type: none;
|
||||
padding: 0.5em 0px;
|
||||
cursor:pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.aladin-tree li:hover {
|
||||
color: var(--hover-color);
|
||||
}
|
||||
|
||||
.aladin-tree li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.aladin-tree li {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
.aladin-tree li > * {
|
||||
border-bottom: var(--border-size) solid var(--border-color);
|
||||
padding: 0.5em 0px;
|
||||
}
|
||||
|
||||
.aladin-tree li:last-of-type > * {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
#aladin-tooltip-mouse {
|
||||
display: none;
|
||||
position: fixed;
|
||||
pointer-events: none; /* tooltip won't block mouse */
|
||||
z-index: 1000;
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
width: fit-content;
|
||||
}
|
||||
#aladin-tooltip-mouse * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.aladin-fig {
|
||||
display: inline-block; /* shrink-wraps content */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.aladin-fig img {
|
||||
display: block;
|
||||
max-width: 128px;
|
||||
max-height: 128px;
|
||||
}
|
||||
|
||||
.aladin-fig figcaption {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
color: white;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
background: black;
|
||||
}
|
||||
|
||||
.aladin-lite-spectra-displayer .aladin-spectra-unit-selector {
|
||||
@@ -195,7 +230,7 @@
|
||||
color: green;
|
||||
}
|
||||
.aladin-measurement-div table tr td a:hover {
|
||||
color: var(--hover-color);
|
||||
color: var(--aladin-color);
|
||||
}
|
||||
|
||||
.aladin-measurement-div table tr td {
|
||||
@@ -249,11 +284,22 @@
|
||||
|
||||
.aladin-anchor-top{top:0}
|
||||
.aladin-anchor-middle{top:50%; transform: translate(0, -50%);/*half of the .box height*/}
|
||||
.aladin-anchor-bottom{bottom:0}
|
||||
.aladin-anchor-bottom{
|
||||
bottom:0;
|
||||
|
||||
.aladin-anchor-left{left:0;}
|
||||
.aladin-anchor-center{left:50%; transform: translate(-50%, 0%);/*half of the .box width*/}
|
||||
.aladin-anchor-right{right:0;}
|
||||
}
|
||||
|
||||
.aladin-anchor-left {
|
||||
left: 0;
|
||||
|
||||
}
|
||||
.aladin-anchor-center{
|
||||
left:50%;
|
||||
transform: translate(-50%, 0%);/*half of the .box width*/
|
||||
}
|
||||
.aladin-anchor-right{
|
||||
right:0;
|
||||
}
|
||||
|
||||
.aladin-anchor-middle.aladin-anchor-center {
|
||||
transform: translate(-50%, -50%);
|
||||
@@ -286,7 +332,7 @@
|
||||
}
|
||||
|
||||
.aladin-box {
|
||||
padding: 0.2rem;
|
||||
padding: 0.3rem;
|
||||
background: whitesmoke;
|
||||
position: absolute;
|
||||
font-size: inherit;
|
||||
@@ -301,6 +347,12 @@
|
||||
width: min-content;
|
||||
|
||||
border: var(--border-size) solid var(--border-color);
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.aladin-box .aladin-box-content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.aladin-container canvas {
|
||||
@@ -318,12 +370,8 @@
|
||||
line-height: 1.5em;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aladin-box-content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.aladin-shareInput {
|
||||
width: 300px;
|
||||
margin-top: 10px;
|
||||
@@ -353,7 +401,7 @@
|
||||
margin-top: 0 0 2px 0;
|
||||
cursor:pointer;
|
||||
color: #605F61;
|
||||
border: var(--border-size) solid #AEAEAE;
|
||||
border: var(--border-size) solid var(--border-color);
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
font-size: 1.0rem;
|
||||
@@ -368,8 +416,10 @@
|
||||
|
||||
.aladin-box-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #d2d2d2;
|
||||
padding-bottom: 5px;
|
||||
border-top: var(--border-size) solid var(--border-color);
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
|
||||
}
|
||||
|
||||
.aladin-restore {
|
||||
@@ -438,12 +488,6 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
.aladin-icon.aladin-dark-theme {
|
||||
background-color: transparent;
|
||||
}
|
||||
*/
|
||||
|
||||
[data-theme="dark"] .aladin-icon.aladin-icon-monochrome img {
|
||||
filter: invert(100%) sepia(91%) saturate(0%) hue-rotate(169deg) brightness(115%) contrast(100%);
|
||||
}
|
||||
@@ -473,26 +517,27 @@
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.aladin-container .small-sized-icon {
|
||||
.aladin-small-sized-icon {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
}
|
||||
|
||||
.aladin-container .medium-sized-icon {
|
||||
.aladin-medium-sized-icon {
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
}
|
||||
|
||||
.aladin-container .medium-sized {
|
||||
.aladin-medium-sized {
|
||||
height: 1.6rem;
|
||||
}
|
||||
|
||||
.aladin-container .small-sized {
|
||||
.aladin-small-sized {
|
||||
height: 1.2rem;
|
||||
}
|
||||
|
||||
.aladin-input-text:focus, .aladin-input-number:focus {
|
||||
border-color: var(--toggle-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
[data-theme="light"] .aladin-input-text.search:focus {
|
||||
@@ -529,12 +574,6 @@
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
|
||||
.aladin-input-text.search.aladin-not-valid {
|
||||
-webkit-box-shadow:inset 0px 0px 0px 1px #f00;
|
||||
-moz-box-shadow:inset 0px 0px 0px 1px #f00;
|
||||
box-shadow:inset 0px 0px 0px 1px #f00;
|
||||
}
|
||||
|
||||
.aladin-input-text.aladin-not-valid {
|
||||
border: var(--border-size) solid var(--error-color);
|
||||
}
|
||||
@@ -543,8 +582,16 @@
|
||||
border: var(--border-size) solid var(--valid-color);
|
||||
}
|
||||
|
||||
.aladin-box-content > div {
|
||||
margin: 10px 0px 0px 0px;
|
||||
.aladin-valid {
|
||||
color: var(--valid-color);
|
||||
}
|
||||
|
||||
.aladin-not-valid {
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
.aladin-not-found {
|
||||
color: darkorange;
|
||||
}
|
||||
|
||||
.aladin-button:hover {
|
||||
@@ -554,18 +601,7 @@
|
||||
}
|
||||
|
||||
.aladin-vertical-list {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
list-style: none;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.aladin-vertical-list.left {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.aladin-vertical-list.right {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.aladin-vertical-list > *:first-child {
|
||||
@@ -601,10 +637,6 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.aladin-form-group > * {
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.aladin-form-group > *:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -811,7 +843,13 @@
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.aladin-context-menu-item:hover > .aladin-context-sub-menu {
|
||||
.aladin-stack-box .aladin-overlay-label {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aladin-context-menu-item:hover > .aladin-context-sub-menu,
|
||||
.aladin-context-menu-item:focus-within > .aladin-context-sub-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -834,6 +872,22 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.aladin-context-menu.left {
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.aladin-context-menu.top{
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.aladin-context-menu.bottom {
|
||||
top: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.aladin-context-menu .aladin-context-sub-menu.left {
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
@@ -858,6 +912,29 @@
|
||||
transform: translate(-100%, -100%);
|
||||
}
|
||||
|
||||
.aladin-box.left {
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.aladin-box.right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.aladin-box.bottom {
|
||||
top: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.aladin-box.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.aladin-box.left.top {
|
||||
transform: translate(-100%, -100%);
|
||||
}
|
||||
|
||||
.aladin-reticle {
|
||||
position: absolute;
|
||||
@@ -882,7 +959,7 @@
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
outline-style: none;
|
||||
padding: 0.2rem;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
font-family: monospace;
|
||||
box-sizing: border-box;
|
||||
@@ -912,9 +989,6 @@
|
||||
cursor: pointer;
|
||||
font-family: monospace;
|
||||
box-sizing: content-box;
|
||||
/* <option> colors */
|
||||
/* Remove focus outline */
|
||||
/* Remove IE arrow */
|
||||
}
|
||||
|
||||
/* This is done so that the select shrink to the size of its parent (coupled with flex)
|
||||
@@ -943,7 +1017,7 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
-webkit-appearance: none;
|
||||
outline-style: none;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border: var(--border-size) solid var(--border-color);
|
||||
border-radius: 0.4rem;
|
||||
width: 2rem;
|
||||
height: 1.5rem;
|
||||
@@ -952,20 +1026,17 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
|
||||
.aladin-input-color::-webkit-color-swatch {
|
||||
border: none;
|
||||
border-radius: 0.4rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aladin-input-color::-webkit-color-swatch-wrapper {
|
||||
border: none;
|
||||
border-radius: 0.4rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/********** Range Input Styles **********/
|
||||
/*Range Reset*/
|
||||
.aladin-input-range {
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
margin: 0.8rem 0;
|
||||
box-sizing: border-box;
|
||||
@@ -981,11 +1052,20 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
.aladin-input-range:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.aladin-input-text:-internal-autofill-selected,
|
||||
.aladin-input-text:-internal-autofill-selected:hover,
|
||||
.aladin-input-text:-internal-autofill-selected:focus,
|
||||
.aladin-input-text:-internal-autofill-selected:active {
|
||||
-webkit-box-shadow: 0 0 0 1000px var(--bg-color) inset !important;
|
||||
box-shadow: 0 0 0 1000px var(--bg-color) inset !important;
|
||||
-webkit-text-fill-color: var(--text-color) !important;
|
||||
padding-left: 0.5rem !important;
|
||||
}
|
||||
|
||||
/***** Chrome, Safari, Opera and Edge Chromium styles *****/
|
||||
|
||||
.aladin-input-range::-webkit-slider-container {
|
||||
background: var(--text-color);
|
||||
height: 0.1rem;
|
||||
min-height: 0.1rem;
|
||||
}
|
||||
@@ -999,8 +1079,7 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
|
||||
font-family: monospace;
|
||||
line-height: 1rem;
|
||||
|
||||
float: left;
|
||||
|
||||
}
|
||||
|
||||
.aladin-tooltip-container .aladin-tooltip {
|
||||
@@ -1076,22 +1155,22 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.aladin-container .aladin-color-picker {
|
||||
.aladin-color-picker {
|
||||
transform: translate(10px, 10px);
|
||||
position: fixed;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.aladin-container .aladin-view-label {
|
||||
.aladin-view-label {
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
background-color: #00000000;
|
||||
font-size: 1rem;
|
||||
color: var(--aladin-color);
|
||||
|
||||
text-shadow: 1px 0 var(--aladin-color-border), -1px 0 var(--aladin-color-border), 0 1px var(--aladin-color-border), 0 -1px var(--aladin-color-border),
|
||||
1px 1px var(--aladin-color-border), -1px -1px var(--aladin-color-border), 1px -1px var(--aladin-color-border), -1px 1px var(--aladin-color-border);
|
||||
text-shadow: 1px 0 var(--border-color), -1px 0 var(--border-color), 0 1px var(--border-color), 0 -1px var(--border-color),
|
||||
1px 1px var(--border-color), -1px -1px var(--border-color), 1px -1px var(--border-color), -1px 1px var(--border-color);
|
||||
}
|
||||
|
||||
/* *********************************************** */
|
||||
@@ -1112,46 +1191,28 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
*
|
||||
*/
|
||||
|
||||
.aladin-stack-control {
|
||||
position: absolute;
|
||||
top: 3rem;
|
||||
left: 0.2rem;
|
||||
.aladin-indicator {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
margin: 0 5px;
|
||||
vertical-align: middle;
|
||||
border: var(--border-size) solid var(--border-color);
|
||||
}
|
||||
|
||||
.aladin-settings-control {
|
||||
position: absolute;
|
||||
top: 5.4rem;
|
||||
left: 0.2rem;
|
||||
.aladin-indicator.aladin-not-found {
|
||||
background-color: darkorange;
|
||||
}
|
||||
|
||||
.aladin-link {
|
||||
color: var(--text-color);
|
||||
.aladin-indicator.aladin-valid {
|
||||
background-color: var(--valid-color);
|
||||
}
|
||||
|
||||
.aladin-link:hover {
|
||||
color: var(--hover-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.aladin-simbadPointer-control {
|
||||
position: absolute;
|
||||
top: 7.8rem;
|
||||
left: 0.2rem;
|
||||
}
|
||||
|
||||
.aladin-grid-control {
|
||||
position: absolute;
|
||||
top: 10.2rem;
|
||||
left: 0.2rem;
|
||||
}
|
||||
|
||||
|
||||
.aladin-colorPicker-control {
|
||||
position: absolute;
|
||||
top: 15rem;
|
||||
left: 0.2rem;
|
||||
}
|
||||
|
||||
.aladin-cooFrame {
|
||||
position: absolute;
|
||||
top: 0.2rem;
|
||||
@@ -1166,32 +1227,29 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
|
||||
.aladin-stack-box {
|
||||
min-width: 17rem;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.aladin-item-selected {
|
||||
border: var(--border-size) solid orange;
|
||||
}
|
||||
|
||||
.aladin-HiPS-filter-box {
|
||||
margin-top: 0.4rem;
|
||||
/*width: 250px;*/
|
||||
.aladin-HiPS-browser-box {
|
||||
height: 500px;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
.aladin-HiPS-filter-box .aladin-horizontal-list {
|
||||
justify-content: space-evenly;
|
||||
width:100%;
|
||||
.aladin-cat-browser-box {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.aladin-HiPS-browser-box .aladin-input-text {
|
||||
width: 100%;
|
||||
min-width: 300px;
|
||||
padding: 0.5rem;
|
||||
|
||||
}
|
||||
|
||||
.aladin-cat-browser-box .aladin-input-text.search {
|
||||
width: 100%;
|
||||
min-width: 300px;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.aladin-location {
|
||||
@@ -1213,6 +1271,7 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
border-radius: 0 0.2rem 0.2rem 0;
|
||||
box-sizing: content-box;
|
||||
width: 12.5rem;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
.aladin-location .aladin-location-copy {
|
||||
@@ -1262,6 +1321,12 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
max-width: 50vw;
|
||||
}
|
||||
|
||||
.aladin-status-bar{
|
||||
@@ -1280,10 +1345,15 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.aladin-share-control {
|
||||
.aladin-widgets-toolbar {
|
||||
position: absolute;
|
||||
top: 12.6rem;
|
||||
left: 0.2rem;
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
|
||||
.aladin-widgets-toolbar > * {
|
||||
padding-top: 0rem;
|
||||
margin-right: 0rem;
|
||||
}
|
||||
|
||||
.aladin-fullScreen-control {
|
||||
|
||||
@@ -117,8 +117,6 @@ A.aladin = function (divSelector, options) {
|
||||
} else {
|
||||
theme = retrieveDefaultMode()
|
||||
}
|
||||
// Retrieve the data-theme from localStorage or system preferences
|
||||
divElement.setAttribute("data-theme", theme);
|
||||
|
||||
// Associate the CSS inside the div
|
||||
var cssStyleSheet = document.createElement('style')
|
||||
@@ -126,7 +124,10 @@ A.aladin = function (divSelector, options) {
|
||||
cssStyleSheet.innerHTML = aladinCSS;
|
||||
divElement.appendChild(cssStyleSheet)
|
||||
|
||||
return new Aladin(divElement, options);
|
||||
let aladin = new Aladin(divElement, options);
|
||||
aladin._applyTheme(theme)
|
||||
|
||||
return aladin;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -904,7 +905,7 @@ A.catalogFromSkyBot = function (ra, dec, radius, epoch, queryOptions, options, s
|
||||
* @param {function} [options.action] - The callback function to execute when the button is clicked.
|
||||
* @param {string} [options.title] - The title attribute for the button.
|
||||
* @param {Object} [options.icon] - An icon object for the button.
|
||||
* @param {boolean} [options.disable=false] - Whether the button is initially disabled.
|
||||
* @param {boolean} [options.disabled=false] - Whether the button is initially disabled.
|
||||
* @param {HTMLElement|string|Widget} [options.content] - The content to be added to the button.
|
||||
* @param {CSSStyleSheet} [options.cssStyle] - The CSS styles to apply to the button.
|
||||
* @param {Object} [options.tooltip] - A tooltip.
|
||||
|
||||
176
src/js/Aladin.js
176
src/js/Aladin.js
@@ -42,7 +42,7 @@ import { Coo } from "./libs/astro/coo.js";
|
||||
import { CooConversion } from "./CooConversion.js";
|
||||
import { HiPSCache } from "./HiPSCache.js";
|
||||
import { HiPSList } from "./DefaultHiPSList.js";
|
||||
|
||||
import { Toolbar } from "./gui/Toolbar.js";
|
||||
import { ProjectionEnum } from "./ProjectionEnum.js";
|
||||
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
@@ -64,12 +64,11 @@ import A from "./A.js";
|
||||
import { StatusBarBox } from "./gui/Box/StatusBarBox.js";
|
||||
import { FullScreenActionButton } from "./gui/Button/FullScreen.js";
|
||||
import { ProjectionActionButton } from "./gui/Button/Projection.js";
|
||||
|
||||
import { Stack } from "./gui/Button/Stack.js";
|
||||
// features
|
||||
import { SettingsButton } from "./gui/Button/Settings";
|
||||
import { SimbadPointer } from "./gui/Button/SimbadPointer";
|
||||
import { ColorPicker } from "./gui/Button/ColorPicker";
|
||||
import { OverlayStackButton } from "./gui/Button/OverlayStack";
|
||||
import { GridEnabler } from "./gui/Button/GridEnabler";
|
||||
import { CooFrame } from "./gui/Input/CooFrame";
|
||||
import { Circle } from "./shapes/Circle";
|
||||
@@ -156,6 +155,10 @@ import { Polyline } from "./shapes/Polyline";
|
||||
* @property {Object} [selector] - More options for the the selector.
|
||||
* @property {string} [selector.color] - Color of the selector, defaults to the color of the reticle. Can be a hex color or a function returning a hex color.
|
||||
* @property {number} [selector.lineWidth=2] - Width of the selector line.
|
||||
* @property {Object} [toolbar] - Toolbar object
|
||||
* @property {string} [toolbar.divSelector="null"] - A selector to put the toolbar in. By default the toolbar will be inserted in the Aladin Lite view.
|
||||
* @property {string} [toolbar.position="topleft"] - Can be 'topleft', 'topright', 'bottomleft', 'bottomright'. Default to 'topleft'
|
||||
* @property {boolean} [toolbar.vertical=true] - Is the toolbar horizontal or not. Default to vertical
|
||||
*
|
||||
* @example
|
||||
* let aladin = A.aladin({
|
||||
@@ -254,7 +257,7 @@ import { Polyline } from "./shapes/Polyline";
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {('select'|'objectsSelected'|'objectClicked'|'objectHovered'|'objectHoveredStop'|'footprintClicked'|'footprintHovered'|'positionChanged'|'zoomChanged'|'rotationChanged'|'click'|'rightClickMove'|'mouseMove'|'wheelTriggered'|'fullScreenToggled'|'cooFrameChanged'|'resizeChanged'|'projectionChanged'|'layerChanged')} EventListener
|
||||
* @typedef {('select'|'objectsSelected'|'objectClicked'|'objectHovered'|'objectHoveredStop'|'footprintClicked'|'footprintHovered'|'positionChanged'|'zoomChanged'|'rotationChanged'|'click'|'rightClickMove'|'mouseMove'|'wheelTriggered'|'fullScreenToggled'|'cooFrameChanged'|'resizeChanged'|'projectionChanged'|'stackChanged')} EventListener
|
||||
*
|
||||
* <ul>
|
||||
* <li>'positionChanged' is triggered when the view position has been changed. It gives the user the new center position of the view in ICRS frame. See {@link positionChangedParam}</li>
|
||||
@@ -262,6 +265,7 @@ import { Polyline } from "./shapes/Polyline";
|
||||
* <li>'mouseMove' is triggered when the mouse move over the view. It gives the the user the new position of the cursor in the current frame. See {@link mouseMoveParam}</li>
|
||||
* <li>'wheelTriggered' allows to redefine the zooming. Listening for it will disable the default zooming heuristic.</li>
|
||||
* <li>'objectsSelected', 'objectClicked', 'objectHovered', 'objectHoveredStop', 'footprintClicked', 'footprintHovered' are triggered when a catalog source/footprint has been clicked, hovered, ...
|
||||
* <li>'stackChanged' is triggered when a layer has been added, removed or swapped. The callback passed is an object having fields. The layer object that has been added/removed (or the swapped layers) and a flag that tells you if it has been 'added', 'removed' or 'swapped'.
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
@@ -301,14 +305,32 @@ export let Aladin = (function () {
|
||||
|
||||
const self = this;
|
||||
|
||||
ALEvent.HIPS_LAYER_ADDED.listenedBy(aladinDiv, (imageLayer) => {
|
||||
this.callbacksByEventName["layerChanged"] &&
|
||||
this.callbacksByEventName["layerChanged"](imageLayer.detail.layer, imageLayer.detail.layer.layer, "ADDED");
|
||||
ALEvent.LAYER_ADDED.listenedBy(aladinDiv, (e) => {
|
||||
const {layer} = e.detail;
|
||||
let callback = this.callbacksByEventName["stackChanged"];
|
||||
callback && callback({
|
||||
change: 'added',
|
||||
layer,
|
||||
});
|
||||
});
|
||||
|
||||
ALEvent.HIPS_LAYER_REMOVED.listenedBy(aladinDiv, (imageLayer) => {
|
||||
this.callbacksByEventName["layerChanged"] &&
|
||||
this.callbacksByEventName["layerChanged"](imageLayer.detail.layer, imageLayer.detail.layer.layer, "REMOVED");
|
||||
ALEvent.LAYER_REMOVED.listenedBy(aladinDiv, (e) => {
|
||||
const {layer} = e.detail;
|
||||
let callback = this.callbacksByEventName["stackChanged"];
|
||||
callback && callback({
|
||||
change: 'removed',
|
||||
layer
|
||||
});
|
||||
});
|
||||
|
||||
ALEvent.LAYER_SWAPPED.listenedBy(aladinDiv, (e) => {
|
||||
const {layer1, layer2} = e.detail;
|
||||
let callback = this.callbacksByEventName["stackChanged"];
|
||||
callback && callback({
|
||||
change: 'swapped',
|
||||
layer1,
|
||||
layer2
|
||||
});
|
||||
});
|
||||
|
||||
// if not options was set, try to retrieve them from the query string
|
||||
@@ -335,6 +357,10 @@ export let Aladin = (function () {
|
||||
...Aladin.DEFAULT_OPTIONS.gridOptions,
|
||||
...requestedOptions.gridOptions
|
||||
},
|
||||
toolbar: {
|
||||
...Aladin.DEFAULT_OPTIONS.toolbar,
|
||||
...requestedOptions.toolbar
|
||||
},
|
||||
// and use the slice method to create a new array for the hipsList property:
|
||||
// https://stackoverflow.com/questions/7486085/copy-array-by-value
|
||||
hipsList: requestedOptions.hipsList || Aladin.DEFAULT_OPTIONS.hipsList.slice()
|
||||
@@ -358,6 +384,11 @@ export let Aladin = (function () {
|
||||
|
||||
this.reticle = new Reticle(this.options, this);
|
||||
this.popup = new Popup(this.aladinDiv, this.view);
|
||||
this.tooltip = document.createElement('div')
|
||||
this.tooltip.id = 'aladin-tooltip-mouse';
|
||||
this.tooltip.classList.add("aladin-box")
|
||||
|
||||
this.aladinDiv.appendChild(this.tooltip)
|
||||
|
||||
this.ui = [];
|
||||
|
||||
@@ -395,7 +426,7 @@ export let Aladin = (function () {
|
||||
}
|
||||
}
|
||||
|
||||
// Format the hipslist given by the user before storing it in the aladin objec
|
||||
// Format the hipslist given by the user before storing it in the aladin instance
|
||||
this.hipsFavorites = [];
|
||||
let hipsList = [].concat(options.hipsList);
|
||||
|
||||
@@ -421,7 +452,7 @@ export let Aladin = (function () {
|
||||
|
||||
name = hips.name || hips.id || hips.url;
|
||||
|
||||
hipsObj = { ...hipsObj, ...hips };
|
||||
hipsObj = { ...hips };
|
||||
} else {
|
||||
console.warn(
|
||||
"unable to parse the survey list item: ",
|
||||
@@ -440,9 +471,6 @@ export let Aladin = (function () {
|
||||
hipsObj["name"] = name;
|
||||
}
|
||||
|
||||
// at least id or url is defined
|
||||
//let key = name || id || url;
|
||||
|
||||
// Merge what is already in the cache for that HiPS with new properties
|
||||
// coming from the MOCServer
|
||||
this.hipsFavorites.push(hipsObj);
|
||||
@@ -532,9 +560,9 @@ export let Aladin = (function () {
|
||||
|
||||
// set right click context menu
|
||||
if (options.showContextMenu) {
|
||||
this.contextMenu = new ContextMenu(this);
|
||||
this.contextMenu.attach(
|
||||
DefaultActionsForContextMenu.getDefaultActions(this)
|
||||
DefaultActionsForContextMenu.getDefaultActions(this),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -557,9 +585,25 @@ export let Aladin = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
Aladin.prototype._applyTheme = function(newTheme) {
|
||||
this.aladinDiv.setAttribute("data-theme", newTheme);
|
||||
this.toolbar.el.setAttribute("data-theme", newTheme);
|
||||
}
|
||||
|
||||
Aladin.prototype._setupUI = function (options) {
|
||||
let self = this;
|
||||
|
||||
this.contextMenu = new ContextMenu(this);
|
||||
|
||||
let toolbarDivSelector = options && options.toolbar.divSelector || this.aladinDiv;
|
||||
if (!(toolbarDivSelector instanceof HTMLElement)) {
|
||||
toolbarDivSelector = document.querySelector(toolbarDivSelector);
|
||||
}
|
||||
this.toolbar = new Toolbar({
|
||||
classList: ["aladin-widgets-toolbar"],
|
||||
...options.toolbar
|
||||
}, toolbarDivSelector)
|
||||
|
||||
// Status bar
|
||||
if (options.showStatusBar) {
|
||||
this.statusBar = new StatusBarBox(this);
|
||||
@@ -582,48 +626,48 @@ export let Aladin = (function () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
let stack = new OverlayStackButton(this);
|
||||
let simbad = new SimbadPointer(this);
|
||||
let colorPicker = new ColorPicker(this);
|
||||
let grid = new GridEnabler(this);
|
||||
this.addUI(stack);
|
||||
this.addUI(simbad);
|
||||
this.addUI(grid);
|
||||
this.addUI(colorPicker)
|
||||
let widgets = {};
|
||||
|
||||
// Add the layers control
|
||||
if (!options.showLayersControl) {
|
||||
stack._hide();
|
||||
}
|
||||
|
||||
// Add the simbad pointer control
|
||||
if (!options.showSimbadPointerControl) {
|
||||
simbad._hide();
|
||||
}
|
||||
|
||||
// Add the projection control
|
||||
// Add the coo grid control
|
||||
if (!options.showCooGridControl) {
|
||||
grid._hide();
|
||||
}
|
||||
|
||||
// Add the projection control
|
||||
// Add the coo grid control
|
||||
if (!options.showColorPickerControl) {
|
||||
colorPicker._hide();
|
||||
if (options.showLayersControl) {
|
||||
let stack = new Stack(this);
|
||||
widgets["stack"] = stack
|
||||
}
|
||||
|
||||
// Settings control
|
||||
if (options.showSettingsControl) {
|
||||
let settings = new SettingsButton(this, {
|
||||
features: { stack, simbad, grid },
|
||||
});
|
||||
this.addUI(settings);
|
||||
let settings = new SettingsButton(this);
|
||||
widgets["settings"] = settings
|
||||
}
|
||||
|
||||
// Add the simbad pointer control
|
||||
if (options.showSimbadPointerControl) {
|
||||
let simbad = new SimbadPointer(this);
|
||||
widgets["simbad"] = simbad
|
||||
}
|
||||
|
||||
// Add the projection control
|
||||
// Add the coo grid control
|
||||
if (options.showCooGridControl) {
|
||||
let grid = new GridEnabler(this);
|
||||
widgets["grid"] = grid;
|
||||
}
|
||||
|
||||
// Add the projection control
|
||||
// Add the coo grid control
|
||||
if (options.showColorPickerControl) {
|
||||
let picker = new ColorPicker(this);
|
||||
widgets["picker"] = picker;
|
||||
}
|
||||
|
||||
// share control panel
|
||||
if (options.showShareControl) {
|
||||
this.addUI(new ShareActionButton(self));
|
||||
let share = new ShareActionButton(this);
|
||||
widgets["share"] = share;
|
||||
}
|
||||
|
||||
for (let [name, widget] of Object.entries(widgets)) {
|
||||
this.toolbar.add(name, widget);
|
||||
}
|
||||
|
||||
if (options.showProjectionControl) {
|
||||
@@ -751,6 +795,11 @@ export let Aladin = (function () {
|
||||
realFullscreen: false,
|
||||
pixelateCanvas: true,
|
||||
manualSelection: false,
|
||||
toolbar: {
|
||||
divSelector: null,
|
||||
vertical: true,
|
||||
position: 'topleft'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -764,7 +813,7 @@ export let Aladin = (function () {
|
||||
|
||||
self.isInFullscreen = !self.isInFullscreen;
|
||||
|
||||
ContextMenu.hideAll();
|
||||
this.contextMenu && this.contextMenu._hide();
|
||||
|
||||
this.ui.forEach(ui => {
|
||||
if (ui.toggle) {
|
||||
@@ -1097,7 +1146,6 @@ export let Aladin = (function () {
|
||||
|
||||
return projName;
|
||||
};
|
||||
``;
|
||||
|
||||
/**
|
||||
* Returns the current coordinate system: possible values are 'ICRS', 'ICRSd', and 'Galactic' .
|
||||
@@ -1114,6 +1162,16 @@ export let Aladin = (function () {
|
||||
return this.view.cooFrame.label;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a reference to the Aladin Lite toolbar object. User can append, remove DOMElement/widgets to it
|
||||
*
|
||||
* @memberof Aladin
|
||||
* @returns {Toolbar}
|
||||
*/
|
||||
Aladin.prototype.getToolbar = function () {
|
||||
return this.toolbar;
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves the Aladin instance to the specified astronomical object.
|
||||
*
|
||||
@@ -1772,14 +1830,6 @@ export let Aladin = (function () {
|
||||
name: hips.name,
|
||||
})
|
||||
|
||||
// and resort the favorites
|
||||
this.hipsFavorites.sort((h1, h2) => {
|
||||
let k1 = h1.name || h1.id || h1.url;
|
||||
let k2 = h2.name || h2.id || h2.url;
|
||||
|
||||
return k1 < k2;
|
||||
})
|
||||
|
||||
// send the final event
|
||||
ALEvent.FAVORITE_HIPS_LIST_UPDATED.dispatchedTo(document.body, this.hipsFavorites);
|
||||
}
|
||||
@@ -2231,7 +2281,7 @@ export let Aladin = (function () {
|
||||
"cooFrameChanged",
|
||||
"resizeChanged",
|
||||
"projectionChanged",
|
||||
"layerChanged"
|
||||
"stackChanged"
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -2289,9 +2339,9 @@ export let Aladin = (function () {
|
||||
console.log("positionChanged", ra, dec)
|
||||
})
|
||||
|
||||
aladin.on("layerChanged", (layer, layerName, state) => {
|
||||
console.log("layerChanged", layer, layerName, state)
|
||||
})
|
||||
aladin.on('stackChanged', function(state) {
|
||||
console.log(state)
|
||||
});
|
||||
*/
|
||||
Aladin.prototype.on = function (what, myFunction) {
|
||||
if (Aladin.AVAILABLE_CALLBACKS.indexOf(what) < 0) {
|
||||
|
||||
@@ -112,11 +112,6 @@ export let Footprint= (function() {
|
||||
this.overlay.reportChange();
|
||||
return;
|
||||
}
|
||||
|
||||
/*let catalog = this.getCatalog();
|
||||
if (catalog) {
|
||||
catalog.view && catalog.view.requestRedraw();
|
||||
}*/
|
||||
};
|
||||
|
||||
Footprint.prototype.unhover = function() {
|
||||
@@ -209,35 +204,6 @@ export let Footprint= (function() {
|
||||
};
|
||||
|
||||
Footprint.prototype.intersectsBBox = function(x, y, w, h, view) {
|
||||
/*if(this.source) {
|
||||
let s = this.source;
|
||||
|
||||
if (!s.isShowing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let c = null;
|
||||
if (s.x && s.y) {
|
||||
c = {
|
||||
x: s.x,
|
||||
y: s.y,
|
||||
};
|
||||
} else {
|
||||
var xy = view.aladin.world2pix(s.ra, s.dec);
|
||||
if (!xy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
c = {
|
||||
x: xy[0],
|
||||
y: xy[1],
|
||||
};
|
||||
}
|
||||
|
||||
if (c.x >= x && c.x <= x + w && c.y >= y && c.y <= y + h) {
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
return this.shapes.some((shape) => shape.intersectsBBox(x, y, w, h, view));
|
||||
};
|
||||
|
||||
|
||||
@@ -339,7 +339,6 @@ export let HiPS = (function () {
|
||||
await HiPSProperties.fetchFromFile(self.localFiles["properties"])
|
||||
.then((p) => {
|
||||
self._parseProperties(p);
|
||||
|
||||
self.url = "local";
|
||||
|
||||
delete self.localFiles["properties"]
|
||||
@@ -870,7 +869,7 @@ export let HiPS = (function () {
|
||||
imgFormat: this.imgFormat,
|
||||
});
|
||||
// once the meta have been well parsed, we can set the meta
|
||||
ALEvent.HIPS_LAYER_CHANGED.dispatchedTo(this.view.aladinDiv, {
|
||||
ALEvent.LAYER_CHANGED.dispatchedTo(this.view.aladinDiv, {
|
||||
layer: this,
|
||||
});
|
||||
}
|
||||
@@ -1075,7 +1074,19 @@ export let HiPS = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
HiPS.prototype._add2View = function (layer) {
|
||||
HiPS.prototype._removeFromView = function() {
|
||||
if (!this.view)
|
||||
return;
|
||||
|
||||
if (this.added) {
|
||||
this.view.wasm.removeLayer(this.layer);
|
||||
}
|
||||
};
|
||||
|
||||
HiPS.prototype._addToView = function (layer) {
|
||||
if (!this.view)
|
||||
return this;
|
||||
|
||||
this.layer = layer;
|
||||
let self = this;
|
||||
|
||||
|
||||
86
src/js/HiPSComposite.js
Normal file
86
src/js/HiPSComposite.js
Normal file
@@ -0,0 +1,86 @@
|
||||
// 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 HiPSComposite.js
|
||||
*
|
||||
* Authors: Matthieu Baumann [CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
import { HiPS } from "./HiPS.js";
|
||||
import A from "./A.js";
|
||||
|
||||
export let HiPSComposite = (function () {
|
||||
/**
|
||||
* The object describing the color composition of image surveys
|
||||
*
|
||||
* @class
|
||||
* @constructs HiPSComposite
|
||||
*
|
||||
* @param {HiPSOptions[]} [options] - The option for the survey
|
||||
*/
|
||||
function HiPSComposite(options) {
|
||||
this.name = options && options.name || 'Composite HiPS';
|
||||
this.hipses = []
|
||||
};
|
||||
|
||||
HiPSComposite.prototype.setOptions = function(options) {
|
||||
this.hipses = [];
|
||||
for (var hipsOptions of options) {
|
||||
let hips = A.HiPS(hipsOptions.id, hipsOptions)
|
||||
this.hipses.push(hips)
|
||||
}
|
||||
};
|
||||
|
||||
HiPSComposite.prototype._setView = HiPS.prototype._setView;
|
||||
|
||||
HiPSComposite.prototype._addToView = function (layer) {
|
||||
this._removeFromView();
|
||||
|
||||
this.layer = layer;
|
||||
|
||||
let i = 0;
|
||||
for (var hips of this.hipses) {
|
||||
hips._addToView(layer + '_' + i)
|
||||
i++;
|
||||
}
|
||||
|
||||
return this
|
||||
};
|
||||
|
||||
HiPSComposite.prototype._removeFromView = function() {
|
||||
for (var hips of this.hipses) {
|
||||
hips._removeFromView()
|
||||
}
|
||||
}
|
||||
|
||||
HiPSComposite.prototype.getOpacity = function() {
|
||||
return this.hipses[0].getOpacity()
|
||||
}
|
||||
|
||||
HiPSComposite.prototype.setOpacity = function(opacity) {
|
||||
for (var hips of this.hipses) {
|
||||
hips.setOpacity(opacity)
|
||||
}
|
||||
}
|
||||
|
||||
return HiPSComposite;
|
||||
})();
|
||||
@@ -362,7 +362,9 @@ export let Image = (function () {
|
||||
// Private method for updating the view with the new meta
|
||||
Image.prototype._updateMetadata = HiPS.prototype._updateMetadata;
|
||||
|
||||
Image.prototype._add2View = function (layer) {
|
||||
Image.prototype._removeFromView = HiPS.prototype._removeFromView;
|
||||
|
||||
Image.prototype._addToView = function (layer) {
|
||||
this.layer = layer;
|
||||
|
||||
let self = this;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Color } from "./Color.js"
|
||||
import { Icon } from "./gui/Widgets/Icon.js";
|
||||
import { Tabs } from "./gui/Widgets/Tab.js";
|
||||
import { Table } from "./gui/Widgets/Table.js";
|
||||
@@ -77,7 +76,7 @@ export let MeasurementTable = (function() {
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin: this.aladin,
|
||||
content: 'Press shift + mouse wheel for scrolling'
|
||||
content: 'Scroll to see more...'
|
||||
},
|
||||
aladin: this.aladin,
|
||||
layout,
|
||||
|
||||
@@ -51,8 +51,7 @@ export class MocServer {
|
||||
//expr: "dataproduct_type=image",
|
||||
get: "record",
|
||||
fmt: "json",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_order,hips_tile_width,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime,client_category",
|
||||
//fields: "ID,hips_initial_fov,hips_initial_ra,hips_initial_dec,hips_pixel_bitpix,hips_creator,hips_copyright,hips_frame,hips_order,hips_order_min,hips_tile_width,hips_tile_format,hips_pixel_cut,obs_title,obs_description,obs_copyright,obs_regime,hips_data_range,hips_service_url",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_order,hips_tile_width,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime,client_category,dataproduct_subtype,hips_service_url,hips_initial_ra,hips_initial_dec,hips_initial_fov,em_min,em_max",
|
||||
};
|
||||
|
||||
this._allHiPSes = Utils.loadFromUrls(MocServer.MIRRORS_HTTPS, {
|
||||
@@ -97,8 +96,7 @@ export class MocServer {
|
||||
expr: "dataproduct_type=image&&ID=" + ids.join(','),
|
||||
get: "record",
|
||||
fmt: "json",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime",
|
||||
//fields: "ID,hips_initial_fov,hips_initial_ra,hips_initial_dec,hips_pixel_bitpix,hips_creator,hips_copyright,hips_frame,hips_order,hips_order_min,hips_tile_width,hips_tile_format,hips_pixel_cut,obs_title,obs_description,obs_copyright,obs_regime,hips_data_range,hips_service_url",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime,dataproduct_subtype,hips_service_url,hips_initial_ra,hips_initial_dec,hips_initial_fov,em_min,em_max",
|
||||
};
|
||||
|
||||
return Utils.loadFromUrls(MocServer.MIRRORS_HTTPS, {
|
||||
@@ -114,7 +112,6 @@ export class MocServer {
|
||||
get: "record",
|
||||
fmt: "json",
|
||||
fields: "ID,hips_copyright,obs_title,obs_description,obs_copyright,cs_service_url,hips_service_url",
|
||||
//fields: "ID,hips_copyright,hips_order,hips_order_min,obs_title,obs_description,obs_copyright,obs_regime,cs_service_url,hips_service_url",
|
||||
};
|
||||
|
||||
this._allCatalogHiPSes = Utils.loadFromUrls(MocServer.MIRRORS_HTTPS, {data: params, dataType: 'json'})
|
||||
|
||||
@@ -624,12 +624,13 @@ export let ProgressiveCat = (function() {
|
||||
},
|
||||
|
||||
computeFootprints: Catalog.prototype.computeFootprints,
|
||||
setSourceSize: Catalog.prototype.setSourceSize,
|
||||
setShape: Catalog.prototype.setShape,
|
||||
setColor: Catalog.prototype.setColor,
|
||||
|
||||
reportChange: function() { // TODO: to be shared with Catalog
|
||||
this.view && this.view.requestRedraw();
|
||||
}
|
||||
|
||||
|
||||
}; // END OF .prototype functions
|
||||
|
||||
ProgressiveCat.parser = new DOMParser();
|
||||
|
||||
@@ -34,20 +34,20 @@ export let ProjectionEnum = {
|
||||
SIN: {id: 3, label: "Spheric"}, /* Orthographic */
|
||||
// TODO: fix why the projection disappears at fov = 360.0
|
||||
ZEA: {id: 4, label: "Zenital equal-area"}, /* Equal-area */
|
||||
//FEYE: {id: 5, fov: 190, label: "fish eye"},
|
||||
//AIR: {id: 6, fov: 360, label: "airy"},
|
||||
/*FEYE: {id: 5, fov: 190, label: "fish eye"},
|
||||
AIR: {id: 6, fov: 360, label: "airy"},
|
||||
//AZP: {fov: 180},
|
||||
//ARC: {id: 7, fov: 360, label: "zenital equidistant"},
|
||||
//NCP: {id: 8, fov: 180, label: "north celestial pole"},
|
||||
ARC: {id: 7, fov: 360, label: "zenital equidistant"},
|
||||
NCP: {id: 8, fov: 180, label: "north celestial pole"},*/
|
||||
// Cylindrical
|
||||
MER: {id: 9, label: "Mercator"},
|
||||
//CAR: {id: 10, fov: 360, label: "plate carrée"},
|
||||
//CEA: {id: 11, fov: 360, label: "cylindrical equal area"},
|
||||
//CYP: {id: 12, fov: 360, label: "cylindrical perspective"},
|
||||
/*CAR: {id: 10, fov: 360, label: "plate carrée"},
|
||||
CEA: {id: 11, fov: 360, label: "cylindrical equal area"},
|
||||
CYP: {id: 12, fov: 360, label: "cylindrical perspective"},*/
|
||||
// Pseudo-cylindrical
|
||||
AIT: {id: 13, label: "Hammer-Aïtoff"},
|
||||
//PAR: {id: 14, fov: 360, label: "parabolic"},
|
||||
//SFL: {id: 15, fov: 360, label: "sanson-flamsteed"},
|
||||
/*PAR: {id: 14, fov: 360, label: "parabolic"},
|
||||
SFL: {id: 15, fov: 360, label: "sanson-flamsteed"},*/
|
||||
MOL: {id: 16, label: "Mollweide"},
|
||||
// Conic
|
||||
//COD: {id: 17, fov: 360, label: "conic equidistant"},
|
||||
|
||||
@@ -23,7 +23,7 @@ import HomeIconUrl from '../../assets/icons/maximize.svg';
|
||||
import SpectraIconUrl from '../../assets/icons/freq.svg';
|
||||
import { Utils } from "./Utils";
|
||||
import { Aladin } from "./Aladin";
|
||||
|
||||
import { DOMElement } from "./gui/Widgets/Widget";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -34,7 +34,7 @@ import { Aladin } from "./Aladin";
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
export class SpectraDisplayer {
|
||||
export class SpectraDisplayer extends DOMElement {
|
||||
static UNIT = {
|
||||
FREQUENCY: {
|
||||
label: "f",
|
||||
@@ -118,6 +118,8 @@ export class SpectraDisplayer {
|
||||
};
|
||||
|
||||
constructor(view, options) {
|
||||
super()
|
||||
|
||||
let createPlotCanvas = (name) => {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.classList.add(name);
|
||||
@@ -555,67 +557,9 @@ export class SpectraDisplayer {
|
||||
|
||||
this.view.catalogCanvas.dispatchEvent(wheelEvent);
|
||||
});
|
||||
|
||||
/*
|
||||
const updateSelectorList = () => {
|
||||
let options = [];
|
||||
for (const hipsName of this.hips3DList.keys()) {
|
||||
options.push(hipsName)
|
||||
}
|
||||
|
||||
this.selector.update({options})
|
||||
};
|
||||
|
||||
ALEvent.HIPS_LAYER_ADDED.listenedBy(
|
||||
this.view.aladin.aladinDiv,
|
||||
function (e) {
|
||||
let hips = e.detail.layer;
|
||||
|
||||
if (hips.dataproductType === "spectral-cube") {
|
||||
self.hips3DList.set(hips.name, hips);
|
||||
|
||||
updateSelectorList()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.HIPS_LAYER_SWAP.listenedBy(
|
||||
this.view.aladin.aladinDiv,
|
||||
function (e) {
|
||||
let firstHiPS = e.detail.firstLayer;
|
||||
let secondHiPS = e.detail.secondLayer;
|
||||
|
||||
self.hips3DList.delete(firstHiPS.name);
|
||||
|
||||
if (secondHiPS.dataproductType === "spectral-cube") {
|
||||
self.hips3DList.set(secondHiPS.name, secondHiPS);
|
||||
}
|
||||
|
||||
updateSelectorList()
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.HIPS_LAYER_REMOVED.listenedBy(
|
||||
this.view.aladin.aladinDiv,
|
||||
function (e) {
|
||||
let hips = e.detail.layer;
|
||||
self.hips3DList.delete(hips.name);
|
||||
|
||||
if (hips === this.hips) {
|
||||
// the hips pointed by the tool has been removed
|
||||
self.attachHiPS3D(null);
|
||||
}
|
||||
|
||||
if (self.hips3DList.size === 0) {
|
||||
self.hide()
|
||||
}
|
||||
|
||||
updateSelectorList()
|
||||
}
|
||||
);*/
|
||||
}
|
||||
|
||||
hide() {
|
||||
_hide() {
|
||||
if (this.isHidden) {
|
||||
return;
|
||||
}
|
||||
@@ -624,7 +568,7 @@ export class SpectraDisplayer {
|
||||
this.isHidden = true;
|
||||
}
|
||||
|
||||
show() {
|
||||
_show() {
|
||||
if (!this.isHidden) {
|
||||
return;
|
||||
}
|
||||
@@ -654,7 +598,7 @@ export class SpectraDisplayer {
|
||||
window.addEventListener("spectra", this.spectraUpdateCallback);
|
||||
|
||||
this.resetScale();
|
||||
this.show()
|
||||
this._show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
103
src/js/View.js
103
src/js/View.js
@@ -48,6 +48,7 @@ import { HiPS } from "./HiPS.js";
|
||||
import { Image } from "./Image.js";
|
||||
import { Color } from "./Color.js";
|
||||
import { SpectraDisplayer } from "./SpectraDisplayer.js";
|
||||
import { DefaultActionsForContextMenu } from "./DefaultActionsForContextMenu.js";
|
||||
|
||||
export let View = (function () {
|
||||
|
||||
@@ -93,7 +94,7 @@ export let View = (function () {
|
||||
// 1. Print the original exception message in the console
|
||||
//console.error(e)
|
||||
// 2. Add a more explicite message to the end user
|
||||
console.error("Problem initializing Aladin Lite. Please contact the support by contacting Matthieu Baumann (baumannmatthieu0@gmail.com) or Thomas Boch (thomas.boch@astro.unistra.fr). You can also open an issue on the Aladin Lite github repository here: https://github.com/cds-astro/aladin-lite. Message error:" + e)
|
||||
console.error("Problem initializing Aladin Lite. Please contact the support by contacting Matthieu Baumann (matthieu.baumann@astro.unistra.fr) or Thomas Boch (thomas.boch@astro.unistra.fr). You can also open an issue on the Aladin Lite github repository here: https://github.com/cds-astro/aladin-lite. Message error:" + e)
|
||||
}
|
||||
|
||||
this._defineProperties();
|
||||
@@ -276,7 +277,6 @@ export let View = (function () {
|
||||
colorPickerElement = document.createElement('span');
|
||||
colorPickerElement.classList.add('aladin-color-picker')
|
||||
colorPickerElement.classList.add('aladin-view-label')
|
||||
colorPickerElement.classList.add('aladin-dark-theme')
|
||||
|
||||
this.aladin.aladinDiv.appendChild(colorPickerElement);
|
||||
}
|
||||
@@ -596,6 +596,9 @@ export let View = (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.spectraDisplayer)
|
||||
this.spectraDisplayer._hide();
|
||||
|
||||
if (imageLayer.dataproductType === "spectral-cube") {
|
||||
if (!this.spectraDisplayer) {
|
||||
this.spectraDisplayer = new SpectraDisplayer(this, {width: 800, height: 300});
|
||||
@@ -833,7 +836,7 @@ export let View = (function () {
|
||||
.then(() => {
|
||||
if (view.aladin.statusBar) {
|
||||
view.aladin.statusBar.appendMessage({
|
||||
message: `${view.colorPickerTool.probedValue} copied into your clipboard`,
|
||||
message: `<span class="aladin-indicator" style="background-color: ${view.colorPickerTool.probedValue}"></span> [${view.colorPickerTool.probedValue}] copied into your clipboard`,
|
||||
duration: 1500,
|
||||
type: 'info'
|
||||
})
|
||||
@@ -904,25 +907,7 @@ export let View = (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
var wasDragging = view.realDragging === true;
|
||||
|
||||
/*if (view.dragging) { // if we were dragging, reset to default cursor
|
||||
if(view.mode === View.PAN) {
|
||||
view.setCursor('default');
|
||||
}
|
||||
|
||||
view.dragging = false;
|
||||
if (wasDragging) {
|
||||
view.realDragging = false;
|
||||
|
||||
// call the positionChanged once more with a dragging = false
|
||||
view.throttledPositionChanged(false);
|
||||
}
|
||||
|
||||
if (view.spectraDisplayer) {
|
||||
view.spectraDisplayer.enableInteraction();
|
||||
}
|
||||
} // end of "if (view.dragging) ... "*/
|
||||
var wasDragging = view.realDragging === true;
|
||||
|
||||
view.mustClearCatalog = true;
|
||||
view.dragCoo = null;
|
||||
@@ -953,8 +938,13 @@ export let View = (function () {
|
||||
}
|
||||
|
||||
if (view.rightClick) {
|
||||
if (showContextMenu) {
|
||||
view.aladin.contextMenu && view.aladin.contextMenu.show({e});
|
||||
let ctxMenu = view.aladin.contextMenu;
|
||||
if (showContextMenu && ctxMenu) {
|
||||
ctxMenu.attach(
|
||||
DefaultActionsForContextMenu.getDefaultActions(view.aladin),
|
||||
null
|
||||
);
|
||||
ctxMenu._show({e});
|
||||
}
|
||||
|
||||
view.rightClick = false;
|
||||
@@ -1796,7 +1786,7 @@ export let View = (function () {
|
||||
|
||||
if (alreadyPresentImageLayer) {
|
||||
if (alreadyPresentImageLayer.added === true) {
|
||||
ALEvent.HIPS_LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer: alreadyPresentImageLayer });
|
||||
ALEvent.LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer: alreadyPresentImageLayer });
|
||||
}
|
||||
|
||||
alreadyPresentImageLayer.added = false;
|
||||
@@ -1813,16 +1803,15 @@ export let View = (function () {
|
||||
// Insert a layer object (Image/HiPS) at a specific index in the stack
|
||||
View.prototype._addLayer = function(imageLayer) {
|
||||
// Keep the JS frontend in-line with the wasm state
|
||||
const layerName = imageLayer.layer;
|
||||
|
||||
const layer = imageLayer.layer;
|
||||
imageLayer.added = true;
|
||||
|
||||
this.imageLayers.set(layerName, imageLayer);
|
||||
this.imageLayers.set(layer, imageLayer);
|
||||
|
||||
// select the layer if he is on top
|
||||
this.selectLayer(layerName);
|
||||
this.selectLayer(layer);
|
||||
|
||||
ALEvent.HIPS_LAYER_ADDED.dispatchedTo(this.aladinDiv, { layer: imageLayer });
|
||||
ALEvent.LAYER_ADDED.dispatchedTo(this.aladinDiv, { layer: imageLayer });
|
||||
}
|
||||
|
||||
View.prototype.addImageLayer = function (imageLayer, layer) {
|
||||
@@ -1835,7 +1824,7 @@ export let View = (function () {
|
||||
|
||||
// All image layer promises must be completed (fullfilled or rejected)
|
||||
const task = {
|
||||
message: 'Load layer: ' + imageLayer.name,
|
||||
message: imageLayer.name + ' loading...',
|
||||
id: Utils.uuidv4(),
|
||||
}
|
||||
// Ensure all the properties for HiPSes have been seeked
|
||||
@@ -1844,7 +1833,7 @@ export let View = (function () {
|
||||
// so that we can add it to the view (call of _add2View)
|
||||
Promise.all([Promise.allSettled(this.promises), imageLayerPromise])
|
||||
// Then we add the layer to the view
|
||||
.then((_) => imageLayer._add2View(layer))
|
||||
.then((_) => imageLayer._addToView(layer))
|
||||
// Then we keep a track of the layer in the JS front
|
||||
.then((imageLayer) => {
|
||||
this._addLayer(imageLayer);
|
||||
@@ -1877,37 +1866,29 @@ export let View = (function () {
|
||||
|
||||
// Remove the settled promise
|
||||
this.promises.splice(idx, 1);
|
||||
|
||||
/*const noMoreLayersToWaitFor = this.promises.length === 0;
|
||||
|
||||
if (noMoreLayersToWaitFor) {
|
||||
if (self.empty) {
|
||||
// no promises to launch and the view has no HiPS.
|
||||
// This situation can occurs if the MOCServer is out
|
||||
// If so we can directly put the url of the DSS hosted in alasky,
|
||||
// it the best I can do if the MOCServer is out
|
||||
self.aladin.setBaseImageLayer("https://alaskybis.cds.unistra.fr/DSS/DSSColor/");
|
||||
} else {
|
||||
//self.renameLayer(this.overlayLayers[0], "base");
|
||||
}
|
||||
}*/
|
||||
})
|
||||
}
|
||||
|
||||
View.prototype.swapLayers = function(firstLayer, secondLayer) {
|
||||
View.prototype.swapLayers = function(layer1, layer2) {
|
||||
// Throw an exception if either the first or the second layers are not in the stack
|
||||
this.wasm.swapLayers(firstLayer, secondLayer);
|
||||
this.wasm.swapLayers(layer1, layer2);
|
||||
|
||||
// Swap in overlaylayers
|
||||
const idxFirstLayer = this.overlayLayers.indexOf(firstLayer);
|
||||
const idxSecondLayer = this.overlayLayers.indexOf(secondLayer);
|
||||
const i = this.overlayLayers.indexOf(layer1);
|
||||
const j = this.overlayLayers.indexOf(layer2);
|
||||
|
||||
const tmp = this.overlayLayers[idxFirstLayer];
|
||||
this.overlayLayers[idxFirstLayer] = this.overlayLayers[idxSecondLayer];
|
||||
this.overlayLayers[idxSecondLayer] = tmp;
|
||||
const tmp = this.overlayLayers[i];
|
||||
this.overlayLayers[i] = this.overlayLayers[j];
|
||||
this.overlayLayers[j] = tmp;
|
||||
|
||||
// Tell the layer hierarchy has changed
|
||||
ALEvent.HIPS_LAYER_SWAP.dispatchedTo(this.aladinDiv, { firstLayer: firstLayer, secondLayer: secondLayer });
|
||||
ALEvent.LAYER_SWAPPED.dispatchedTo(
|
||||
this.aladinDiv,
|
||||
{
|
||||
layer1: this.imageLayers.get(layer1),
|
||||
layer2: this.imageLayers.get(layer2)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
View.prototype.removeImageLayer = function (layer) {
|
||||
@@ -1920,9 +1901,7 @@ export let View = (function () {
|
||||
}
|
||||
|
||||
// Update the backend
|
||||
if (imageLayer.added) {
|
||||
this.wasm.removeLayer(layer);
|
||||
}
|
||||
imageLayer._removeFromView();
|
||||
|
||||
// Get the survey to remove to dissociate it from the view
|
||||
imageLayer.added = false;
|
||||
@@ -1945,15 +1924,7 @@ export let View = (function () {
|
||||
this.selectLayer(this.overlayLayers[this.overlayLayers.length - 1]);
|
||||
}
|
||||
|
||||
ALEvent.HIPS_LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer: imageLayer });
|
||||
|
||||
// check if there are no more surveys
|
||||
/*const noMoreLayersToWaitFor = this.promises.length === 0;
|
||||
if (noMoreLayersToWaitFor && this.empty) {
|
||||
// no promises to launch!
|
||||
const dssId = Aladin.DEFAULT_OPTIONS.survey;
|
||||
this.aladin.setBaseImageLayer(dssId);
|
||||
}*/
|
||||
ALEvent.LAYER_REMOVED.dispatchedTo(this.aladinDiv, { layer: imageLayer });
|
||||
};
|
||||
|
||||
View.prototype.contains = function(survey) {
|
||||
|
||||
@@ -51,17 +51,14 @@ export class ALEvent {
|
||||
static POSITION_CHANGED = new ALEvent("AL:position.changed");
|
||||
static ZOOM_CHANGED = new ALEvent("AL:zoom.changed");
|
||||
|
||||
static HIPS_LAYER_ADDED = new ALEvent("AL:HiPSLayer.added");
|
||||
static HIPS_LAYER_REMOVED = new ALEvent("AL:HiPSLayer.removed");
|
||||
static HIPS_LAYER_RENAMED = new ALEvent("AL:HiPSLayer.renamed");
|
||||
static HIPS_LAYER_SWAP = new ALEvent("AL:HiPSLayer.swap");
|
||||
static HIPS_LAYER_CHANGED = new ALEvent("AL:HiPSLayer.changed");
|
||||
static LAYER_ADDED = new ALEvent("AL:Layer.added");
|
||||
static LAYER_REMOVED = new ALEvent("AL:Layer.removed");
|
||||
static LAYER_SWAPPED = new ALEvent("AL:Layer.swapped");
|
||||
static LAYER_CHANGED = new ALEvent("AL:Layer.changed");
|
||||
|
||||
static HIPS_CACHE_UPDATED = new ALEvent("AL:HiPSCache.updated");
|
||||
|
||||
static FAVORITE_HIPS_LIST_UPDATED = new ALEvent("AL:HiPSFavorites.updated");
|
||||
|
||||
|
||||
static GRAPHIC_OVERLAY_LAYER_ADDED = new ALEvent("AL:GraphicOverlayLayer.added");
|
||||
static GRAPHIC_OVERLAY_LAYER_REMOVED = new ALEvent("AL:GraphicOverlayLayer.removed");
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
CatalogQueryBox.catalogs[cat.obs_title] = cat;
|
||||
});
|
||||
|
||||
inputText.update({autocomplete: {options: Object.keys(CatalogQueryBox.catalogs)}})
|
||||
searchDropdown.update({options: Object.keys(CatalogQueryBox.catalogs)})
|
||||
})
|
||||
|
||||
const fnIdSelected = function(type, params) {
|
||||
@@ -120,12 +120,12 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
self.fnIdSelected('votable', {
|
||||
url: votableUrl,
|
||||
success: () => {
|
||||
inputText.addClass('aladin-valid');
|
||||
searchDropdown.addClass('aladin-valid');
|
||||
},
|
||||
error: () => {
|
||||
inputText.addClass('aladin-not-valid')
|
||||
self.csForm.submit.update({disable: true})
|
||||
self.hipsCatLoad.update({disable: true});
|
||||
searchDropdown.addClass('aladin-not-valid')
|
||||
self.csForm.submit.update({disabled: true})
|
||||
self.hipsCatLoad.update({disabled: true});
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
@@ -134,24 +134,24 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
|
||||
if (catalog) {
|
||||
self._selectItem(catalog, aladin);
|
||||
inputText.addClass('aladin-valid');
|
||||
searchDropdown.addClass('aladin-valid');
|
||||
} else {
|
||||
// consider it as a cat ID and search in catalogs for it
|
||||
const foundCat = Object.values(CatalogQueryBox.catalogs)
|
||||
.find((c) => c.ID === value);
|
||||
if (foundCat) {
|
||||
self._selectItem(foundCat, aladin);
|
||||
inputText.addClass('aladin-valid')
|
||||
searchDropdown.addClass('aladin-valid')
|
||||
} else {
|
||||
inputText.addClass('aladin-not-valid')
|
||||
self.csForm.submit.update({disable: true})
|
||||
self.hipsCatLoad.update({disable: true});
|
||||
searchDropdown.addClass('aladin-not-valid')
|
||||
self.csForm.submit.update({disabled: true})
|
||||
self.hipsCatLoad.update({disabled: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let inputText = new Dropdown(aladin, {
|
||||
let searchDropdown = new Dropdown(aladin, {
|
||||
name: 'catalogs',
|
||||
placeholder: "Type ID, title, keyword or URL",
|
||||
tooltip: {
|
||||
@@ -159,22 +159,9 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
aladin,
|
||||
content: 'HiPS url, ID or keyword accepted',
|
||||
},
|
||||
actions: {
|
||||
input(e) {
|
||||
inputText.removeClass('aladin-valid')
|
||||
inputText.removeClass('aladin-not-valid')
|
||||
},
|
||||
focus(e) {
|
||||
inputText.removeClass('aladin-valid')
|
||||
inputText.removeClass('aladin-not-valid')
|
||||
},
|
||||
change(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault()
|
||||
|
||||
_parseEntry(e)
|
||||
},
|
||||
},
|
||||
action: (e) => {
|
||||
_parseEntry(e)
|
||||
}
|
||||
});
|
||||
|
||||
let self;
|
||||
@@ -190,7 +177,7 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
position: {direction: "bottom"}
|
||||
},
|
||||
content: 'HiPS',
|
||||
disable: true,
|
||||
disabled: true,
|
||||
action() {
|
||||
self.fnIdSelected('hips', {
|
||||
hipsURL: self.selectedItem.hips_service_url,
|
||||
@@ -220,7 +207,6 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
let [lon, lat] = coo.format('s2');
|
||||
|
||||
let fov = new Angle(radius, 1).format();
|
||||
//selectorBtn.update({tooltip: {content: 'center: ' + ra.toFixed(2) + ', ' + dec.toFixed(2) + '<br\>radius: ' + radius.toFixed(2), position: {direction: 'left'}}})
|
||||
form.set('ra', lon)
|
||||
form.set('dec', lat)
|
||||
form.set('rad', fov)
|
||||
@@ -241,7 +227,7 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
|
||||
let form = new Form({
|
||||
submit: {
|
||||
disable: true,
|
||||
disabled: true,
|
||||
icon: {
|
||||
monochrome: true,
|
||||
url: targetIconUrl,
|
||||
@@ -344,20 +330,25 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
classList: ['aladin-cat-browser-box'],
|
||||
content: Layout.vertical(
|
||||
[
|
||||
Layout.horizontal({
|
||||
layout: ["Search:", inputText], cssStyle: {width: '100%'}
|
||||
}),
|
||||
Layout.horizontal({
|
||||
layout: ["Progressive catalog:", hipsCatLoad],
|
||||
cssStyle: {
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
listStyle: "none",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
},
|
||||
}),
|
||||
Layout.horizontal(
|
||||
["Search:", searchDropdown],
|
||||
{cssStyle:
|
||||
{width: '100%'}
|
||||
}
|
||||
),
|
||||
Layout.horizontal(
|
||||
["Progressive catalog:", hipsCatLoad],
|
||||
{
|
||||
cssStyle: {
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
listStyle: "none",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
},
|
||||
}
|
||||
),
|
||||
form
|
||||
]
|
||||
),
|
||||
@@ -367,7 +358,7 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
self = this;
|
||||
this.hipsCatLoad = hipsCatLoad;
|
||||
this.csForm = form;
|
||||
this.inputText = inputText;
|
||||
this.searchDropdown = searchDropdown;
|
||||
this.fnIdSelected = fnIdSelected;
|
||||
}
|
||||
|
||||
@@ -375,15 +366,15 @@ import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
this.selectedItem = item;
|
||||
|
||||
if (!item) {
|
||||
this.csForm.submit.update({disable: true})
|
||||
this.hipsCatLoad.update({disable: true});
|
||||
this.csForm.submit.update({disabled: true})
|
||||
this.hipsCatLoad.update({disabled: true});
|
||||
} else {
|
||||
if (item && item.cs_service_url) {
|
||||
this.csForm.submit.update({disable: false});
|
||||
this.csForm.submit.update({disabled: false});
|
||||
}
|
||||
|
||||
if (item && item.hips_service_url) {
|
||||
this.hipsCatLoad.update({disable: false});
|
||||
this.hipsCatLoad.update({disabled: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,20 +36,6 @@ import { SearchTextInput } from "../Input/InputTextSearch.js";
|
||||
export class GotoBox extends Box {
|
||||
// Constructor
|
||||
constructor(aladin) {
|
||||
/*let content = Layout.horizontal([
|
||||
'Go to:',
|
||||
Input.text({
|
||||
//tooltip: {content: 'Search for a VizieR catalogue', position: {direction :'bottom'}},
|
||||
label: "Go to:",
|
||||
name: "goto",
|
||||
type: "text",
|
||||
placeholder: 'Object name/position',
|
||||
autocomplete: 'off',
|
||||
change(e, self) {
|
||||
self.addEventListener('blur', (event) => {});
|
||||
}
|
||||
})
|
||||
]);*/
|
||||
let textField = new SearchTextInput(aladin, {
|
||||
cssStyle: {
|
||||
width: '15rem'
|
||||
|
||||
@@ -41,6 +41,7 @@ import labelSizeIcon from './../../../../assets/icons/font-size.svg';
|
||||
export class GridBox extends Box {
|
||||
// Constructor
|
||||
constructor(aladin) {
|
||||
let self;
|
||||
let colorInput = new Input({
|
||||
layout: {
|
||||
name: 'gridColor',
|
||||
@@ -98,7 +99,7 @@ export class GridBox extends Box {
|
||||
})
|
||||
}
|
||||
|
||||
ctxMenu.attach(ctxMenuLayout);
|
||||
ctxMenu.attach(ctxMenuLayout, self);
|
||||
ctxMenu.show({
|
||||
e: e,
|
||||
position: {
|
||||
@@ -134,7 +135,7 @@ export class GridBox extends Box {
|
||||
})
|
||||
}
|
||||
|
||||
ctxMenu.attach(ctxMenuLayout);
|
||||
ctxMenu.attach(ctxMenuLayout, self);
|
||||
ctxMenu.show({
|
||||
e: e,
|
||||
position: {
|
||||
@@ -154,15 +155,13 @@ export class GridBox extends Box {
|
||||
}
|
||||
});
|
||||
sliderOpacity.addClass("aladin-input-range")
|
||||
const layout = Layout.horizontal({
|
||||
layout: [
|
||||
enableCheckbox,
|
||||
labelSizeBtn,
|
||||
thicknessLineBtn,
|
||||
colorInput,
|
||||
sliderOpacity
|
||||
]
|
||||
})
|
||||
const layout = Layout.horizontal([
|
||||
enableCheckbox,
|
||||
labelSizeBtn,
|
||||
thicknessLineBtn,
|
||||
colorInput,
|
||||
sliderOpacity
|
||||
])
|
||||
|
||||
layout.addClass('aladin-grid-frame');
|
||||
|
||||
@@ -182,6 +181,7 @@ export class GridBox extends Box {
|
||||
this.addClass("aladin-box-night")
|
||||
|
||||
this.aladin = aladin;
|
||||
self = this;
|
||||
|
||||
this._hide();
|
||||
}
|
||||
|
||||
@@ -22,16 +22,17 @@ import { MocServer } from "../../MocServer.js";
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { Dropdown } from "../Input/Dropdown.js";
|
||||
import filterOnUrl from "../../../../assets/icons/filter-on.svg";
|
||||
import hipsIconUrl from "../../../../assets/icons/hips.svg";
|
||||
import treeIconUrl from "../../../../assets/icons/tree.svg";
|
||||
import filterOffUrl from "../../../../assets/icons/filter-off.svg";
|
||||
import helpIconUrl from "../../../../assets/icons/help.svg";
|
||||
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
import { WidgetTogglerButton } from "../Button/Toggler.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
import { HiPSFilterBox } from "./HiPSFilterBox.js";
|
||||
import A from "../../A.js";
|
||||
import { Utils } from "../../Utils.ts";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import infoIconUrl from "../../../../assets/icons/info.svg"
|
||||
import { Icon } from "../Widgets/Icon.js";
|
||||
import { Tree } from "../Widgets/Tree.js";
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
@@ -47,6 +48,10 @@ import { ALEvent } from "../../events/ALEvent.js";
|
||||
*****************************************************************************/
|
||||
|
||||
function fillHiPSHierarchy(name, hips, path, hierarchy) {
|
||||
if (path[path.length - 1] === '/') {
|
||||
path = path.substring(0, path.length - 1);
|
||||
}
|
||||
|
||||
let folders = path.split('/')
|
||||
let curFolder = folders.shift()
|
||||
|
||||
@@ -105,10 +110,13 @@ export class HiPSBrowserBox extends Box {
|
||||
}
|
||||
|
||||
if (params.title) {
|
||||
if (!item.obs_title)
|
||||
if (!item.obs_title && !item.ID)
|
||||
return false;
|
||||
|
||||
if (!item.obs_title.toLowerCase().includes(params.title.toLowerCase())) {
|
||||
let obsTitleDoesNotMatch = !item.obs_title.toLowerCase().includes(params.title.toLowerCase());
|
||||
let creatorDidDoesNotMatch = !item.ID.toLowerCase().includes(params.title.toLowerCase());
|
||||
|
||||
if (obsTitleDoesNotMatch && creatorDidDoesNotMatch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -129,8 +137,16 @@ export class HiPSBrowserBox extends Box {
|
||||
let name = item.obs_title || item.ID;
|
||||
self._addHiPS(image, name)
|
||||
},
|
||||
dblclick: (item) => {
|
||||
let image = item.ID || item.hips_service_url;
|
||||
let name = item.obs_title || item.ID;
|
||||
self._addHiPS(image, name)
|
||||
|
||||
self.close();
|
||||
},
|
||||
// a callback called for filtering
|
||||
filter,
|
||||
aladin,
|
||||
});
|
||||
|
||||
MocServer.getAllHiPSes().then((HiPSes) => {
|
||||
@@ -140,19 +156,28 @@ export class HiPSBrowserBox extends Box {
|
||||
// Fill the HiPSList from the MOCServer
|
||||
|
||||
// Build a hierarchy w.r.t sorted by regime
|
||||
let HiPSIDs = []
|
||||
HiPSes.forEach((h) => {
|
||||
let name = h.obs_title;
|
||||
name = name.replace(/:|\'/g, '');
|
||||
HiPSIDs.push(name)
|
||||
|
||||
HiPSBrowserBox.HiPSList[name] = h;
|
||||
|
||||
if (h.client_category) {
|
||||
let path = h.client_category
|
||||
|
||||
fillHiPSHierarchy(name, h, path, hipsHierarchy)
|
||||
} else {
|
||||
let hipsID = h.ID;
|
||||
hipsID = hipsID.replace('/P', '');
|
||||
|
||||
let path = "Others/" + hipsID;
|
||||
fillHiPSHierarchy(name, h, path, hipsHierarchy)
|
||||
}
|
||||
});
|
||||
|
||||
self.searchDropdown.update({ options: HiPSIDs });
|
||||
self.searchTree.setHierarchy(hipsHierarchy)
|
||||
|
||||
// Initialize the autocompletion without any filtering
|
||||
@@ -191,37 +216,24 @@ export class HiPSBrowserBox extends Box {
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin,
|
||||
content: 'HiPS url, ID or keyword accepted',
|
||||
content: 'HiPS url, ID or keyword accepted.',
|
||||
},
|
||||
actions: {
|
||||
focus(e) {
|
||||
searchDropdown.removeClass('aladin-valid')
|
||||
searchDropdown.removeClass('aladin-not-valid')
|
||||
},
|
||||
keydown(e) {
|
||||
e.stopPropagation();
|
||||
action: (e) => {
|
||||
_parseHiPS(e)
|
||||
},
|
||||
input: (e) => {
|
||||
let value = e.target.value;
|
||||
self.searchTree.triggerFilter({title: value});
|
||||
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault()
|
||||
_parseHiPS(e)
|
||||
}
|
||||
},
|
||||
input(e) {
|
||||
self.infoCurrentHiPSBtn.update({
|
||||
disable: true,
|
||||
})
|
||||
|
||||
self.searchTree.triggerFilter({title: e.target.value});
|
||||
|
||||
searchDropdown.removeClass('aladin-valid')
|
||||
searchDropdown.removeClass('aladin-not-valid')
|
||||
},
|
||||
self.infoCurrentHiPSBtn.update({
|
||||
disabled: true,
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
let filterEnabler = Input.checkbox({
|
||||
name: "filter-enabler",
|
||||
tooltip: { content: "enable/disable" },
|
||||
tooltip: { content: "Enable the filter" },
|
||||
checked: false,
|
||||
click(e) {
|
||||
let on = e.target.checked;
|
||||
@@ -247,21 +259,15 @@ export class HiPSBrowserBox extends Box {
|
||||
},
|
||||
});
|
||||
|
||||
let infoCurrentHiPSBtn = new ActionButton({
|
||||
disable: true,
|
||||
icon: {
|
||||
size: 'medium',
|
||||
monochrome: true,
|
||||
url: infoIconUrl,
|
||||
},
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin,
|
||||
content: "More about that survey?"
|
||||
}
|
||||
});
|
||||
let infoCurrentHiPSBtn = ActionButton.BUTTONS(aladin)
|
||||
.infoHiPS({disabled: true})
|
||||
|
||||
let filterBtn = new TogglerActionButton({
|
||||
let filterBox = new HiPSFilterBox(aladin, {
|
||||
callback: (params) => {
|
||||
self._filterHiPSList(params);
|
||||
},
|
||||
})
|
||||
let filterBtn = new WidgetTogglerButton({
|
||||
icon: {
|
||||
url: filterOffUrl,
|
||||
monochrome: true,
|
||||
@@ -272,40 +278,50 @@ export class HiPSBrowserBox extends Box {
|
||||
position: { direction: "top" },
|
||||
},
|
||||
toggled: false,
|
||||
actionOn: (e) => {
|
||||
self.filterBox._show({position: {
|
||||
anchor: 'right center'
|
||||
}});
|
||||
},
|
||||
actionOff: (e) => {
|
||||
self.filterBox._hide();
|
||||
},
|
||||
openPosition: 'right center',
|
||||
widget: filterBox,
|
||||
});
|
||||
|
||||
let filterNumberElt = document.createElement("div");
|
||||
|
||||
super(
|
||||
{
|
||||
super({
|
||||
close: true,
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin,
|
||||
content: 'orange: out of the view, green: in view'
|
||||
},
|
||||
header: {
|
||||
title: Layout.horizontal([new Icon({
|
||||
size: 'medium',
|
||||
url: hipsIconUrl,
|
||||
monochrome: true,
|
||||
}), "HiPS browser"]),
|
||||
title: [
|
||||
new Icon({
|
||||
size: 'medium',
|
||||
url: treeIconUrl,
|
||||
monochrome: true,
|
||||
}),
|
||||
"HiPS browser",
|
||||
new Icon({
|
||||
size: 'medium',
|
||||
url: helpIconUrl,
|
||||
monochrome: true,
|
||||
tooltip: {
|
||||
content: 'HiPS:<br/><span class="aladin-indicator aladin-not-found"></span> out of the view<br /><span class="aladin-indicator aladin-valid"></span> in view',
|
||||
mouse: true,
|
||||
aladin
|
||||
},
|
||||
style: {
|
||||
cursor: 'help'
|
||||
}
|
||||
}),
|
||||
],
|
||||
draggable: true,
|
||||
},
|
||||
//onDragged: () => {
|
||||
//if (self.filterBtn.toggled) {
|
||||
//self.filterBtn.toggle();
|
||||
//}
|
||||
//},
|
||||
sizeable: true,
|
||||
classList: ['aladin-HiPS-browser-box'],
|
||||
content: Layout.vertical([
|
||||
content: [
|
||||
searchTree,
|
||||
Layout.horizontal(["Search:", searchDropdown, infoCurrentHiPSBtn]),
|
||||
Layout.horizontal(["Filter:", Layout.horizontal([filterEnabler, filterBtn, filterNumberElt])]),
|
||||
]),
|
||||
["Search:", searchDropdown, infoCurrentHiPSBtn],
|
||||
[filterEnabler, filterBtn, filterNumberElt],
|
||||
],
|
||||
...options,
|
||||
},
|
||||
aladin.aladinDiv
|
||||
@@ -314,11 +330,7 @@ export class HiPSBrowserBox extends Box {
|
||||
self = this;
|
||||
|
||||
this.searchTree = searchTree;
|
||||
this.filterBox = new HiPSFilterBox(aladin, {
|
||||
callback: (params) => {
|
||||
self._filterHiPSList(params);
|
||||
},
|
||||
})
|
||||
this.filterBox = filterBox;
|
||||
this.filterNumberElt = filterNumberElt;
|
||||
this.filterBox._hide();
|
||||
|
||||
@@ -371,7 +383,7 @@ export class HiPSBrowserBox extends Box {
|
||||
self.searchDropdown.addClass('aladin-valid');
|
||||
|
||||
self.infoCurrentHiPSBtn.update({
|
||||
disable: false,
|
||||
disabled: false,
|
||||
action(e) {
|
||||
window.open(hips.url);
|
||||
}
|
||||
@@ -477,14 +489,15 @@ export class HiPSBrowserBox extends Box {
|
||||
self.searchDropdown.addClass('aladin-not-valid');
|
||||
}
|
||||
});
|
||||
this.aladin.setOverlayImageLayer(hips, self.layer);
|
||||
|
||||
self.selected(hips)
|
||||
}
|
||||
|
||||
// This method is executed only if the filter is enabled
|
||||
_filterHiPSList(params) {
|
||||
let self = this;
|
||||
let HiPSIDs = [];
|
||||
|
||||
let numHiPSMatching = 0;
|
||||
for (var key in HiPSBrowserBox.HiPSList) {
|
||||
let HiPS = HiPSBrowserBox.HiPSList[key];
|
||||
// apply filtering
|
||||
@@ -496,7 +509,7 @@ export class HiPSBrowserBox extends Box {
|
||||
let name = HiPS.obs_title;
|
||||
name = name.replace(/:|\'/g, "");
|
||||
|
||||
HiPSIDs.push(name);
|
||||
numHiPSMatching += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,8 +517,7 @@ export class HiPSBrowserBox extends Box {
|
||||
self.searchTree.triggerFilter(params);
|
||||
}
|
||||
|
||||
self.searchDropdown.update({ options: HiPSIDs });
|
||||
self.filterNumberElt.innerHTML = HiPSIDs.length + "/" + Object.keys(HiPSBrowserBox.HiPSList).length;
|
||||
self.filterNumberElt.innerHTML = numHiPSMatching + "/" + Object.keys(HiPSBrowserBox.HiPSList).length;
|
||||
}
|
||||
|
||||
_hide() {
|
||||
@@ -517,10 +529,11 @@ export class HiPSBrowserBox extends Box {
|
||||
}
|
||||
|
||||
_show(options) {
|
||||
this._requestMOCServer();
|
||||
|
||||
// Regenerate a new layer name
|
||||
this.layer = (options && options.layer) || Utils.uuidv4();
|
||||
this.selected = options && options.selected;
|
||||
|
||||
super._show(options)
|
||||
|
||||
this._requestMOCServer();
|
||||
}
|
||||
}
|
||||
|
||||
267
src/js/gui/Box/HiPSCompositeBox.js
Normal file
267
src/js/gui/Box/HiPSCompositeBox.js
Normal file
@@ -0,0 +1,267 @@
|
||||
// Copyright 2013 - UDS/CNRS
|
||||
// The Aladin Lite program is distributed under the terms
|
||||
// of the GNU General Public License version 3.
|
||||
//
|
||||
// This file is part of Aladin Lite.
|
||||
//
|
||||
// Aladin Lite is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Aladin Lite is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// The GNU General Public License is available in COPYING file
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import hipsIconUrl from "../../../../assets/icons/hips.svg";
|
||||
import addIconUrl from "../../../../assets/icons/plus.svg";
|
||||
import settingsIconUrl from "../../../../assets/icons/settings.svg";
|
||||
import { Icon } from "../Widgets/Icon.js";
|
||||
import { HiPSSelector } from "../Input/HiPSSelector.js";
|
||||
import { HiPSBrowserBox } from "./HiPSBrowserBox.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import { Form } from "../Widgets/Form.js";
|
||||
import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
import { Utils } from "../../Utils";
|
||||
import { HiPSComposite } from "../../HiPSComposite.js";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/Box/HiPSCompositeBox.js
|
||||
*
|
||||
* The code source of the interface for creating a new composite HiPS survey from multiple surveys
|
||||
*
|
||||
* Author: Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
export class HiPSCompositeBox extends Box {
|
||||
static HiPSList = {};
|
||||
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
|
||||
let nameInput = Input.text({
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin,
|
||||
content: 'What name for your composite survey?'
|
||||
},
|
||||
placeholder: "What name?...",
|
||||
autocomplete: 'off',
|
||||
autofocus: true,
|
||||
actions: {
|
||||
dblclick: (_) => {
|
||||
nameInput.set('')
|
||||
},
|
||||
keydown: (e) => {
|
||||
e.stopPropagation();
|
||||
//
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let content = [[
|
||||
new ActionButton({
|
||||
icon: {
|
||||
url: addIconUrl,
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {
|
||||
content: "Add a new layer",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
toggled: false,
|
||||
action(_) {
|
||||
self.content.push(self._addNewHiPS());
|
||||
self.update({content: self.content})
|
||||
}
|
||||
}),
|
||||
nameInput
|
||||
]];
|
||||
|
||||
super(
|
||||
{
|
||||
close: true,
|
||||
header: {
|
||||
title: [
|
||||
new Icon({
|
||||
size: 'medium',
|
||||
url: hipsIconUrl,
|
||||
monochrome: true,
|
||||
}),
|
||||
"HiPS Compositor"
|
||||
],
|
||||
draggable: true,
|
||||
},
|
||||
content,
|
||||
...options,
|
||||
},
|
||||
aladin.aladinDiv
|
||||
);
|
||||
|
||||
this.aladin = aladin;
|
||||
|
||||
this.hipsOptions = [];
|
||||
self = this;
|
||||
|
||||
this.layer = Utils.uuidv4();
|
||||
this.hipsComposite = new HiPSComposite(this.hipsOptions)
|
||||
|
||||
this.numHiPSLayers = 0;
|
||||
this.content = content.concat([this._addNewHiPS()])
|
||||
this.update({content: this.content})
|
||||
|
||||
this.openSettings = null;
|
||||
}
|
||||
|
||||
_addNewHiPS() {
|
||||
const getIdHiPS = (node) => {
|
||||
let parent = node.parentElement;
|
||||
return [...parent.parentElement.children].indexOf(parent) - 1;
|
||||
};
|
||||
this.hipsOptions.push({});
|
||||
let self = this;
|
||||
let newLayerLayout = [
|
||||
new HiPSSelector({
|
||||
change(e) {
|
||||
let name = e.target.value;
|
||||
let idLayer = getIdHiPS(e.target);
|
||||
|
||||
if (name === "More...") {
|
||||
if (!aladin.hipsBrowser) {
|
||||
aladin.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
}
|
||||
|
||||
aladin.hipsBrowser._show({
|
||||
selected: (hips) => {
|
||||
self.hipsOptions[idLayer].id = hips.id || hips.url
|
||||
},
|
||||
position: { anchor: "center center" }
|
||||
});
|
||||
} else {
|
||||
// it is an hips
|
||||
let HiPSOptions = HiPSSelector.cachedHiPS[name];
|
||||
self.hipsOptions[idLayer].id = HiPSOptions.id || HiPSOptions.url
|
||||
}
|
||||
|
||||
self.hipsComposite.setOptions(self.hipsOptions);
|
||||
self.aladin.setOverlayImageLayer(self.hipsComposite, self.layer);
|
||||
}
|
||||
}),
|
||||
this._createLayerSettingsBox(),
|
||||
ActionButton.BUTTONS(aladin)
|
||||
.remove((e) => {
|
||||
let node = e.target.parentElement.parentElement.parentElement;
|
||||
let idLayer = [...node.parentElement.children].indexOf(node);
|
||||
|
||||
this.content.splice(idLayer, 1)
|
||||
this.hipsOptions.splice(idLayer, 1);
|
||||
|
||||
this.update({content: this.content})
|
||||
this.numHiPSLayers = this.content.length - 1;
|
||||
})
|
||||
];
|
||||
this.numHiPSLayers += 1;
|
||||
|
||||
return newLayerLayout;
|
||||
}
|
||||
|
||||
_createLayerSettingsBox() {
|
||||
let self = this;
|
||||
let layerSettingsBox = new Box({
|
||||
close: false,
|
||||
content: new Form({
|
||||
subInputs: [
|
||||
{
|
||||
type: 'color',
|
||||
label: "Color",
|
||||
value: 'red',
|
||||
name: 'color',
|
||||
change(e) {
|
||||
let idLayer = getIdHiPS(e.target);
|
||||
|
||||
let hex = e.target.value;
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Stretch',
|
||||
type: "select",
|
||||
name: 'stretch',
|
||||
value: 'linear',
|
||||
options: ['sqrt', 'linear', 'asinh', 'pow2', 'log'],
|
||||
change(e) {},
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
label: "Min cut",
|
||||
name: 'mincut',
|
||||
value: 0.0,
|
||||
change: (e) => {
|
||||
let minCut = +e.target.value
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Max cut',
|
||||
type: "number",
|
||||
name: 'maxcut',
|
||||
value: 0.0,
|
||||
change: (e) => {
|
||||
let maxCut = +e.target.value
|
||||
}
|
||||
},
|
||||
]
|
||||
}),
|
||||
}, this.aladin.aladinDiv);
|
||||
layerSettingsBox._hide()
|
||||
|
||||
/*let layerSettingsBtn = new TogglerActionButton({
|
||||
icon: { url: settingsIconUrl, monochrome: true },
|
||||
size: "small",
|
||||
tooltip: {
|
||||
content: "Settings",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
toggled: false,
|
||||
on: (_) => {
|
||||
layerSettingsBox._show({
|
||||
position: {
|
||||
nextTo: layerSettingsBtn,
|
||||
direction: "right",
|
||||
aladin: self.aladin,
|
||||
},
|
||||
});
|
||||
|
||||
if (self.openSettings) {
|
||||
self.openSettings.close();
|
||||
}
|
||||
|
||||
self.openSettings = layerSettingsBtn;
|
||||
},
|
||||
off: (_) => {
|
||||
layerSettingsBox._hide();
|
||||
if (self.openSettings === layerSettingsBtn) {
|
||||
self.openSettings = null;
|
||||
}
|
||||
},
|
||||
});*/
|
||||
|
||||
return layerSettingsBtn
|
||||
}
|
||||
|
||||
_hide() {
|
||||
if (this.openSettings)
|
||||
this.openSettings.close();
|
||||
|
||||
super._hide()
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,12 @@
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
import filterOnUrl from "../../../../assets/icons/filter-on.svg";
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { Form } from "../Widgets/Form.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
import { Angle } from "../../libs/astro/angle.js";
|
||||
import { AladinUtils } from "../../AladinUtils.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
|
||||
import { Icon } from "../Widgets/Icon.js";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
@@ -41,7 +40,7 @@ export class HiPSFilterBox extends Box {
|
||||
|
||||
let regimeBtn = Input.checkbox({
|
||||
name: 'Freq',
|
||||
tooltip: {content: 'Observation bandwidth', position: {direction: 'left'}},
|
||||
tooltip: {content: 'enable/disable', position: {direction: 'left'}},
|
||||
type: 'checkbox',
|
||||
checked: false,
|
||||
click(e) {
|
||||
@@ -50,7 +49,7 @@ export class HiPSFilterBox extends Box {
|
||||
});
|
||||
let resolutionBtn = Input.checkbox({
|
||||
name: 'Resolution',
|
||||
tooltip: {content: 'Check for HiPS with a specific pixel resolution.', position: {direction: 'left'}},
|
||||
tooltip: {content: 'enable/disable', position: {direction: 'left'}},
|
||||
type: 'checkbox',
|
||||
checked: false,
|
||||
click(e) {
|
||||
@@ -58,82 +57,80 @@ export class HiPSFilterBox extends Box {
|
||||
}
|
||||
});
|
||||
|
||||
let regimeOption = Layout.horizontal({
|
||||
tooltip: {
|
||||
content: "Observation regime",
|
||||
position: { direction: "right" },
|
||||
},
|
||||
label: 'Freq: ',
|
||||
layout: [Input.select({
|
||||
value: "Optical",
|
||||
options: [
|
||||
"Radio",
|
||||
"Infrared",
|
||||
"Millimeter",
|
||||
"Optical",
|
||||
"UV",
|
||||
"EUV",
|
||||
"X-ray",
|
||||
"Gamma-ray",
|
||||
],
|
||||
change: (e) => {
|
||||
let regime = e.target.value;
|
||||
self.params["regime"] = regime;
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
}), regimeBtn]
|
||||
});
|
||||
|
||||
let resolutionOption = Layout.horizontal({
|
||||
label: "Max resolution [°/px]:",
|
||||
layout: [
|
||||
new Input({
|
||||
name: "res",
|
||||
value: 0.1,
|
||||
type: 'range',
|
||||
cssStyle: {
|
||||
width: '200px'
|
||||
},
|
||||
tooltip: {content: AladinUtils.degreesToString(0.1), position: {direction: 'bottom'}},
|
||||
ticks: [0.1 / 3600, 1 / 3600, 1 / 60, 0.1],
|
||||
stretch: "log",
|
||||
min: 0.1 / 3600,
|
||||
max: 0.1,
|
||||
reversed: true,
|
||||
change: (e, slider, deg) => {
|
||||
slider.update({value: e.target.value, tooltip: {content: AladinUtils.degreesToString(deg), position:{direction:'bottom'}}});
|
||||
|
||||
let resolution = new Angle(deg);
|
||||
self.params["resolution"] = resolution.degrees();
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
}),
|
||||
resolutionBtn,
|
||||
]
|
||||
});
|
||||
super(
|
||||
{
|
||||
header: {
|
||||
title: 'Filter tags',
|
||||
title: [
|
||||
new Icon({
|
||||
size: 'medium',
|
||||
url: filterOnUrl,
|
||||
monochrome: true,
|
||||
}),
|
||||
'Filter'
|
||||
],
|
||||
draggable: false,
|
||||
},
|
||||
close: false,
|
||||
classList: ['aladin-HiPS-filter-box'],
|
||||
content: Layout.vertical([
|
||||
new Form({
|
||||
subInputs: [
|
||||
{
|
||||
type: "group",
|
||||
subInputs: [
|
||||
regimeOption,
|
||||
resolutionOption
|
||||
content: [
|
||||
{
|
||||
start: [
|
||||
"Freq:",
|
||||
Input.select({
|
||||
tooltip: {
|
||||
content: "Observation regime",
|
||||
position: { direction: "left" },
|
||||
},
|
||||
value: "Optical",
|
||||
options: [
|
||||
"Radio",
|
||||
"Infrared",
|
||||
"Millimeter",
|
||||
"Optical",
|
||||
"UV",
|
||||
"EUV",
|
||||
"X-ray",
|
||||
"Gamma-ray",
|
||||
],
|
||||
},
|
||||
change: (e) => {
|
||||
let regime = e.target.value;
|
||||
self.params["regime"] = regime;
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
end: [regimeBtn]
|
||||
},
|
||||
{
|
||||
start: [
|
||||
"Max resolution [°/px]:",
|
||||
new Input({
|
||||
name: "res",
|
||||
value: 0.1,
|
||||
type: 'range',
|
||||
cssStyle: {
|
||||
width: '200px'
|
||||
},
|
||||
tooltip: {content: AladinUtils.degreesToString(0.1), position: {direction: 'bottom'}},
|
||||
ticks: [0.001 / 3600, 0.01 / 3600, 0.1 / 3600, 1 / 3600, 1 / 60, 0.1],
|
||||
stretch: "log",
|
||||
min: 0.001 / 3600,
|
||||
max: 0.1,
|
||||
reversed: true,
|
||||
change: (e, slider, deg) => {
|
||||
slider.update({value: e.target.value, tooltip: {content: AladinUtils.degreesToString(deg), position:{direction:'bottom'}}});
|
||||
|
||||
let resolution = new Angle(deg);
|
||||
self.params["resolution"] = resolution.degrees();
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
})
|
||||
],
|
||||
end: [resolutionBtn]
|
||||
}
|
||||
]
|
||||
},
|
||||
aladin.aladinDiv
|
||||
);
|
||||
@@ -170,15 +167,6 @@ export class HiPSFilterBox extends Box {
|
||||
}
|
||||
}
|
||||
|
||||
/*signalBrowserStatus(closed) {
|
||||
this.browserClosed = closed;
|
||||
|
||||
// open
|
||||
if (!closed) {
|
||||
this._requestMOCServer()
|
||||
}
|
||||
}*/
|
||||
|
||||
enable(enable) {
|
||||
this.on = enable;
|
||||
|
||||
|
||||
@@ -1,172 +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.
|
||||
//
|
||||
|
||||
import { MocServer } from "../../MocServer.js";
|
||||
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/HiPSSelector.js
|
||||
*
|
||||
*
|
||||
* Author: Thomas Boch, Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
export class HiPSSelectorBox extends Box {
|
||||
static HiPSList = {};
|
||||
|
||||
constructor(aladin, options) {
|
||||
MocServer.getAllHiPSes()
|
||||
.then((HiPSes) => {
|
||||
HiPSes.forEach((h) => {
|
||||
HiPSSelectorBox.HiPSList[h.obs_title] = h
|
||||
HiPSSelectorBox.HiPSList[h.ID] = h
|
||||
|
||||
});
|
||||
|
||||
inputText.update({autocomplete: {options: Object.keys(HiPSSelectorBox.HiPSList)}})
|
||||
});
|
||||
|
||||
let self;
|
||||
let loadBtn = new ActionButton({
|
||||
content: 'Add',
|
||||
disable: true,
|
||||
action(e) {
|
||||
self.callback && self.callback(inputText.get());
|
||||
// reset the field
|
||||
inputText.set('');
|
||||
|
||||
self._hide();
|
||||
}
|
||||
})
|
||||
|
||||
let inputText = Input.text({
|
||||
classList: ['search'],
|
||||
name: 'survey',
|
||||
placeholder: "Type survey keywords",
|
||||
actions: {
|
||||
change() {
|
||||
const HiPS = HiPSSelectorBox.HiPSList[this.value];
|
||||
inputText.set(HiPS.ID);
|
||||
loadBtn.update({disable: false});
|
||||
},
|
||||
keydown() {
|
||||
loadBtn.update({disable: true});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
super(
|
||||
{
|
||||
close: false,
|
||||
content: Layout.horizontal({
|
||||
layout: [
|
||||
inputText,
|
||||
loadBtn
|
||||
]
|
||||
}),
|
||||
...options
|
||||
},
|
||||
aladin.aladinDiv
|
||||
)
|
||||
|
||||
self = this;
|
||||
// Query the mocserver
|
||||
/*MocServer.getAllHiPSes();
|
||||
|
||||
autocomplete({
|
||||
input: inputText.element(),
|
||||
fetch: function(text, update) {
|
||||
text = text.toLowerCase();
|
||||
// filter suggestions
|
||||
const suggestions = MocServer.getAllHiPSes().filter(n => n.ID.toLowerCase().includes(text) || n.obs_title.toLowerCase().includes(text))
|
||||
|
||||
// sort suggestions
|
||||
suggestions.sort( function(a , b) {
|
||||
let scoreForA = 0;
|
||||
let scoreForB = 0;
|
||||
|
||||
if (a.ID.toLowerCase().includes(text)) {
|
||||
scoreForA += 100;
|
||||
}
|
||||
if (b.ID.toLowerCase().includes(text)) {
|
||||
scoreForB += 100;
|
||||
}
|
||||
|
||||
if (a.obs_title.toLowerCase().includes(text)) {
|
||||
scoreForA += 50;
|
||||
}
|
||||
if (b.obs_title.toLowerCase().includes(text)) {
|
||||
scoreForB += 50;
|
||||
}
|
||||
|
||||
if (a.obs_description && a.obs_description.toLowerCase().includes(text)) {
|
||||
scoreForA += 10;
|
||||
}
|
||||
if (b.obs_description && b.obs_description.toLowerCase().includes(text)) {
|
||||
scoreForB += 10;
|
||||
}
|
||||
|
||||
if (scoreForA > scoreForB) {
|
||||
return -1;
|
||||
}
|
||||
if (scoreForB > scoreForA) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
// limit to 50 first suggestions
|
||||
const returnedSuggestions = suggestions.slice(0, 50);
|
||||
|
||||
update(returnedSuggestions);
|
||||
},
|
||||
onSelect: function(item) {
|
||||
inputText.set(item.ID);
|
||||
loadBtn.update({disable: false});
|
||||
|
||||
inputText.element().blur();
|
||||
},
|
||||
// attach container to AL div if needed (to prevent it from being hidden in full screen mode)
|
||||
customize: function(input, inputRect, container, maxHeight) {
|
||||
// this tests if we are in full screen mode
|
||||
if (aladin.isInFullscreen) {
|
||||
aladin.aladinDiv.appendChild(container);
|
||||
}
|
||||
},
|
||||
render: function(item, currentValue) {
|
||||
const itemElement = document.createElement("div");
|
||||
itemElement.innerHTML = item.obs_title + ' - ' + '<span style="color: #ae8de1">' + item.ID + '</span>';
|
||||
|
||||
|
||||
return itemElement;
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
attach(callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import { Form } from "../Widgets/Form.js";
|
||||
import pixelHistIconUrl from '../../../../assets/icons/pixel_histogram.svg';
|
||||
import { RadioButton } from "../Widgets/Radio.js";
|
||||
import waveOnIconUrl from '../../../../assets/icons/wave-on.svg';
|
||||
import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
import { WidgetTogglerButton } from "../Button/Toggler.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
|
||||
export class HiPSSettingsBox extends Box {
|
||||
@@ -53,9 +53,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
},
|
||||
tooltip: {content: 'Contrast', position: {direction: 'bottom'}},
|
||||
action: (e) => {
|
||||
const content = Layout.vertical({
|
||||
layout: [Layout.horizontal([self.selector, self.spectraBtn]), self.luminositySettingsContent]
|
||||
});
|
||||
const content = Layout.vertical([[self.selector, self.spectraBtn], self.luminositySettingsContent]);
|
||||
self.update({content})
|
||||
}
|
||||
},
|
||||
@@ -67,7 +65,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
},
|
||||
tooltip: {content: 'Opacity', position: {direction: 'bottom'}},
|
||||
action: (e) => {
|
||||
const content = Layout.vertical({layout: [Layout.horizontal([self.selector, self.spectraBtn]), self.opacitySettingsContent]});
|
||||
const content = Layout.vertical([[self.selector, self.spectraBtn], self.opacitySettingsContent]);
|
||||
self.update({content})
|
||||
}
|
||||
},
|
||||
@@ -78,7 +76,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
},
|
||||
tooltip: {content: 'Colormap', position: {direction: 'bottom'}},
|
||||
action: (e) => {
|
||||
const content = Layout.vertical({layout: [Layout.horizontal([self.selector, self.spectraBtn]), self.colorSettingsContent]});
|
||||
const content = Layout.vertical([[self.selector, self.spectraBtn], self.colorSettingsContent]);
|
||||
self.update({content})
|
||||
}
|
||||
},
|
||||
@@ -90,7 +88,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
},
|
||||
tooltip: {content: 'Cutouts', position: {direction: 'bottom'}},
|
||||
action: (e) => {
|
||||
const content = Layout.vertical({layout: [Layout.horizontal([self.selector, self.spectraBtn]), self.pixelSettingsContent]});
|
||||
const content = Layout.vertical([[self.selector, self.spectraBtn], self.pixelSettingsContent]);
|
||||
self.update({content})
|
||||
}
|
||||
},
|
||||
@@ -211,30 +209,26 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
{
|
||||
label: 'min cut:',
|
||||
type: 'number',
|
||||
cssStyle: {
|
||||
width: '6rem',
|
||||
},
|
||||
tooltip: {content: 'Min cut', position: {direction: 'bottom'}},
|
||||
name: 'mincut',
|
||||
value: 0.0,
|
||||
change: (e) => {
|
||||
let minCut = +e.target.value
|
||||
self.options.layer.setCuts(minCut, self.options.layer.getColorCfg().getCuts()[1])
|
||||
}
|
||||
},
|
||||
cssStyle: { width: '7rem' }
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
label: 'max cut:',
|
||||
cssStyle: {
|
||||
width: '6rem',
|
||||
},
|
||||
tooltip: {content: 'Max cut', position: {direction: 'bottom'}},
|
||||
name: 'maxcut',
|
||||
value: 1.0,
|
||||
change: (e) => {
|
||||
let maxCut = +e.target.value
|
||||
self.options.layer.setCuts(self.options.layer.getColorCfg().getCuts()[0], maxCut)
|
||||
}
|
||||
},
|
||||
cssStyle: { width: '7rem' }
|
||||
}]
|
||||
});
|
||||
|
||||
@@ -325,7 +319,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
if (options.layer.isSpectralCube && options.layer.isSpectralCube()) {
|
||||
let spectraDisplayer = self.aladin.view.spectraDisplayer;
|
||||
|
||||
self.spectraBtn = new TogglerActionButton({
|
||||
self.spectraBtn = new WidgetTogglerButton({
|
||||
content: 'Spectra',
|
||||
icon: {
|
||||
size: 'small',
|
||||
@@ -334,16 +328,13 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
},
|
||||
tooltip: {content: 'Show/hide spectra', position: {direction: 'bottom'}},
|
||||
toggled: true,
|
||||
actionOn: () => {
|
||||
enable: (o) => {
|
||||
spectraDisplayer.attachHiPS3D(options.layer)
|
||||
spectraDisplayer.show()
|
||||
},
|
||||
actionOff: () => {
|
||||
spectraDisplayer.hide()
|
||||
}
|
||||
widget: spectraDisplayer
|
||||
});
|
||||
|
||||
self.update({content: Layout.vertical([Layout.horizontal([self.selector, self.spectraBtn]), self.opacitySettingsContent])})
|
||||
self.update({content: Layout.vertical([[self.selector, self.spectraBtn], self.opacitySettingsContent])})
|
||||
}
|
||||
|
||||
this._update(options.layer)
|
||||
@@ -353,9 +344,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
}
|
||||
|
||||
_addListeners() {
|
||||
let self = this;
|
||||
|
||||
ALEvent.HIPS_LAYER_CHANGED.listenedBy(this.aladin.aladinDiv, (e) => {
|
||||
ALEvent.LAYER_CHANGED.listenedBy(this.aladin.aladinDiv, (e) => {
|
||||
const hips = e.detail.layer;
|
||||
let selectedLayer = this.options.layer;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import { Utils } from "../../Utils";
|
||||
import { View } from "../../View.js";
|
||||
import { HiPSSettingsBox } from "./HiPSSettingsBox.js";
|
||||
import hipsIconUrl from "../../../../assets/icons/hips.svg";
|
||||
import treeIconUrl from "../../../../assets/icons/tree.svg";
|
||||
import showIconUrl from "../../../../assets/icons/show.svg";
|
||||
import addIconUrl from "../../../../assets/icons/plus.svg";
|
||||
import hideIconUrl from "../../../../assets/icons/hide.svg";
|
||||
@@ -44,13 +45,18 @@ import settingsIconUrl from "../../../../assets/icons/settings.svg";
|
||||
import searchIconImg from "../../../../assets/icons/search.svg";
|
||||
import downloadIconUrl from '../../../../assets/icons/download.svg';
|
||||
import swapIcon from '../../../../assets/icons/swap.svg'
|
||||
import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
import { WidgetTogglerButton } from "../Button/Toggler.js";
|
||||
import { Icon } from "../Widgets/Icon.js";
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { Image } from "../../Image.js";
|
||||
import { HiPSBrowserBox } from "./HiPSBrowserBox.js";
|
||||
import { HiPSCompositeBox } from "./HiPSCompositeBox.js"
|
||||
import { Catalog } from "../../Catalog.js";
|
||||
import { ProgressiveCat } from "../../ProgressiveCat.js";
|
||||
import { Form } from "../Widgets/Form.js";
|
||||
import { HiPSSelector } from "./../Input/HiPSSelector.js";
|
||||
import { HiPS } from "../../HiPS.js";
|
||||
|
||||
export class OverlayStackBox extends Box {
|
||||
/*static previewImagesUrl = {
|
||||
@@ -120,7 +126,7 @@ export class OverlayStackBox extends Box {
|
||||
},
|
||||
};
|
||||
// Constructor
|
||||
constructor(aladin, stackBtn) {
|
||||
constructor(aladin) {
|
||||
super(
|
||||
{
|
||||
close: true,
|
||||
@@ -132,18 +138,14 @@ export class OverlayStackBox extends Box {
|
||||
},
|
||||
aladin.aladinDiv
|
||||
);
|
||||
this.stackBtn = stackBtn;
|
||||
this.cachedHiPS = {};
|
||||
|
||||
this.aladin = aladin;
|
||||
|
||||
this.mode = "stack";
|
||||
|
||||
this._addListeners();
|
||||
|
||||
this.mocHiPSUrls = {};
|
||||
this.ui = {};
|
||||
|
||||
this.HiPSui = {};
|
||||
let self = this;
|
||||
// Add overlay button
|
||||
this.addOverlayBtn = new CtxMenuActionButtonOpener(
|
||||
@@ -153,6 +155,7 @@ export class OverlayStackBox extends Box {
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
openDirection: 'right',
|
||||
tooltip: {
|
||||
content: "A catalog, MOC or footprint",
|
||||
position: { direction: "top" },
|
||||
@@ -187,8 +190,6 @@ export class OverlayStackBox extends Box {
|
||||
o.stopPropagation();
|
||||
o.preventDefault();
|
||||
|
||||
//self._hide();
|
||||
|
||||
const simbadHiPS = A.catalogHiPS(
|
||||
OverlayStackBox.predefinedCats.simbad
|
||||
.url,
|
||||
@@ -204,8 +205,6 @@ export class OverlayStackBox extends Box {
|
||||
o.stopPropagation();
|
||||
o.preventDefault();
|
||||
|
||||
//self._hide();
|
||||
|
||||
const simbadHiPS = A.catalogHiPS(
|
||||
OverlayStackBox.predefinedCats.gaia.url,
|
||||
OverlayStackBox.predefinedCats.gaia
|
||||
@@ -487,6 +486,7 @@ export class OverlayStackBox extends Box {
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
openDirection: 'right',
|
||||
ctxMenu: [
|
||||
{
|
||||
label: {
|
||||
@@ -501,28 +501,12 @@ export class OverlayStackBox extends Box {
|
||||
cursor: "help",
|
||||
},
|
||||
},
|
||||
content: "Add new survey",
|
||||
content: "Add a new HiPS",
|
||||
},
|
||||
action: (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
/*self._hide();
|
||||
|
||||
self.hipsSelectorBox = new HiPSSelectorBox(self.aladin);
|
||||
// attach a callback
|
||||
self.hipsSelectorBox.attach(
|
||||
(HiPSId) => {
|
||||
let name = Utils.uuidv4()
|
||||
self.aladin.setOverlayImageLayer(HiPSId, name)
|
||||
|
||||
self.show();
|
||||
}
|
||||
);
|
||||
|
||||
self.hipsSelectorBox._show({
|
||||
position: self.position,
|
||||
});*/
|
||||
self.aladin.addNewImageLayer(
|
||||
'P/DSS2/color'
|
||||
);
|
||||
@@ -531,7 +515,7 @@ export class OverlayStackBox extends Box {
|
||||
{
|
||||
label: {
|
||||
icon: {
|
||||
url: hipsIconUrl,
|
||||
url: treeIconUrl,
|
||||
monochrome: true,
|
||||
tooltip: {
|
||||
content: "From our database...",
|
||||
@@ -547,10 +531,50 @@ export class OverlayStackBox extends Box {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
if (!self.hipsBrowser)
|
||||
self.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
if (!aladin.hipsBrowser)
|
||||
aladin.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
|
||||
self.hipsBrowser._show({position: {
|
||||
let newLayer = Utils.uuidv4();
|
||||
|
||||
aladin.hipsBrowser._show({
|
||||
selected: (hips) => {
|
||||
let oldHiPS = aladin.getOverlayImageLayer(newLayer);
|
||||
if (oldHiPS && hips.id === oldHiPS.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
aladin.setOverlayImageLayer(hips, newLayer);
|
||||
},
|
||||
position: {
|
||||
anchor: 'center center'
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
icon: {
|
||||
url: hipsIconUrl,
|
||||
monochrome: true,
|
||||
tooltip: {
|
||||
content: "Combine different surveys into a color one!",
|
||||
position: { direction: "right" },
|
||||
},
|
||||
cssStyle: {
|
||||
cursor: "help",
|
||||
},
|
||||
},
|
||||
content: "Add a composite HiPS",
|
||||
},
|
||||
disabled: true,
|
||||
action: (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
if (!self.hipsCompositeBox)
|
||||
self.hipsCompositeBox = new HiPSCompositeBox(aladin);
|
||||
|
||||
self.hipsCompositeBox._show({position: {
|
||||
anchor: 'center center'
|
||||
}});
|
||||
},
|
||||
@@ -582,8 +606,9 @@ export class OverlayStackBox extends Box {
|
||||
ContextMenu.webkitDir({
|
||||
label: "Load local HiPS",
|
||||
action(files) {
|
||||
let id = files[0].webkitRelativePath.split("/")[0];
|
||||
let name = id;
|
||||
// Give a different id at each loading.
|
||||
let id = Utils.uuidv4();
|
||||
let name = files[0].webkitRelativePath.split("/")[0];
|
||||
|
||||
let hips = self.aladin.createImageSurvey(
|
||||
id,
|
||||
@@ -646,36 +671,29 @@ export class OverlayStackBox extends Box {
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.GRAPHIC_OVERLAY_LAYER_CHANGED.listenedBy(
|
||||
ALEvent.LAYER_ADDED.listenedBy(
|
||||
this.aladin.aladinDiv,
|
||||
function (e) {
|
||||
updateOverlayList();
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.HIPS_LAYER_ADDED.listenedBy(
|
||||
this.aladin.aladinDiv,
|
||||
function (e) {
|
||||
updateOverlayList();
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.HIPS_LAYER_SWAP.listenedBy(this.aladin.aladinDiv, function (e) {
|
||||
ALEvent.LAYER_SWAPPED.listenedBy(this.aladin.aladinDiv, function (e) {
|
||||
updateOverlayList();
|
||||
});
|
||||
|
||||
ALEvent.HIPS_LAYER_REMOVED.listenedBy(
|
||||
ALEvent.LAYER_REMOVED.listenedBy(
|
||||
this.aladin.aladinDiv,
|
||||
function (e) {
|
||||
updateOverlayList();
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.HIPS_LAYER_CHANGED.listenedBy(
|
||||
ALEvent.LAYER_CHANGED.listenedBy(
|
||||
this.aladin.aladinDiv,
|
||||
function (e) {
|
||||
const hips = e.detail.layer;
|
||||
let ui = self.HiPSui[hips.layer];
|
||||
let ui = self.ui[hips.layer];
|
||||
|
||||
if (!ui) {
|
||||
return;
|
||||
@@ -702,83 +720,65 @@ export class OverlayStackBox extends Box {
|
||||
);
|
||||
|
||||
updateOverlayList();
|
||||
|
||||
// Add a listener for HiPS list changes
|
||||
ALEvent.FAVORITE_HIPS_LIST_UPDATED.listenedBy(document.body, (event) => {
|
||||
let favoritesHips = event.detail;
|
||||
|
||||
self.cachedHiPS = {};
|
||||
|
||||
for (var hips of favoritesHips) {
|
||||
let key = hips.name || hips.id || hips.url;
|
||||
self.cachedHiPS[key] = hips;
|
||||
}
|
||||
// Update the options of the selector
|
||||
const favorites = Object.keys(self.cachedHiPS);
|
||||
for (var key in self.HiPSui) {
|
||||
let hips = self.HiPSui[key];
|
||||
let currentHiPS = hips.HiPSSelector.options.value
|
||||
|
||||
let favoritesCopy = [...favorites];
|
||||
|
||||
// add the current hips to the selector as well, even if it has been manually
|
||||
// removed from the HiPSList
|
||||
if (favoritesCopy.indexOf(currentHiPS) < 0) {
|
||||
favoritesCopy.push(currentHiPS)
|
||||
}
|
||||
|
||||
// one must add the current HiPS too!
|
||||
favoritesCopy.sort();
|
||||
|
||||
favoritesCopy.push("More...")
|
||||
|
||||
hips.HiPSSelector.update({value: currentHiPS, options: favoritesCopy});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_hide() {
|
||||
for (var key in this.HiPSui) {
|
||||
let hips = this.HiPSui[key];
|
||||
if (hips.settingsBtn.toggled) {
|
||||
for (var key in this.ui) {
|
||||
let ui = this.ui[key];
|
||||
if (ui.settingsBtn && ui.settingsBtn.toggled) {
|
||||
// toggle off
|
||||
hips.settingsBtn.toggle();
|
||||
ui.settingsBtn.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.addOverlayBtn) this.addOverlayBtn.hideMenu();
|
||||
if (this.addOverlayBtn) this.addOverlayBtn.close();
|
||||
|
||||
if (this.addHiPSBtn) this.addHiPSBtn.hideMenu();
|
||||
|
||||
// toggle the button because the window is closed
|
||||
this.stackBtn.update({toggled: false});
|
||||
if (this.addHiPSBtn) this.addHiPSBtn.close();
|
||||
|
||||
super._hide();
|
||||
}
|
||||
|
||||
createLayout() {
|
||||
this.HiPSui = {};
|
||||
delete() {
|
||||
if (!this.ui) {
|
||||
return
|
||||
}
|
||||
|
||||
let layout = [Layout.horizontal([this.addOverlayBtn, "Overlays"])];
|
||||
for (let component of Object.values(this.ui)) {
|
||||
for (let elt of Object.values(component)) {
|
||||
elt.remove && elt.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createLayout() {
|
||||
this.delete()
|
||||
this.ui = {};
|
||||
|
||||
let layout = [[this.addOverlayBtn, " Overlays"]];
|
||||
|
||||
layout = layout.concat(this._createOverlaysList());
|
||||
|
||||
layout.push(
|
||||
Layout.horizontal({
|
||||
layout: [
|
||||
this.addHiPSBtn,
|
||||
"Surveys",
|
||||
this.filterEnabler,
|
||||
this.filterBtn,
|
||||
],
|
||||
})
|
||||
[
|
||||
this.addHiPSBtn,
|
||||
" Surveys",
|
||||
this.filterEnabler,
|
||||
this.filterBtn,
|
||||
],
|
||||
);
|
||||
layout = layout.concat(this._createSurveysList());
|
||||
return Layout.vertical({ layout });
|
||||
return Layout.vertical(layout,
|
||||
{
|
||||
cssStyle: {
|
||||
overflowWrap: "anywhere",
|
||||
wordBreak: "break-word",
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_createOverlaysList() {
|
||||
let self = this;
|
||||
let aladin = self.aladin;
|
||||
|
||||
let layout = [];
|
||||
const overlays = Array.from(this.aladin.getOverlays())
|
||||
@@ -789,8 +789,7 @@ export class OverlayStackBox extends Box {
|
||||
// list of overlays
|
||||
for (const overlay of overlays) {
|
||||
const name = overlay.name;
|
||||
let optBtn = [];
|
||||
optBtn.push(new ActionButton({
|
||||
let showBtn = new ActionButton({
|
||||
size: "small",
|
||||
icon: {
|
||||
url: overlay.isShowing ? showIconUrl : hideIconUrl,
|
||||
@@ -815,25 +814,10 @@ export class OverlayStackBox extends Box {
|
||||
});
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
optBtn.push(new ActionButton({
|
||||
icon: {
|
||||
url: removeIconUrl,
|
||||
monochrome: true,
|
||||
},
|
||||
size: "small",
|
||||
/*cssStyle: {
|
||||
visibility: Utils.hasTouchScreen() ? 'visible' : 'hidden',
|
||||
},*/
|
||||
tooltip: {
|
||||
content: "Remove",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
action(e) {
|
||||
self.aladin.removeLayer(overlay);
|
||||
},
|
||||
}));
|
||||
});
|
||||
let optBtn = [
|
||||
showBtn,
|
||||
];
|
||||
|
||||
if (overlay.serialize) {
|
||||
optBtn.push(new ActionButton({
|
||||
@@ -853,44 +837,108 @@ export class OverlayStackBox extends Box {
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
let item = Layout.horizontal({
|
||||
layout: [
|
||||
this._addOverlayIcon(overlay),
|
||||
name,
|
||||
Layout.horizontal({ layout: optBtn }),
|
||||
],
|
||||
cssStyle: {
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
listStyle: "none",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
},
|
||||
});
|
||||
if (overlay instanceof Catalog || overlay instanceof ProgressiveCat) {
|
||||
let catSettingsBox = new Box({
|
||||
close: false,
|
||||
content: new Form({
|
||||
subInputs: [
|
||||
{
|
||||
label: 'Size',
|
||||
tooltip: {content: 'Size of the sources', position: {direction: 'right'}},
|
||||
name: 'size',
|
||||
type: 'range',
|
||||
min: 2.0,
|
||||
max: 30.0,
|
||||
value: overlay.sourceSize,
|
||||
change: (e) => {
|
||||
const size = +e.target.value;
|
||||
overlay.setSourceSize(size)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Shape',
|
||||
name: 'shape',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: "plus", label: "+" },
|
||||
{ value: "rhomb", label: "◇" },
|
||||
{ value: "triangle", label: "△" },
|
||||
{ value: "cross", label: "✕" },
|
||||
{ value: "square", label: "□" },
|
||||
{ value: "circle", label: "○" },
|
||||
],
|
||||
value: (overlay.shapeFn && "square") || overlay.shape,
|
||||
change: (e) => {
|
||||
const shape = e.target.value
|
||||
overlay.setShape(shape)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Color',
|
||||
name: 'color',
|
||||
type: 'color',
|
||||
value: overlay.color,
|
||||
change: (e) => {
|
||||
let hex = e.target.value;
|
||||
overlay.setColor(hex)
|
||||
}
|
||||
},
|
||||
]
|
||||
}),
|
||||
}, this.aladin.aladinDiv);
|
||||
catSettingsBox._hide()
|
||||
|
||||
/*if(!Utils.hasTouchScreen()) {
|
||||
layout.push({
|
||||
label: item,
|
||||
cssStyle,
|
||||
hover(e) {
|
||||
showBtn.el.style.visibility = 'visible'
|
||||
deleteBtn.el.style.visibility = 'visible'
|
||||
// catalog settings
|
||||
let catSettingsBtn = new WidgetTogglerButton({
|
||||
icon: { url: settingsIconUrl, monochrome: true },
|
||||
size: "small",
|
||||
tooltip: {
|
||||
content: "Settings",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
unhover(e) {
|
||||
showBtn.el.style.visibility = 'hidden'
|
||||
deleteBtn.el.style.visibility = 'hidden'
|
||||
toggled: false,
|
||||
enable: (_) => {
|
||||
// toggle off the other settings if opened
|
||||
for (var l in self.ui) {
|
||||
let ui = self.ui[l]
|
||||
|
||||
if (l != name) {
|
||||
if (ui.settingsBtn)
|
||||
ui.settingsBtn.close();
|
||||
}
|
||||
}
|
||||
|
||||
let spectraDisplayer = aladin.view.spectraDisplayer;
|
||||
if (spectraDisplayer)
|
||||
spectraDisplayer.attachHiPS3D(options.layer)
|
||||
},
|
||||
})
|
||||
} else {
|
||||
layout.push({
|
||||
label: item,
|
||||
cssStyle
|
||||
})
|
||||
}*/
|
||||
layout.push(item);
|
||||
widget: catSettingsBox,
|
||||
openDirection: "right"
|
||||
});
|
||||
|
||||
optBtn.push(catSettingsBtn);
|
||||
|
||||
if (!(name in self.ui)) {
|
||||
self.ui[name] = {
|
||||
settingsBox: catSettingsBox,
|
||||
settingsBtn: catSettingsBtn,
|
||||
showBtn,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
optBtn.push(ActionButton.BUTTONS(self.aladin).remove(
|
||||
(e) => {
|
||||
self.aladin.removeLayer(overlay);
|
||||
}
|
||||
));
|
||||
|
||||
layout.push([
|
||||
this._addOverlayIcon(overlay),
|
||||
'<div class="aladin-overlay-label">' + name + "</div>",
|
||||
optBtn
|
||||
]);
|
||||
}
|
||||
|
||||
return layout;
|
||||
@@ -899,98 +947,96 @@ export class OverlayStackBox extends Box {
|
||||
_createSurveysList() {
|
||||
let self = this;
|
||||
|
||||
const layers = Array.from(self.aladin.getStackLayers())
|
||||
let aladin = self.aladin;
|
||||
|
||||
const layers = Array.from(aladin.getStackLayers())
|
||||
.reverse()
|
||||
.map((name) => {
|
||||
let overlay = self.aladin.getOverlayImageLayer(name);
|
||||
let overlay = aladin.getOverlayImageLayer(name);
|
||||
return overlay;
|
||||
});
|
||||
|
||||
// survey list
|
||||
let layout = [];
|
||||
|
||||
let hipsOptions = Object.keys(self.cachedHiPS);
|
||||
hipsOptions.sort()
|
||||
|
||||
for (const layer of layers) {
|
||||
if (!layer) {
|
||||
for (const hips of layers) {
|
||||
if (!hips) {
|
||||
continue;
|
||||
}
|
||||
let options = Array.from([...hipsOptions])
|
||||
let value = layer.name || layer.id
|
||||
|
||||
if (options.indexOf(value) < 0) {
|
||||
options.push(value)
|
||||
}
|
||||
|
||||
options.push("More...")
|
||||
|
||||
let HiPSSelector = Input.select({
|
||||
value,
|
||||
options,
|
||||
title: layer.name,
|
||||
change: (e) => {
|
||||
let HiPSselect = new HiPSSelector({
|
||||
layer: hips,
|
||||
change(e) {
|
||||
let name = e.target.value;
|
||||
|
||||
if (name === "More...") {
|
||||
if (!self.hipsBrowser)
|
||||
self.hipsBrowser = new HiPSBrowserBox(self.aladin);
|
||||
if (!aladin.hipsBrowser) {
|
||||
aladin.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
}
|
||||
|
||||
self.hipsBrowser._show({ layer: layer.layer, position: { anchor: "center center" } });
|
||||
aladin.hipsBrowser._show({
|
||||
selected: (hips) => {
|
||||
self.aladin.setOverlayImageLayer(hips, hips.layer);
|
||||
},
|
||||
position: { anchor: "center center" }
|
||||
});
|
||||
return;
|
||||
}
|
||||
// search for the
|
||||
let overlayLayer;
|
||||
if (name in self.cachedHiPS) {
|
||||
// it is an hips
|
||||
let HiPSOptions = self.cachedHiPS[name];
|
||||
|
||||
let overlayLayer;
|
||||
if (name in HiPSSelector.cachedHiPS) {
|
||||
// it is an hips
|
||||
let HiPSOptions = HiPSSelector.cachedHiPS[name];
|
||||
overlayLayer = A.HiPS(HiPSOptions.id || HiPSOptions.url, HiPSOptions);
|
||||
} else {
|
||||
overlayLayer = layer
|
||||
overlayLayer = hips
|
||||
}
|
||||
|
||||
self.aladin.setOverlayImageLayer(overlayLayer, layer.layer);
|
||||
aladin.setOverlayImageLayer(overlayLayer, hips.layer);
|
||||
}
|
||||
});
|
||||
|
||||
let deleteBtn = ActionButton.createSmallSizedIconBtn({
|
||||
icon: { url: removeIconUrl, monochrome: true },
|
||||
//disable: layer.layer === "base",
|
||||
tooltip: { content: "Remove", position: { direction: "top" } },
|
||||
action(e) {
|
||||
self.aladin.removeImageLayer(layer.layer);
|
||||
action: (e) => {
|
||||
aladin.removeImageLayer(hips.layer);
|
||||
// remove HiPS cube player if any
|
||||
self.aladin.removeUIByName("cube_displayer" + layer.layer)
|
||||
aladin.removeUIByName("cube_displayer" + hips.layer)
|
||||
|
||||
let spectraDisplayer = aladin.view.spectraDisplayer;
|
||||
if (hips instanceof HiPS && spectraDisplayer && hips === spectraDisplayer.hips) {
|
||||
spectraDisplayer._hide()
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let prevOpacity = null;
|
||||
let showBtn = ActionButton.createSmallSizedIconBtn({
|
||||
icon: {
|
||||
url: layer.getOpacity() === 0.0 ? hideIconUrl : showIconUrl,
|
||||
url: hips.getOpacity() === 0.0 ? hideIconUrl : showIconUrl,
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {
|
||||
content: layer.getOpacity() === 0.0 ? "Show" : "Hide",
|
||||
content: hips.getOpacity() === 0.0 ? "Show" : "Hide",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
action(e, btn) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
let opacity = layer.getOpacity();
|
||||
let opacity = hips.getOpacity();
|
||||
if (opacity === 0.0) {
|
||||
let newOpacity = prevOpacity || 1.0;
|
||||
prevOpacity = null;
|
||||
layer.setOpacity(newOpacity);
|
||||
hips.setOpacity(newOpacity);
|
||||
btn.update({
|
||||
icon: { monochrome: true, url: showIconUrl },
|
||||
tooltip: { content: "Hide" },
|
||||
});
|
||||
} else {
|
||||
prevOpacity = opacity;
|
||||
layer.setOpacity(0.0);
|
||||
hips.setOpacity(0.0);
|
||||
btn.update({
|
||||
icon: { monochrome: true, url: hideIconUrl },
|
||||
tooltip: { content: "Show" },
|
||||
@@ -1000,10 +1046,9 @@ export class OverlayStackBox extends Box {
|
||||
});
|
||||
|
||||
let settingsBox = new HiPSSettingsBox(self.aladin);
|
||||
settingsBox.update({ layer });
|
||||
settingsBox._hide();
|
||||
|
||||
let settingsBtn = new TogglerActionButton({
|
||||
let settingsBtn = new WidgetTogglerButton({
|
||||
icon: { url: settingsIconUrl, monochrome: true },
|
||||
size: "small",
|
||||
tooltip: {
|
||||
@@ -1011,104 +1056,27 @@ export class OverlayStackBox extends Box {
|
||||
position: { direction: "top" },
|
||||
},
|
||||
toggled: false,
|
||||
actionOn: (e) => {
|
||||
enable: (_) => {
|
||||
// toggle off the other settings if opened
|
||||
for (var l in self.HiPSui) {
|
||||
let ui = self.HiPSui[l]
|
||||
for (var l in self.ui) {
|
||||
let ui = self.ui[l]
|
||||
|
||||
if (l != layer.layer) {
|
||||
if (l != hips.layer) {
|
||||
ui.settingsBtn.close();
|
||||
}
|
||||
}
|
||||
|
||||
settingsBox._show({
|
||||
position: {
|
||||
nextTo: settingsBtn,
|
||||
direction: "right",
|
||||
aladin: self.aladin,
|
||||
},
|
||||
});
|
||||
},
|
||||
actionOff: (e) => {
|
||||
settingsBox._hide();
|
||||
settingsBox.update({ layer: hips });
|
||||
},
|
||||
widget: settingsBox,
|
||||
openDirection: "right",
|
||||
});
|
||||
|
||||
let loadMOCBtn = new ActionButton({
|
||||
size: "small",
|
||||
|
||||
icon: {
|
||||
url: Icon.dataURLFromSVG({ svg: Icon.SVG_ICONS.MOC }),
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {
|
||||
content: "Add coverage",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
toggled: (() => {
|
||||
let overlays = self.aladin.getOverlays();
|
||||
let found = overlays.find(
|
||||
(o) => o.type === "moc" && o.name === layer.name
|
||||
);
|
||||
return found !== undefined;
|
||||
})(),
|
||||
action: (e) => {
|
||||
if (!loadMOCBtn.options.toggled) {
|
||||
// load the moc
|
||||
let moc = A.MOCFromURL(
|
||||
layer.url + "/Moc.fits",
|
||||
{ name: layer.name },
|
||||
() => {
|
||||
self.mocHiPSUrls[layer.url] = moc;
|
||||
|
||||
if (self.aladin.statusBar) {
|
||||
self.aladin.statusBar.appendMessage({
|
||||
message:
|
||||
"Coverage of " +
|
||||
layer.name +
|
||||
" loaded",
|
||||
duration: 2000,
|
||||
type: "info",
|
||||
});
|
||||
}
|
||||
|
||||
loadMOCBtn.update({
|
||||
toggled: true,
|
||||
tooltip: {
|
||||
content: "Remove coverage",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
self.aladin.addMOC(moc);
|
||||
} else {
|
||||
// unload the moc
|
||||
let moc = self.mocHiPSUrls[layer.url];
|
||||
self.aladin.removeLayer(moc);
|
||||
|
||||
delete self.mocHiPSUrls[layer.url];
|
||||
|
||||
if (self.aladin.statusBar) {
|
||||
self.aladin.statusBar.appendMessage({
|
||||
message:
|
||||
"Coverage of " + layer.name + " removed",
|
||||
duration: 2000,
|
||||
type: "info",
|
||||
});
|
||||
}
|
||||
|
||||
loadMOCBtn.update({
|
||||
toggled: false,
|
||||
tooltip: {
|
||||
content: "Add coverage",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
let loadMOCBtn = ActionButton.BUTTONS(self.aladin)
|
||||
.addMOC({
|
||||
name: hips.name,
|
||||
url: hips.url + '/Moc.fits'
|
||||
});
|
||||
|
||||
self.layer2swap = null;
|
||||
let swapBtn = new ActionButton({
|
||||
@@ -1127,9 +1095,9 @@ export class OverlayStackBox extends Box {
|
||||
let toggled = swapBtn.options.toggled;
|
||||
if (!toggled) {
|
||||
if (!self.layer2swap) {
|
||||
self.layer2swap = layer;
|
||||
self.layer2swap = hips;
|
||||
} else {
|
||||
self.aladin.view.swapLayers(self.layer2swap.layer, layer.layer);
|
||||
self.aladin.view.swapLayers(self.layer2swap.layer, hips.layer);
|
||||
}
|
||||
} else {
|
||||
if (self.layer2swap) {
|
||||
@@ -1145,20 +1113,17 @@ export class OverlayStackBox extends Box {
|
||||
|
||||
let btns = [showBtn, settingsBtn];
|
||||
|
||||
if (!(layer instanceof Image)) {
|
||||
if (!(hips instanceof Image)) {
|
||||
btns.push(loadMOCBtn);
|
||||
}
|
||||
btns = btns.concat([swapBtn, deleteBtn]);
|
||||
|
||||
let item = Layout.horizontal({
|
||||
layout: [HiPSSelector, Layout.horizontal(btns)],
|
||||
});
|
||||
|
||||
let item = Layout.horizontal([HiPSselect, Layout.horizontal(btns)]);
|
||||
layout.push(item);
|
||||
|
||||
if (!(layer.layer in self.HiPSui)) {
|
||||
self.HiPSui[layer.layer] = {
|
||||
HiPSSelector,
|
||||
if (!(hips.layer in self.ui)) {
|
||||
self.ui[hips.layer] = {
|
||||
HiPSSelector: HiPSselect,
|
||||
settingsBox,
|
||||
settingsBtn,
|
||||
showBtn,
|
||||
@@ -1224,7 +1189,5 @@ export class OverlayStackBox extends Box {
|
||||
...options,
|
||||
...{ position: this.position },
|
||||
});
|
||||
|
||||
this.stackBtn.update({toggled: true});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,27 +117,12 @@ export class StatusBarBox extends Box {
|
||||
this.el.title = task.message;
|
||||
|
||||
// create message div
|
||||
let message = Layout.horizontal({
|
||||
layout: task.message,
|
||||
tooltip: {
|
||||
content: task.message,
|
||||
position: {
|
||||
direction: "top",
|
||||
},
|
||||
hoverable: true,
|
||||
delayShowUpTime: '500ms',
|
||||
cssStyle: {
|
||||
fontSize: 'x-small',
|
||||
maxWidth: "200px",
|
||||
"overflow-wrap": "break-word",
|
||||
}
|
||||
},
|
||||
});
|
||||
let message = Layout.horizontal(task.message);
|
||||
|
||||
message.addClass("aladin-status-bar-message")
|
||||
|
||||
this._show({
|
||||
content: new Layout({layout: [StatusBarBox.icons[task.type], message], orientation: 'horizontal'}),
|
||||
content: Layout.horizontal([StatusBarBox.icons[task.type], message]),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export class ConeSearchActionButton extends ActionButton {
|
||||
url: targetIconUrl
|
||||
},
|
||||
tooltip: options.tooltip,
|
||||
disable: options.disable,
|
||||
disabled: options.disabled,
|
||||
cssStyle: {
|
||||
backgroundPosition: 'center center',
|
||||
cursor: 'pointer',
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import { ContextMenu } from "../Widgets/ContextMenu.js";
|
||||
|
||||
import { WidgetTogglerButton } from "./Toggler.js";
|
||||
/*
|
||||
export class CtxMenuActionButtonOpener extends ActionButton {
|
||||
|
||||
// Constructor
|
||||
constructor(options, aladin) {
|
||||
let self;
|
||||
@@ -48,35 +48,86 @@ export class CtxMenuActionButtonOpener extends ActionButton {
|
||||
};
|
||||
|
||||
super({
|
||||
...options,
|
||||
cssStyle: {
|
||||
backgroundPosition: 'center center',
|
||||
cursor: 'pointer',
|
||||
...options.cssStyle
|
||||
},
|
||||
action(e) {
|
||||
enableTooltips()
|
||||
|
||||
let isHidden = self.ctxMenu.isHidden
|
||||
let wasClosed = self.ctxMenu.isHidden;
|
||||
self.close()
|
||||
|
||||
ContextMenu.hideAll();
|
||||
if (self.ctxMenu.toggler === self && !wasClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it was hidden then reopen it
|
||||
if (isHidden) {
|
||||
if (options.action) {
|
||||
options.action(e)
|
||||
}
|
||||
self.open(e);
|
||||
|
||||
if (self.layout) {
|
||||
self.ctxMenu.attach(self.layout)
|
||||
}
|
||||
// the panel is now open and we know the button has a tooltip
|
||||
// => we close it!
|
||||
if (self.tooltip && !self.ctxMenu.isHidden) {
|
||||
self.tooltip.element().style.visibility = 'hidden'
|
||||
self.tooltip.element().style.transitionDelay = '0ms';
|
||||
|
||||
self.ctxMenu.show({
|
||||
position: {
|
||||
nextTo: self,
|
||||
direction: options.openDirection,
|
||||
},
|
||||
});
|
||||
aladin.aladinDiv.addEventListener("click", enableTooltips)
|
||||
}
|
||||
},
|
||||
...options,
|
||||
})
|
||||
|
||||
self = this;
|
||||
|
||||
this.ctxMenu = aladin.contextMenu;
|
||||
this.layout = options.ctxMenu;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.closed = true;
|
||||
this.ctxMenu._hide();
|
||||
}
|
||||
|
||||
open(e) {
|
||||
if (this.layout) {
|
||||
this.ctxMenu.attach(this.layout, this)
|
||||
}
|
||||
|
||||
this.ctxMenu.show({
|
||||
position: {
|
||||
nextTo: this,
|
||||
direction: this.options.openDirection,
|
||||
},
|
||||
});
|
||||
|
||||
this.closed = false;
|
||||
}
|
||||
|
||||
_hide() {
|
||||
this.close();
|
||||
super._hide();
|
||||
}
|
||||
}*/
|
||||
|
||||
export class CtxMenuActionButtonOpener extends WidgetTogglerButton {
|
||||
|
||||
// Constructor
|
||||
constructor(options, aladin) {
|
||||
let self;
|
||||
|
||||
const enableTooltips = () => {
|
||||
aladin.aladinDiv.removeEventListener('click', enableTooltips);
|
||||
|
||||
aladin.aladinDiv.querySelectorAll('.aladin-tooltip')
|
||||
// for each tooltips reset its visibility and transition delay
|
||||
.forEach((t) => {
|
||||
t.style.visibility = ''
|
||||
t.style.transitionDelay = ''
|
||||
})
|
||||
};
|
||||
super({
|
||||
widget: aladin.contextMenu,
|
||||
enable(e) {
|
||||
enableTooltips()
|
||||
// If it was hidden then reopen it
|
||||
if (self.layout) {
|
||||
self.ctxMenu.attach(self.layout, self)
|
||||
}
|
||||
|
||||
// the panel is now open and we know the button has a tooltip
|
||||
@@ -87,58 +138,22 @@ export class CtxMenuActionButtonOpener extends ActionButton {
|
||||
|
||||
aladin.aladinDiv.addEventListener("click", enableTooltips)
|
||||
}
|
||||
}
|
||||
},
|
||||
...options,
|
||||
})
|
||||
|
||||
self = this;
|
||||
|
||||
let ctxMenu;
|
||||
if (options.ctxMenu instanceof ContextMenu) {
|
||||
ctxMenu = options.ctxMenu;
|
||||
} else {
|
||||
this.layout = options.ctxMenu;
|
||||
ctxMenu = new ContextMenu(aladin, {hideOnClick: true, hideOnResize: true})
|
||||
}
|
||||
|
||||
self.ctxMenu = ctxMenu;
|
||||
}
|
||||
|
||||
hideMenu() {
|
||||
this.ctxMenu._hide();
|
||||
}
|
||||
|
||||
_hide() {
|
||||
this.hideMenu();
|
||||
super._hide();
|
||||
this.ctxMenu = aladin.contextMenu;
|
||||
this.layout = options.ctxMenu;
|
||||
}
|
||||
|
||||
update(options) {
|
||||
if(options.ctxMenu) {
|
||||
if (options.ctxMenu instanceof ContextMenu) {
|
||||
this.ctxMenu = options.ctxMenu
|
||||
} else {
|
||||
this.layout = options.ctxMenu;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.ctxMenu) {
|
||||
this.ctxMenu = new ContextMenu(aladin, {hideOnClick: true, hideOnResize: true})
|
||||
if (options && options.ctxMenu) {
|
||||
this.layout = options.ctxMenu;
|
||||
//this.ctxMenu.attach(this.layout, this)
|
||||
}
|
||||
|
||||
super.update(options)
|
||||
|
||||
if (!this.ctxMenu.isHidden) {
|
||||
if (this.layout) {
|
||||
this.ctxMenu.attach(this.layout)
|
||||
}
|
||||
|
||||
this.ctxMenu.show({
|
||||
position: {
|
||||
nextTo: this,
|
||||
// it case it is not given then it will be computed by default
|
||||
direction: options.openDirection,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,25 +44,28 @@ import { ALEvent } from "../../events/ALEvent";
|
||||
constructor(aladin, options) {
|
||||
options = options || {};
|
||||
options.verbosity = (options && options.verbosity) || 'full';
|
||||
|
||||
let projectionName = aladin.getProjectionName();
|
||||
let self;
|
||||
let ctxMenu = _buildLayout(aladin);
|
||||
|
||||
super({
|
||||
icon: {
|
||||
monochrome: true,
|
||||
size: 'medium',
|
||||
url: projectionIconUrl,
|
||||
},
|
||||
openDirection: 'left',
|
||||
classList: ['aladin-projection-control'],
|
||||
//content: [options.verbosity === 'full' ? ProjectionEnum[projectionName].label : projectionName],
|
||||
content: projectionName,
|
||||
tooltip: {content: 'Change the view projection', position: {direction: 'bottom left'}},
|
||||
ctxMenu,
|
||||
...options
|
||||
}, aladin);
|
||||
|
||||
self = this;
|
||||
this.aladin = aladin;
|
||||
|
||||
let ctxMenu = this._buildLayout();
|
||||
this.update({ctxMenu})
|
||||
|
||||
this._addEventListeners()
|
||||
}
|
||||
|
||||
@@ -77,41 +80,21 @@ import { ALEvent } from "../../events/ALEvent";
|
||||
self.update({content})
|
||||
});
|
||||
}
|
||||
|
||||
_buildLayout() {
|
||||
let aladin = this.aladin;
|
||||
|
||||
let layout = [];
|
||||
let self = this;
|
||||
|
||||
let aladinProj = aladin.getProjectionName();
|
||||
for (const key in ProjectionEnum) {
|
||||
let proj = ProjectionEnum[key];
|
||||
|
||||
layout.push({
|
||||
label: proj.label,
|
||||
selected: aladinProj === key,
|
||||
action(o) {
|
||||
aladin.setProjection(key)
|
||||
|
||||
let ctxMenu = self._buildLayout(aladin);
|
||||
//self.update({ctxMenu, content: self.options.verbosity === 'full' ? proj.label : key});
|
||||
self.update({ctxMenu});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
update(options) {
|
||||
super.update(options);
|
||||
|
||||
/*if (options.verbosity) {
|
||||
let ctxMenu = this._buildLayout();
|
||||
let projName = this.aladin.getProjectionName();
|
||||
let label = options.verbosity === 'full' ? ProjectionEnum[projName].label : projName;
|
||||
super.update({ctxMenu, content: label});
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
function _buildLayout(aladin) {
|
||||
let layout = [];
|
||||
|
||||
for (const key in ProjectionEnum) {
|
||||
let proj = ProjectionEnum[key];
|
||||
|
||||
layout.push({
|
||||
label: proj.label,
|
||||
action(o) {
|
||||
aladin.setProjection(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ import waveOffIconUrl from '../../../../assets/icons/wave-off.svg';
|
||||
url: waveOffIconUrl
|
||||
},
|
||||
tooltip: {content: 'SAMP disabled in Aladin Lite options', position: {direction: 'top'}},
|
||||
disable: true,
|
||||
disabled: true,
|
||||
}
|
||||
} else {
|
||||
//let isHubRunning = aladin.samp.isHubCurrentlyRunning();
|
||||
@@ -92,23 +92,6 @@ import waveOffIconUrl from '../../../../assets/icons/wave-off.svg';
|
||||
}
|
||||
self.update({icon})
|
||||
});
|
||||
|
||||
/*ALEvent.SAMP_HUB_RUNNING.listenedBy(aladin.aladinDiv, function (e) {
|
||||
const isHubRunning = e.detail.isHubRunning;
|
||||
|
||||
if (hubRunning !== isHubRunning) {
|
||||
let newOptions = {
|
||||
disable: !isHubRunning,
|
||||
tooltip: isHubRunning ? {content: 'Connect to SAMP hub'} : {content: 'No hub running found'}
|
||||
};
|
||||
|
||||
self.update(newOptions)
|
||||
if (isHubRunning === false) {
|
||||
self.update({iconURL: waveOffIconUrl})
|
||||
}
|
||||
hubRunning = isHubRunning;
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
static sendSources(aladin) {
|
||||
|
||||
@@ -17,9 +17,22 @@
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
import { Layout } from "../Layout.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { Color } from "../../Color.js";
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
import { SAMPActionButton } from "../Button/SAMP.js";
|
||||
import helpIconBtn from '../../../../assets/icons/help.svg';
|
||||
import { Utils } from "../../Utils";
|
||||
import { GridSettingsCtxMenu } from "./../CtxMenu/GridSettings.js";
|
||||
import { CtxMenuActionButtonOpener } from "./CtxMenuOpener";
|
||||
import settingsIconUrl from './../../../../assets/icons/settings.svg';
|
||||
import { SettingsCtxMenu } from "../CtxMenu/Settings";
|
||||
import { SimbadPointer } from "./SimbadPointer.js";
|
||||
import { GridEnabler } from "./GridEnabler.js";
|
||||
import { Stack } from "./Stack.js";
|
||||
import { ColorPicker } from "./ColorPicker.js";
|
||||
import { ShareActionButton } from "./ShareView.js";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -54,8 +67,307 @@ import { SettingsCtxMenu } from "../CtxMenu/Settings";
|
||||
direction: 'right'
|
||||
}
|
||||
},
|
||||
ctxMenu: new SettingsCtxMenu(aladin, options),
|
||||
ctxMenu: undefined,
|
||||
...options
|
||||
}, aladin);
|
||||
|
||||
this.aladin = aladin;
|
||||
let ctxMenu = this._buildLayout()
|
||||
this.update({ctxMenu})
|
||||
}
|
||||
|
||||
_buildLayout() {
|
||||
let self = this;
|
||||
let aladin = this.aladin;
|
||||
let backgroundColorInput = Input.color({
|
||||
name: 'color',
|
||||
value: (() => {
|
||||
let {r, g, b} = aladin.getBackgroundColor();
|
||||
return Color.rgbToHex(r, g, b);
|
||||
})(),
|
||||
change(e) {
|
||||
let hex = e.target.value;
|
||||
aladin.setBackgroundColor(hex)
|
||||
}
|
||||
});
|
||||
|
||||
let reticleColorInput = Input.color({
|
||||
value: new Color(aladin.getReticle().getColor()).toHex(),
|
||||
name: 'reticleColor',
|
||||
change(e) {
|
||||
let hex = e.target.value;
|
||||
aladin.setDefaultColor(hex)
|
||||
}
|
||||
});
|
||||
|
||||
// Event received from aladin
|
||||
ALEvent.BACKGROUND_COLOR_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
|
||||
const {r, g, b} = e.detail.color;
|
||||
|
||||
let hex = Color.rgbToHex(r, g, b);
|
||||
backgroundColorInput.set(hex)
|
||||
});
|
||||
|
||||
ALEvent.RETICLE_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
|
||||
const color = e.detail.color;
|
||||
let hex = new Color(color).toHex();
|
||||
|
||||
reticleColorInput.set(hex)
|
||||
});
|
||||
|
||||
const toggleCheckbox = (checkbox) => {
|
||||
const pastVal = checkbox.get();
|
||||
const curVal = !pastVal;
|
||||
|
||||
checkbox.set(curVal)
|
||||
|
||||
return curVal;
|
||||
};
|
||||
|
||||
let hpxGridCheckbox = Input.checkbox({
|
||||
name: 'hpxgrid', checked: aladin.healpixGrid(),
|
||||
click(e) {
|
||||
let newVal = toggleCheckbox(hpxGridCheckbox);
|
||||
aladin.showHealpixGrid(newVal)
|
||||
}
|
||||
})
|
||||
let reticleCheckbox = Input.checkbox({
|
||||
name: 'reticle',
|
||||
checked: aladin.isReticleDisplayed(),
|
||||
click(e) {
|
||||
let newVal = toggleCheckbox(reticleCheckbox);
|
||||
aladin.showReticle(newVal)
|
||||
}
|
||||
})
|
||||
|
||||
let reticle = aladin.getReticle();
|
||||
|
||||
let sliderReticleSize = Input.slider({
|
||||
name: 'reticleSize',
|
||||
type: 'range',
|
||||
min: 0.0,
|
||||
max: 50,
|
||||
value: reticle.getSize(),
|
||||
change(e) {
|
||||
reticle.update({size: e.target.value})
|
||||
}
|
||||
});
|
||||
|
||||
let sampBtn = new SAMPActionButton({
|
||||
size: 'small',
|
||||
action(conn) {
|
||||
if (conn.isConnected()) {
|
||||
conn.unregister();
|
||||
} else {
|
||||
conn.register();
|
||||
}
|
||||
|
||||
//self._hide()
|
||||
}
|
||||
}, aladin);
|
||||
|
||||
return [
|
||||
GridSettingsCtxMenu.getLayout(aladin),
|
||||
{
|
||||
label: {
|
||||
content: ['Reticle']
|
||||
},
|
||||
subMenu: [
|
||||
{
|
||||
label: {
|
||||
content: [reticleCheckbox, 'Show/Hide']
|
||||
},
|
||||
mustHide: false,
|
||||
action(o) {
|
||||
let newVal = toggleCheckbox(reticleCheckbox);
|
||||
aladin.showReticle(newVal)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [reticleColorInput, 'Color']
|
||||
},
|
||||
},
|
||||
{
|
||||
label: Layout.horizontal(['Size', sliderReticleSize]),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [backgroundColorInput, 'Back color']
|
||||
},
|
||||
mustHide: false,
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: 'Light/Dark mode'
|
||||
},
|
||||
mustHide: false,
|
||||
action(o) {
|
||||
const currentTheme = aladin.aladinDiv.getAttribute("data-theme");
|
||||
const newTheme = currentTheme === "dark" ? "light" : "dark";
|
||||
aladin._applyTheme(newTheme);
|
||||
localStorage.setItem("theme", newTheme);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [hpxGridCheckbox, 'HEALPix grid']
|
||||
},
|
||||
mustHide: false,
|
||||
action(o) {
|
||||
let newVal = toggleCheckbox(hpxGridCheckbox);
|
||||
aladin.showHealpixGrid(newVal)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [sampBtn, 'SAMP']
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Tools',
|
||||
subMenu: [
|
||||
{
|
||||
label: 'Stack',
|
||||
mustHide: false,
|
||||
action: (o) => {
|
||||
let toolbar = aladin.toolbar;
|
||||
if (!toolbar.has('stack')) {
|
||||
toolbar.add('stack', new Stack(aladin));
|
||||
} else {
|
||||
if (toolbar.enabled('stack')) {
|
||||
toolbar.disable('stack')
|
||||
} else {
|
||||
toolbar.enable('stack')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Simbad',
|
||||
mustHide: false,
|
||||
action: (o) => {
|
||||
let toolbar = aladin.toolbar;
|
||||
if (!toolbar.has('simbad')) {
|
||||
toolbar.add('simbad', new SimbadPointer(aladin));
|
||||
} else {
|
||||
if (toolbar.enabled('simbad')) {
|
||||
toolbar.disable('simbad')
|
||||
} else {
|
||||
toolbar.enable('simbad')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Grid',
|
||||
mustHide: false,
|
||||
action: (o) => {
|
||||
let toolbar = aladin.toolbar;
|
||||
if (!toolbar.has('grid')) {
|
||||
toolbar.add('grid', new GridEnabler(aladin));
|
||||
} else {
|
||||
if (toolbar.enabled('grid')) {
|
||||
toolbar.disable('grid')
|
||||
} else {
|
||||
toolbar.enable('grid')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Color picker',
|
||||
mustHide: false,
|
||||
action: (o) => {
|
||||
let toolbar = aladin.toolbar;
|
||||
if (!toolbar.has('picker')) {
|
||||
toolbar.add('picker', new ColorPicker(aladin));
|
||||
} else {
|
||||
if (toolbar.enabled('picker')) {
|
||||
toolbar.disable('picker')
|
||||
} else {
|
||||
toolbar.enable('picker')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Share view',
|
||||
mustHide: false,
|
||||
action: (o) => {
|
||||
let toolbar = aladin.toolbar;
|
||||
if (!toolbar.has('share')) {
|
||||
toolbar.add('share', new ShareActionButton(aladin));
|
||||
} else {
|
||||
if (toolbar.enabled('share')) {
|
||||
toolbar.disable('share')
|
||||
} else {
|
||||
toolbar.enable('share')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: {
|
||||
icon: {
|
||||
monochrome: true,
|
||||
tooltip: {content: 'Documentation about Aladin Lite', position: {direction: 'top'}},
|
||||
url: helpIconBtn,
|
||||
size: 'small',
|
||||
cssStyle: {
|
||||
cursor: 'help',
|
||||
}
|
||||
},
|
||||
content: 'Help'
|
||||
},
|
||||
subMenu: [
|
||||
{
|
||||
label: 'Aladin Lite API',
|
||||
action(o) {
|
||||
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: 'Contact us',
|
||||
tooltip: { content: 'For bug reports, discussions, feature ideas...', position: {direction: 'bottom'} }
|
||||
},
|
||||
subMenu: [
|
||||
{
|
||||
label: 'GitHub',
|
||||
action(o) {
|
||||
Utils.openNewTab('https://github.com/cds-astro/aladin-lite/issues')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'by email',
|
||||
action(o) {
|
||||
Utils.openNewTab('mailto:matthieu.baumann@astro.unistra.fr,thomas.boch@astro.unistra.fr?subject=Aladin Lite issue&body=message%20goes%20here')
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'General documentation',
|
||||
|
||||
action(o) {
|
||||
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: Layout.horizontal('Examples', { tooltip: { content: 'How to embed Aladin Lite <br \>into your own webpages!', position: {direction: 'bottom'}}}),
|
||||
action(o) {
|
||||
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,6 @@ export class SnapshotActionButton extends ActionButton {
|
||||
}
|
||||
})
|
||||
|
||||
this.addClass('medium-sized-icon')
|
||||
this.addClass('aladin-medium-sized-icon')
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,9 @@
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
import { CtxMenuActionButtonOpener } from "./CtxMenuOpener";
|
||||
import stackOverlayIconUrl from './../../../../assets/icons/stack.svg';
|
||||
import { OverlayStackBox } from "../Box/StackBox";
|
||||
|
||||
import { ActionButton } from "./../Widgets/ActionButton";
|
||||
import { WidgetTogglerButton } from "./Toggler";
|
||||
import stackOverlayIconUrl from "./../../../../assets/icons/stack.svg";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -34,18 +32,18 @@ import { ActionButton } from "./../Widgets/ActionButton";
|
||||
*
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Class representing a Tabs layout
|
||||
* @extends CtxMenuActionButtonOpener
|
||||
* Class representing the stack
|
||||
* @extends WidgetTogglerButton
|
||||
*/
|
||||
export class OverlayStackButton extends ActionButton {
|
||||
export class Stack extends WidgetTogglerButton {
|
||||
/**
|
||||
* UI responsible for displaying the viewport infos
|
||||
* @param {Aladin} aladin - The aladin instance.
|
||||
*/
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
let stack;
|
||||
super({
|
||||
openDirection: (options && options.openDirection) || 'right',
|
||||
widget: new OverlayStackBox(aladin),
|
||||
icon: {
|
||||
size: 'medium',
|
||||
monochrome: true,
|
||||
@@ -55,25 +53,9 @@ import { ActionButton } from "./../Widgets/ActionButton";
|
||||
tooltip: {
|
||||
content: 'Open the overlays menu',
|
||||
position: {
|
||||
direction: 'top right'
|
||||
direction: (options && options.openDirection) || 'left'
|
||||
}
|
||||
},
|
||||
toggled: false,
|
||||
action(e) {
|
||||
if (stack.isHidden) {
|
||||
stack._show({
|
||||
position: {
|
||||
nextTo: self,
|
||||
direction: 'right'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
stack._hide()
|
||||
}
|
||||
},
|
||||
...options
|
||||
});
|
||||
self = this;
|
||||
stack = new OverlayStackBox(aladin, self);
|
||||
}
|
||||
}
|
||||
@@ -42,9 +42,8 @@ export class TogglerActionButton extends ActionButton {
|
||||
super({
|
||||
...options,
|
||||
toggled,
|
||||
action(o) {
|
||||
options.action && options.action(o);
|
||||
self.toggle(o);
|
||||
action: (o) => {
|
||||
self.toggle(o)
|
||||
}
|
||||
})
|
||||
this.toggled = toggled;
|
||||
@@ -67,15 +66,89 @@ export class TogglerActionButton extends ActionButton {
|
||||
toggle(o) {
|
||||
this.toggled = !this.toggled;
|
||||
|
||||
if (this.toggled && this.options.actionOn) {
|
||||
this.options.actionOn(o)
|
||||
if (this.toggled && this.options.on) {
|
||||
this.options.on(o)
|
||||
}
|
||||
|
||||
if (!this.toggled && this.options.actionOff) {
|
||||
this.options.actionOff(o)
|
||||
if (!this.toggled && this.options.off) {
|
||||
this.options.off(o)
|
||||
}
|
||||
|
||||
// once the actions has been executed, modify the styling
|
||||
this.update({toggled: this.toggled, tooltip: this.toggled ? this.options.tooltipOn : this.options.tooltipOff})
|
||||
this.update({toggled: this.toggled})
|
||||
}
|
||||
}
|
||||
|
||||
// It may happen that the widget closes and so the toggler
|
||||
// has to be notified. For example when the user clicks on a Box that
|
||||
// is attached to a toggler.
|
||||
notify(state) {
|
||||
if (this.toggled === state)
|
||||
return;
|
||||
|
||||
this.toggled = state;
|
||||
this.update({toggled: this.toggled})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a Tabs layout
|
||||
* @extends TogglerActionButton
|
||||
*/
|
||||
export class WidgetTogglerButton extends TogglerActionButton {
|
||||
/**
|
||||
* UI responsible for displaying the viewport infos
|
||||
* @param {Aladin} aladin - The aladin instance.
|
||||
*/
|
||||
constructor(options) {
|
||||
let self;
|
||||
|
||||
let widget = options && options.widget;
|
||||
let enable = options && options.enable;
|
||||
|
||||
super({
|
||||
toggled: false,
|
||||
on: (o) => {
|
||||
if (enable)
|
||||
enable(o)
|
||||
|
||||
widget._show({
|
||||
position: self.position
|
||||
})
|
||||
},
|
||||
off: (_) => {
|
||||
self.close();
|
||||
},
|
||||
...options
|
||||
});
|
||||
self = this;
|
||||
|
||||
this.update(options)
|
||||
|
||||
widget.setToggler(this);
|
||||
this.widget = widget;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.widget._hide();
|
||||
|
||||
super.close()
|
||||
}
|
||||
|
||||
update(options) {
|
||||
this.openDirection = (options && options.openDirection) || this.openDirection;
|
||||
this.openPosition = (options && options.openPosition) || this.openPosition;
|
||||
|
||||
if (this.openPosition) {
|
||||
this.position = {
|
||||
anchor: this.openPosition,
|
||||
}
|
||||
} else {
|
||||
this.position = {
|
||||
direction: this.openDirection,
|
||||
nextTo: this
|
||||
}
|
||||
}
|
||||
|
||||
super.update(options)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +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 gui/Stack/Menu.js
|
||||
*
|
||||
*
|
||||
* Author: Matthieu Baumann [CDS, matthieu.baumann@astro.unistra.fr]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
|
||||
/*
|
||||
options = {
|
||||
action: (connector) => {
|
||||
|
||||
}
|
||||
tooltip
|
||||
}
|
||||
*/
|
||||
export class WidgetOpenerActionButton extends ActionButton {
|
||||
// Constructor
|
||||
constructor(options) {
|
||||
let widget = options.widget;
|
||||
super({
|
||||
...options,
|
||||
action(e) {
|
||||
if (widget.isHidden) {
|
||||
widget._show();
|
||||
} else {
|
||||
widget._hide();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.addClass('medium-sized-icon')
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,7 @@
|
||||
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import { Color } from "../../Color.js";
|
||||
import thicknessLineIcon from './../../../../assets/icons/thickness.svg';
|
||||
|
||||
export let GridSettingsCtxMenu = (function () {
|
||||
|
||||
@@ -77,55 +75,6 @@ export let GridSettingsCtxMenu = (function () {
|
||||
}
|
||||
});
|
||||
|
||||
const thicknessLineBtn = ActionButton.createSmallSizedIconBtn({
|
||||
icon: {
|
||||
url: thicknessLineIcon,
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {content: 'Grid line thickness', position: {direction: 'left'}},
|
||||
cssStyle: {
|
||||
backgroundColor: '#bababa',
|
||||
borderColor: '#484848',
|
||||
cursor: 'pointer',
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
padding: '0',
|
||||
},
|
||||
action(e) {
|
||||
let ctxMenu = ContextMenu.getInstance(aladin);
|
||||
ctxMenu._hide();
|
||||
|
||||
let ctxMenuLayout = [];
|
||||
for (let thickness = 1; thickness <= 5; thickness++) {
|
||||
ctxMenuLayout.push({
|
||||
label: thickness + 'px',
|
||||
action(o) {
|
||||
aladin.setCooGrid({thickness: thickness})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ctxMenu.attach(ctxMenuLayout);
|
||||
ctxMenu.show({
|
||||
e: e,
|
||||
position: {
|
||||
nextTo: thicknessLineBtn,
|
||||
direction: 'bottom',
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
let enableCheckbox = Input.checkbox({
|
||||
name: 'enableGrid',
|
||||
tooltip: {content: 'Enable/disable the grid', position: {direction: 'left'}},
|
||||
type: 'checkbox',
|
||||
checked: aladin.getGridOptions().enabled,
|
||||
click(e) {
|
||||
aladin.setCooGrid({enabled: enableCheckbox.get()})
|
||||
}
|
||||
});
|
||||
|
||||
ALEvent.COO_GRID_UPDATED.listenedBy(aladin.aladinDiv, function (e) {
|
||||
let color = e.detail.color;
|
||||
|
||||
|
||||
@@ -1,309 +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 gui/Stack/Menu.js
|
||||
*
|
||||
*
|
||||
* Author: Matthieu Baumann [CDS, matthieu.baumann@astro.unistra.fr]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Layout } from "../Layout.js";
|
||||
import { ContextMenu } from "../Widgets/ContextMenu.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { Color } from "../../Color.js";
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
import { SAMPActionButton } from "../Button/SAMP.js";
|
||||
import helpIconBtn from '../../../../assets/icons/help.svg';
|
||||
import { Utils } from "../../Utils";
|
||||
import { GridSettingsCtxMenu } from "./GridSettings.js";
|
||||
|
||||
export class SettingsCtxMenu extends ContextMenu {
|
||||
// Constructor
|
||||
constructor(aladin, options) {
|
||||
super(aladin, {hideOnClick: true});
|
||||
let self = this;
|
||||
self.backgroundColorInput = Input.color({
|
||||
name: 'color',
|
||||
value: (() => {
|
||||
let {r, g, b} = aladin.getBackgroundColor();
|
||||
return Color.rgbToHex(r, g, b);
|
||||
})(),
|
||||
change(e) {
|
||||
let hex = e.target.value;
|
||||
aladin.setBackgroundColor(hex)
|
||||
}
|
||||
});
|
||||
|
||||
let reticleColor = new Color(aladin.getReticle().getColor())
|
||||
self.reticleColorInput = Input.color({
|
||||
value: reticleColor.toHex(),
|
||||
name: 'reticleColor',
|
||||
change(e) {
|
||||
let hex = e.target.value;
|
||||
aladin.setDefaultColor(hex)
|
||||
}
|
||||
});
|
||||
|
||||
// Event received from aladin
|
||||
ALEvent.BACKGROUND_COLOR_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
|
||||
const {r, g, b} = e.detail.color;
|
||||
|
||||
let hex = Color.rgbToHex(r, g, b);
|
||||
self.backgroundColorInput.set(hex)
|
||||
});
|
||||
ALEvent.RETICLE_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
|
||||
const color = e.detail.color;
|
||||
let hex = new Color(color).toHex();
|
||||
|
||||
self.reticleColorInput.set(hex)
|
||||
});
|
||||
|
||||
this.toggleCheckbox = (checkbox) => {
|
||||
const pastVal = checkbox.get();
|
||||
const curVal = !pastVal;
|
||||
|
||||
checkbox.set(curVal)
|
||||
|
||||
return curVal;
|
||||
};
|
||||
|
||||
self.hpxGridCheckbox = Input.checkbox({
|
||||
name: 'hpxgrid', checked: this.aladin.healpixGrid(),
|
||||
click(e) {
|
||||
let newVal = self.toggleCheckbox(self.hpxGridCheckbox);
|
||||
self.aladin.showHealpixGrid(newVal)
|
||||
}
|
||||
})
|
||||
self.reticleCheckbox = Input.checkbox({
|
||||
name: 'reticle',
|
||||
checked: this.aladin.isReticleDisplayed(),
|
||||
click(e) {
|
||||
let newVal = self.toggleCheckbox(self.reticleCheckbox);
|
||||
self.aladin.showReticle(newVal)
|
||||
}
|
||||
})
|
||||
|
||||
this.features = options && options.features;
|
||||
|
||||
let sampBtn = new SAMPActionButton({
|
||||
size: 'small',
|
||||
action(conn) {
|
||||
if (conn.isConnected()) {
|
||||
conn.unregister();
|
||||
} else {
|
||||
conn.register();
|
||||
}
|
||||
|
||||
self._hide()
|
||||
}
|
||||
}, aladin);
|
||||
this.sampBtn = sampBtn;
|
||||
|
||||
this.attach();
|
||||
}
|
||||
|
||||
attach() {
|
||||
let self = this;
|
||||
|
||||
const toggleFeature = (name) => {
|
||||
let feature = self.features[name];
|
||||
if(feature.isHidden) {
|
||||
feature._show();
|
||||
} else {
|
||||
feature._hide();
|
||||
}
|
||||
}
|
||||
|
||||
let reticle = self.aladin.getReticle();
|
||||
|
||||
let sliderReticleSize = Input.slider({
|
||||
name: 'reticleSize',
|
||||
type: 'range',
|
||||
min: 0.0,
|
||||
max: 50,
|
||||
value: reticle.getSize(),
|
||||
change(e) {
|
||||
reticle.update({size: e.target.value})
|
||||
}
|
||||
});
|
||||
|
||||
let options = [
|
||||
//ProjectionCtxMenu.getLayout(self.aladin),
|
||||
GridSettingsCtxMenu.getLayout(self.aladin),
|
||||
{
|
||||
label: {
|
||||
content: ['Reticle']
|
||||
},
|
||||
subMenu: [
|
||||
{
|
||||
label: {
|
||||
content: [self.reticleCheckbox, 'Show/Hide']
|
||||
},
|
||||
mustHide: false,
|
||||
action(o) {
|
||||
let newVal = self.toggleCheckbox(self.reticleCheckbox);
|
||||
self.aladin.showReticle(newVal)
|
||||
|
||||
self.attach();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [self.reticleColorInput, 'Color']
|
||||
},
|
||||
},
|
||||
{
|
||||
label: Layout.horizontal(['Size', sliderReticleSize]),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [self.backgroundColorInput, 'Back color']
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: 'Light/Dark mode'
|
||||
},
|
||||
action(o) {
|
||||
const currentTheme = self.aladin.aladinDiv.getAttribute("data-theme");
|
||||
const newTheme = currentTheme === "dark" ? "light" : "dark";
|
||||
self.aladin.aladinDiv.setAttribute("data-theme", newTheme);
|
||||
localStorage.setItem("theme", newTheme);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [self.hpxGridCheckbox, 'HEALPix grid']
|
||||
},
|
||||
mustHide: false,
|
||||
action(o) {
|
||||
let newVal = self.toggleCheckbox(self.hpxGridCheckbox);
|
||||
self.aladin.showHealpixGrid(newVal)
|
||||
|
||||
self.attach();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: [self.sampBtn, 'SAMP']
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Tools',
|
||||
subMenu: [
|
||||
{
|
||||
label: 'Stack',
|
||||
selected: !self.features['stack'].isHidden,
|
||||
action(o) {
|
||||
toggleFeature('stack')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Simbad',
|
||||
selected: !self.features['simbad'].isHidden,
|
||||
action(o) {
|
||||
toggleFeature('simbad');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Grid',
|
||||
selected: !self.features['grid'].isHidden,
|
||||
action(o) {
|
||||
toggleFeature('grid');
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: {
|
||||
icon: {
|
||||
monochrome: true,
|
||||
tooltip: {content: 'Documentation about Aladin Lite', position: {direction: 'top'}},
|
||||
url: helpIconBtn,
|
||||
size: 'small',
|
||||
cssStyle: {
|
||||
cursor: 'help',
|
||||
}
|
||||
},
|
||||
content: 'Help'
|
||||
},
|
||||
subMenu: [
|
||||
{
|
||||
label: 'Aladin Lite API',
|
||||
action(o) {
|
||||
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: {
|
||||
content: 'Contact us',
|
||||
tooltip: { content: 'For bug reports, discussions, feature ideas...', position: {direction: 'bottom'} }
|
||||
},
|
||||
subMenu: [
|
||||
{
|
||||
label: 'GitHub',
|
||||
action(o) {
|
||||
Utils.openNewTab('https://github.com/cds-astro/aladin-lite/issues')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'by email',
|
||||
action(o) {
|
||||
Utils.openNewTab('mailto:matthieu.baumann@astro.unistra.fr,thomas.boch@astro.unistra.fr?subject=Aladin Lite issue&body=message%20goes%20here')
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'General documentation',
|
||||
|
||||
action(o) {
|
||||
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: Layout.horizontal({layout: ['Examples'], tooltip: { content: 'How to embed Aladin Lite <br \>into your own webpages!', position: {direction: 'bottom'}}}),
|
||||
action(o) {
|
||||
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
super.attach(options);
|
||||
}
|
||||
|
||||
show(options) {
|
||||
this.attach();
|
||||
|
||||
this.position = (options && options.position) || this.position || { anchor: 'center center'};
|
||||
|
||||
super.show({
|
||||
position: this.position,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +83,9 @@ export class FoV extends DOMElement {
|
||||
'<div class="aladin-monospace-text"></div>'])
|
||||
}
|
||||
|
||||
let el = Layout.horizontal({layout});
|
||||
let el = Layout.horizontal(layout);
|
||||
if (el) {
|
||||
el.addClass('aladin-fov');
|
||||
el.addClass('aladin-dark-theme')
|
||||
}
|
||||
|
||||
super(el)
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
...options
|
||||
})
|
||||
|
||||
this.addClass('medium-sized');
|
||||
this.addClass('aladin-medium-sized');
|
||||
|
||||
self = this;
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@ import infoIconUrl from '../../../../assets/icons/info.svg';
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
|
||||
export class Dropdown extends Input {
|
||||
|
||||
// constructor
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
@@ -75,33 +74,70 @@ export class Dropdown extends Input {
|
||||
self.el.blur();
|
||||
});
|
||||
|
||||
options.options = options.options || [];
|
||||
options.autocomplete = {options: options.options || []};
|
||||
delete options.options;
|
||||
|
||||
super({
|
||||
type: 'text',
|
||||
//autocomplete: {options: options.options},
|
||||
actions: {
|
||||
focus(_) {
|
||||
self.removeClass('aladin-valid')
|
||||
self.removeClass('aladin-not-valid')
|
||||
},
|
||||
dblclick(e) {
|
||||
self.set('')
|
||||
|
||||
if (self.options.input) {
|
||||
self.options.input(e)
|
||||
}
|
||||
},
|
||||
input(e) {
|
||||
self.removeClass('aladin-valid')
|
||||
self.removeClass('aladin-not-valid')
|
||||
|
||||
if (e.data === undefined) {
|
||||
// select
|
||||
self.options.action(e)
|
||||
|
||||
let value = e.target.value;
|
||||
self.set('');
|
||||
|
||||
if (self.options.input) {
|
||||
self.options.input(e)
|
||||
}
|
||||
|
||||
self.set(value)
|
||||
} else {
|
||||
if (self.options.input) {
|
||||
self.options.input(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
keydown(e) {
|
||||
if (!e.key) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
// ignore navigation keys
|
||||
if (e.key === 'Enter') {
|
||||
self.options.action(e)
|
||||
}
|
||||
},
|
||||
},
|
||||
...options
|
||||
})
|
||||
this.el.classList.add('search')
|
||||
|
||||
self = this;
|
||||
this._addListeners(aladin);
|
||||
}
|
||||
|
||||
update(options) {
|
||||
let newOptions = {};
|
||||
|
||||
/*if (options && options.options) {
|
||||
newOptions['autocomplete'] = {options: options.options};
|
||||
|
||||
if (options.options) {
|
||||
options.autocomplete = {options: options.options || []};
|
||||
delete options.options;
|
||||
}*/
|
||||
}
|
||||
|
||||
// add the other input text options
|
||||
newOptions = {...newOptions, ...options};
|
||||
super.update(newOptions)
|
||||
}
|
||||
|
||||
_addListeners(aladin) {
|
||||
super.update(options)
|
||||
}
|
||||
};
|
||||
148
src/js/gui/Input/HiPSSelector.js
Normal file
148
src/js/gui/Input/HiPSSelector.js
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright 2013 - UDS/CNRS
|
||||
// The Aladin Lite program is distributed under the terms
|
||||
// of the GNU General Public License version 3.
|
||||
//
|
||||
// This file is part of Aladin Lite.
|
||||
//
|
||||
// Aladin Lite is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Aladin Lite is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// The GNU General Public License is available in COPYING file
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/Input/HiPSSelector.js
|
||||
*
|
||||
*
|
||||
* Author: Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
|
||||
export class HiPSSelector extends Input {
|
||||
static cachedHiPS = {}
|
||||
static objects = [];
|
||||
|
||||
// constructor
|
||||
constructor(options) {
|
||||
let surveys = [];
|
||||
for (var survey of Object.values(HiPSSelector.cachedHiPS)) {
|
||||
surveys.push({value: survey.id, label: survey.name});
|
||||
}
|
||||
surveys.sort((s1, s2) => {
|
||||
const s1l = s1.label.toLowerCase()
|
||||
const s2l = s2.label.toLowerCase()
|
||||
|
||||
if (s1l < s2l) {
|
||||
return -1;
|
||||
}
|
||||
if (s1l > s2l) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
let current = {};
|
||||
if (options.layer) {
|
||||
let id = options.layer.id;
|
||||
let name = options.layer.name;
|
||||
|
||||
current["value"] = id;
|
||||
current["label"] = name;
|
||||
|
||||
if (!surveys.some(item => item.value === id)) {
|
||||
surveys.push(current)
|
||||
}
|
||||
} else {
|
||||
current = surveys[0];
|
||||
}
|
||||
|
||||
current["title"] = current["label"];
|
||||
|
||||
surveys.push("More...")
|
||||
|
||||
super({
|
||||
type: "select",
|
||||
options: surveys,
|
||||
...current,
|
||||
...options
|
||||
})
|
||||
|
||||
self = this;
|
||||
|
||||
HiPSSelector.objects.push(self);
|
||||
}
|
||||
};
|
||||
|
||||
(function () {
|
||||
ALEvent.FAVORITE_HIPS_LIST_UPDATED.listenedBy(document.body, (event) => {
|
||||
let favoritesHips = event.detail;
|
||||
|
||||
HiPSSelector.cachedHiPS = {};
|
||||
|
||||
for (var hips of favoritesHips) {
|
||||
let key = hips.id || hips.url || hips.name;
|
||||
HiPSSelector.cachedHiPS[key] = hips;
|
||||
}
|
||||
|
||||
// Update the options of the selector
|
||||
let favoritesHiPS = []
|
||||
for(var hips of Object.values(HiPSSelector.cachedHiPS)) {
|
||||
favoritesHiPS.push({
|
||||
value: hips.id,
|
||||
label: hips.name
|
||||
})
|
||||
}
|
||||
|
||||
favoritesHiPS.sort((s1, s2) => {
|
||||
const s1l = s1.label.toLowerCase()
|
||||
const s2l = s2.label.toLowerCase()
|
||||
|
||||
if (s1l < s2l) {
|
||||
return -1;
|
||||
}
|
||||
if (s1l > s2l) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
for (var selector of HiPSSelector.objects) {
|
||||
// refers to an HiPS image survey
|
||||
let currentFavoriteHiPS = {
|
||||
value: selector.options.value,
|
||||
label: selector.options.label,
|
||||
};
|
||||
|
||||
let favoritesHiPSCopy = [...favoritesHiPS];
|
||||
|
||||
// Add the current hips to the selector as well, even if it has been manually
|
||||
// removed from the HiPSList
|
||||
if (!favoritesHiPSCopy.some(item => item.value === currentFavoriteHiPS.value)) {
|
||||
favoritesHiPSCopy.push(currentFavoriteHiPS)
|
||||
}
|
||||
|
||||
favoritesHiPSCopy.push("More...")
|
||||
|
||||
currentFavoriteHiPS["title"] = currentFavoriteHiPS["label"];
|
||||
|
||||
selector.update({
|
||||
...currentFavoriteHiPS,
|
||||
options: favoritesHiPSCopy
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -18,6 +18,7 @@
|
||||
//
|
||||
import { DOMElement } from "./Widgets/Widget";
|
||||
import { Tooltip } from "./Widgets/Tooltip";
|
||||
import { isJSObject } from "./Utils";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
@@ -34,23 +35,21 @@ import { Tooltip } from "./Widgets/Tooltip";
|
||||
export class Layout extends DOMElement {
|
||||
/**
|
||||
* Create a layout
|
||||
* @param {layout: Array.<DOMElement | String>, cssStyle: Object} options - Represents the structure of the Tabs
|
||||
* @param {layout: Array.<DOMElement | String>} layout - Represents the structure of the Tabs
|
||||
* @param {Object} options - Options object
|
||||
* @param {DOMElement} target - The parent element.
|
||||
* @param {String} position - The position of the tabs layout relative to the target.
|
||||
* For the list of possibilities, see https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
|
||||
*/
|
||||
constructor(options = {layout: []}, target, position = "beforeend") {
|
||||
constructor(layout, options, target, position = "beforeend") {
|
||||
let el = document.createElement('div');
|
||||
|
||||
// The user should also be able to give just a list of DOMElement
|
||||
if (options instanceof Array) {
|
||||
options['layout'] = options;
|
||||
}
|
||||
|
||||
options.layout = options.layout || [];
|
||||
layout = layout || [];
|
||||
super(el, options);
|
||||
|
||||
if (options.cssStyle) {
|
||||
this.layout = layout;
|
||||
|
||||
if (options && options.cssStyle) {
|
||||
this.setCss(options.cssStyle);
|
||||
}
|
||||
|
||||
@@ -58,17 +57,35 @@ export class Layout extends DOMElement {
|
||||
this.attachTo(target, position);
|
||||
|
||||
// 2. Once self is attached, attach the children
|
||||
if (options.layout) {
|
||||
if (typeof options.layout === 'string' || options.layout instanceof String) {
|
||||
this.el.innerHTML = options.layout;
|
||||
} else {
|
||||
if (typeof layout === 'string' || layout instanceof String) {
|
||||
this.el.innerHTML = layout;
|
||||
// otherwise it is an object
|
||||
} else if (
|
||||
isJSObject(layout)
|
||||
) {
|
||||
if (layout.start) {
|
||||
this.appendContent(new Layout(layout.start));
|
||||
}
|
||||
|
||||
if (layout.end) {
|
||||
this.appendContent(new Layout(layout.end));
|
||||
}
|
||||
|
||||
this.el.style.justifyContent = "space-between";
|
||||
} else if (Array.isArray(layout)) {
|
||||
// treat it as an array
|
||||
for (const item of options.layout) {
|
||||
for (let item of layout) {
|
||||
if (Array.isArray(item) || isJSObject(item)) {
|
||||
item = new Layout(item)
|
||||
}
|
||||
this.appendContent(item)
|
||||
}
|
||||
} else {
|
||||
const item = layout;
|
||||
this.appendContent(item)
|
||||
}
|
||||
|
||||
if (options.draggable) {
|
||||
if (options && options.draggable) {
|
||||
// retrieve the children and add the drag listeners
|
||||
let draggableFn = options.draggable;
|
||||
let firstSelected = null;
|
||||
@@ -108,43 +125,44 @@ export class Layout extends DOMElement {
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// The tooltip has to be set once the element
|
||||
// lies in the DOM
|
||||
if (options.tooltip) {
|
||||
if (options && options.tooltip) {
|
||||
Tooltip.add(options.tooltip, this)
|
||||
}
|
||||
|
||||
if (options.position) {
|
||||
if (options && options.position) {
|
||||
this.setPosition(options.position)
|
||||
}
|
||||
|
||||
if (options.orientation) {
|
||||
if (options.orientation === 'horizontal') {
|
||||
this.addClass('aladin-horizontal-list')
|
||||
} else {
|
||||
this.addClass('aladin-vertical-list')
|
||||
}
|
||||
if (options && options.vertical && options.vertical === true) {
|
||||
this.addClass('aladin-vertical-list')
|
||||
} else {
|
||||
this.addClass('aladin-horizontal-list')
|
||||
}
|
||||
|
||||
if (options.classList) {
|
||||
if (options && options.classList) {
|
||||
this.addClass(options.classList)
|
||||
}
|
||||
}
|
||||
|
||||
static horizontal(options, target, position = "beforeend") {
|
||||
let layout = new Layout(options, target, position);
|
||||
layout.addClass('aladin-horizontal-list');
|
||||
|
||||
return layout;
|
||||
static horizontal(layout, options, target, position = "beforeend") {
|
||||
return new Layout(layout, options, target, position);
|
||||
}
|
||||
|
||||
static vertical(options, target, position = "beforeend") {
|
||||
let layout = new Layout(options, target, position);
|
||||
layout.addClass('aladin-vertical-list');
|
||||
static nested(layout, options, target, position = "beforeend") {
|
||||
let horizontalLayout = new Layout(layout, options, target, position);
|
||||
horizontalLayout.removeClass('aladin-horizontal-list');
|
||||
|
||||
return layout;
|
||||
return horizontalLayout;
|
||||
}
|
||||
|
||||
static vertical(layout, options, target, position = "beforeend") {
|
||||
let verticalLayout = new Layout(layout, {...options, vertical: true}, target, position);
|
||||
verticalLayout.addClass('aladin-vertical-list');
|
||||
|
||||
return verticalLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +178,7 @@ export class Layout extends DOMElement {
|
||||
* @param {DOMElement} item - Represents the structure of the Tabs
|
||||
*/
|
||||
removeItem(item) {
|
||||
let arr = this.options.layout;
|
||||
let arr = this.layout;
|
||||
|
||||
var index = arr.indexOf(item);
|
||||
if (index > -1) {
|
||||
@@ -175,7 +193,7 @@ export class Layout extends DOMElement {
|
||||
* @param {DOMElement} item - Represents the structure of the Tabs
|
||||
*/
|
||||
appendLast(item) {
|
||||
this.insertItemAtIndex(item, this.options.layout.length);
|
||||
this.insertItemAtIndex(item, this.layout.length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +203,7 @@ export class Layout extends DOMElement {
|
||||
* For the list of possibilities, see https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
|
||||
*/
|
||||
insertItemAtIndex(item, index) {
|
||||
this.options.layout.splice(index, 0, item);
|
||||
this.layout.splice(index, 0, item);
|
||||
this._show();
|
||||
}
|
||||
|
||||
@@ -195,11 +213,7 @@ export class Layout extends DOMElement {
|
||||
*/
|
||||
empty() {
|
||||
// remove all the sub elements
|
||||
/*for (let elmt of this.options.layout) {
|
||||
elmt.remove();
|
||||
}*/
|
||||
|
||||
this.options.layout = [];
|
||||
this.layout = [];
|
||||
this._show();
|
||||
}
|
||||
|
||||
@@ -208,19 +222,19 @@ export class Layout extends DOMElement {
|
||||
this.el.innerHTML = "";
|
||||
|
||||
// apply css
|
||||
if (this.options.cssStyle) {
|
||||
if (this.options && this.options.cssStyle) {
|
||||
this.setCss(this.options.cssStyle);
|
||||
}
|
||||
|
||||
if (this.options.layout) {
|
||||
for (const item of this.options.layout) {
|
||||
if (this.layout) {
|
||||
for (const item of this.layout) {
|
||||
if (item) {
|
||||
this.appendContent(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.position) {
|
||||
if (this.options && this.options.position) {
|
||||
this.setPosition(this.options.position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,9 @@ export class Location extends DOMElement {
|
||||
autocomplete: 'off',
|
||||
autofocus: true,
|
||||
actions: {
|
||||
dblclick: (_) => {
|
||||
field.set('')
|
||||
},
|
||||
focus: (e) => {
|
||||
focused = true;
|
||||
},
|
||||
@@ -91,8 +94,6 @@ export class Location extends DOMElement {
|
||||
field.removeClass('aladin-valid'); // remove red border
|
||||
|
||||
if (e.key === 'Enter') {
|
||||
//field.el.blur();
|
||||
|
||||
let object = field.get();
|
||||
|
||||
field.update({placeholder: 'Resolving ' + object + '...'})
|
||||
@@ -120,7 +121,7 @@ export class Location extends DOMElement {
|
||||
value: parseCoo(),
|
||||
});
|
||||
|
||||
field.addClass("medium-sized")
|
||||
field.addClass("aladin-medium-sized")
|
||||
|
||||
let copyBtn = new ActionButton({
|
||||
icon: {
|
||||
@@ -135,12 +136,10 @@ export class Location extends DOMElement {
|
||||
})
|
||||
copyBtn.el.classList.add("aladin-location-copy");
|
||||
|
||||
let el = Layout.horizontal({
|
||||
layout: [
|
||||
copyBtn,
|
||||
field
|
||||
]
|
||||
})
|
||||
let el = Layout.horizontal([
|
||||
copyBtn,
|
||||
field
|
||||
])
|
||||
el.addClass('aladin-location');
|
||||
|
||||
super(el)
|
||||
|
||||
166
src/js/gui/Toolbar.js
Normal file
166
src/js/gui/Toolbar.js
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright 2023 - UDS/CNRS
|
||||
// The Aladin Lite program is distributed under the terms
|
||||
// of the GNU General Public License version 3.
|
||||
//
|
||||
// This file is part of Aladin Lite.
|
||||
//
|
||||
// Aladin Lite is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Aladin Lite is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// The GNU General Public License is available in COPYING file
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
import { Layout } from "./Layout";
|
||||
import { ActionButton } from "./Widgets/ActionButton";
|
||||
import { DOMElement } from "./Widgets/Widget";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/Widgets/layout/Horizontal.js
|
||||
*
|
||||
* A layout grouping widgets horizontaly
|
||||
*
|
||||
*
|
||||
* Author: Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
export class Toolbar extends Layout {
|
||||
/**
|
||||
* Create a layout
|
||||
* @param {Object[]} widgets - A list of predefined widgets
|
||||
* @param {Object} options - Options object
|
||||
* @param {DOMElement} target - The parent element.
|
||||
* @param {String} position - The position of the tabs layout relative to the target.
|
||||
* For the list of possibilities, see https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
|
||||
*/
|
||||
constructor(options, target) {
|
||||
let position = (options && options.position) || 'topleft';
|
||||
delete options.position;
|
||||
|
||||
super(
|
||||
[],
|
||||
options,
|
||||
target,
|
||||
)
|
||||
|
||||
console.log("options toolbar", options)
|
||||
|
||||
this.position = position;
|
||||
this.vertical = options && options.vertical === true;
|
||||
|
||||
this.toggled = null;
|
||||
this.widgets = {};
|
||||
}
|
||||
|
||||
// Close the toggled widget if the user clicks on another one
|
||||
_toggleOffWidget(widget) {
|
||||
if (this.toggled && this.toggled !== widget) {
|
||||
let canBeClosed = this.toggled && this.toggled.close;
|
||||
if (canBeClosed) {
|
||||
this.toggled.close();
|
||||
}
|
||||
|
||||
this.toggled = null;
|
||||
}
|
||||
}
|
||||
|
||||
has(name) {
|
||||
return name in this.widgets;
|
||||
}
|
||||
|
||||
enabled(name) {
|
||||
if (!this.has(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let widget = this.widgets[name];
|
||||
return widget.el.disabled === false;
|
||||
}
|
||||
|
||||
enable(name) {
|
||||
if (!this.has(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let widget = this.widgets[name];
|
||||
widget.update({disabled: false})
|
||||
}
|
||||
|
||||
disable(name) {
|
||||
if (!this.has(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let widget = this.widgets[name];
|
||||
widget.update({disabled: true})
|
||||
}
|
||||
|
||||
add(name, widget) {
|
||||
if (!(widget instanceof DOMElement)) {
|
||||
widget = new ActionButton(widget)
|
||||
}
|
||||
|
||||
switch (this.position) {
|
||||
case 'topleft':
|
||||
widget.update({openDirection: 'right'})
|
||||
this.update({position: {
|
||||
anchor: 'left top'
|
||||
}})
|
||||
break;
|
||||
case 'topright':
|
||||
widget.update({openDirection: 'left'})
|
||||
this.update({position: {
|
||||
anchor: 'right top'
|
||||
}})
|
||||
break;
|
||||
case 'bottomleft':
|
||||
widget.update({openDirection: 'top'})
|
||||
this.update({position: {
|
||||
anchor: 'left bottom'
|
||||
}})
|
||||
break;
|
||||
case 'bottomright':
|
||||
widget.update({openDirection: 'top right'})
|
||||
this.update({position: {
|
||||
anchor: 'right bottom'
|
||||
}})
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const action = widget.options.action;
|
||||
widget.update({
|
||||
action: (o) => {
|
||||
// toggle off the current toggled widget
|
||||
this._toggleOffWidget(widget)
|
||||
this.toggled = widget;
|
||||
|
||||
action(o)
|
||||
}
|
||||
})
|
||||
|
||||
this.widgets[name] = widget;
|
||||
|
||||
this.appendLast(widget);
|
||||
}
|
||||
|
||||
remove(name) {
|
||||
let widget = this.widgets[name];
|
||||
|
||||
if (this.toggled === widget)
|
||||
this.toggled = null;
|
||||
|
||||
this.removeItem(widget);
|
||||
|
||||
delete this.widgets[name];
|
||||
widget.remove()
|
||||
}
|
||||
}
|
||||
@@ -15,4 +15,10 @@ Element.prototype.swap = function (node) {
|
||||
|
||||
// Move `node` to before the sibling of `this`
|
||||
parent.insertBefore(node, sibling);
|
||||
};
|
||||
};
|
||||
|
||||
export function isJSObject(obj) {
|
||||
return obj !== null &&
|
||||
typeof obj === "object" &&
|
||||
obj.constructor === Object
|
||||
}
|
||||
@@ -21,6 +21,12 @@ import { DOMElement } from "./Widget";
|
||||
import { Tooltip } from "./Tooltip";
|
||||
import { Icon } from "./Icon";
|
||||
import { Layout } from "../Layout";
|
||||
|
||||
import infoIconUrl from "../../../../assets/icons/info.svg"
|
||||
import targetIconUrl from "../../../../assets/icons/target.svg";
|
||||
import removeIconUrl from "../../../../assets/icons/remove.svg";
|
||||
|
||||
import A from "../../A";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -48,7 +54,7 @@ import { Layout } from "../Layout";
|
||||
* @property {function} [opt.action] - The callback function to execute when the button is clicked.
|
||||
* @property {string} [opt.title] - The title attribute for the button.
|
||||
* @property {Object} [opt.icon] - An icon object for the button.
|
||||
* @property {boolean} [opt.disable=false] - Whether the button is initially disabled.
|
||||
* @property {boolean} [opt.disabled=false] - Whether the button is initially disabled.
|
||||
* @property {HTMLElement|string|Widget} [opt.content] - The content to be added to the button.
|
||||
* @property {CSSStyleSheet} [opt.cssStyle] - The CSS styles to apply to the button.
|
||||
* @property {Object} [opt.tooltip] - A tooltip.
|
||||
@@ -63,24 +69,25 @@ import { Layout } from "../Layout";
|
||||
*
|
||||
* @example
|
||||
* const actionButton = new ActionButton({
|
||||
* toggled: false,
|
||||
* action: (e) => { /* callback function * },
|
||||
* title: "Click me",
|
||||
* iconURL: "path/to/icon.png",
|
||||
* cssStyle: "color: red;",
|
||||
* tooltip: {
|
||||
* position: {
|
||||
* direction: 'left,
|
||||
* },
|
||||
* content: 'A tooltip'
|
||||
* },
|
||||
* position: { nextTo: someDOMElement, direction: 'right' }
|
||||
* }, document.getElementById('container'));
|
||||
size: 'small',
|
||||
content: '❌',
|
||||
//tooltip: {content: 'Close the window', position: {direction: 'bottom'}},
|
||||
action(e) {
|
||||
self._hide();
|
||||
},
|
||||
cssStyle: {
|
||||
position: 'absolute',
|
||||
},
|
||||
position: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
}
|
||||
});
|
||||
*/
|
||||
export class ActionButton extends DOMElement {
|
||||
constructor(options, target, position = "beforeend") {
|
||||
let el = document.createElement('button');
|
||||
el.classList.add('aladin-btn', 'aladin-dark-theme');
|
||||
el.classList.add('aladin-btn');
|
||||
|
||||
// add it to the dom
|
||||
super(el, options);
|
||||
@@ -100,9 +107,9 @@ export class ActionButton extends DOMElement {
|
||||
}
|
||||
|
||||
if (this.options.size === 'small') {
|
||||
this.addClass('small-sized-icon')
|
||||
this.addClass('aladin-small-sized-icon')
|
||||
} else if (this.options.size === 'medium') {
|
||||
this.addClass('medium-sized-icon')
|
||||
this.addClass('aladin-medium-sized-icon')
|
||||
}
|
||||
|
||||
if (this.options.action) {
|
||||
@@ -125,7 +132,7 @@ export class ActionButton extends DOMElement {
|
||||
layout.push(new Icon(this.options.icon));
|
||||
}
|
||||
|
||||
if (this.options.disable) {
|
||||
if (this.options.disabled) {
|
||||
this.el.disabled = true;
|
||||
this.addClass('disabled')
|
||||
} else {
|
||||
@@ -143,7 +150,7 @@ export class ActionButton extends DOMElement {
|
||||
if (layout.length === 1) {
|
||||
this.appendContent(layout[0])
|
||||
} else {
|
||||
this.appendContent(new Layout({layout, orientation: 'horizontal'}))
|
||||
this.appendContent(new Layout(layout))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,4 +195,118 @@ export class ActionButton extends DOMElement {
|
||||
|
||||
return new ActionButton(opt, target, position);
|
||||
}
|
||||
|
||||
static BUTTONS(aladin) {
|
||||
return {
|
||||
infoHiPS: (options) => {
|
||||
return new ActionButton({
|
||||
icon: {
|
||||
size: 'small',
|
||||
monochrome: true,
|
||||
url: infoIconUrl,
|
||||
},
|
||||
tooltip: {
|
||||
position: {direction: "top"},
|
||||
content: "More about that survey?"
|
||||
},
|
||||
action(e) {
|
||||
window.open(options && options.url);
|
||||
},
|
||||
...options
|
||||
})
|
||||
},
|
||||
targetHiPSLocation: (options) => {
|
||||
let ra = options && options.ra;
|
||||
let dec = options && options.dec;
|
||||
let fov = options && options.fov;
|
||||
return new ActionButton({
|
||||
icon: {
|
||||
size: 'small',
|
||||
monochrome: true,
|
||||
url: targetIconUrl,
|
||||
},
|
||||
disabled: ra === undefined || dec === undefined || fov === undefined,
|
||||
tooltip: {
|
||||
content: "Target interesting sky location",
|
||||
},
|
||||
action(e) {
|
||||
if (fov !== undefined && ra !== undefined && dec !== undefined) {
|
||||
aladin.setFoV(+fov)
|
||||
aladin.gotoObject(ra + ' ' + dec);
|
||||
}
|
||||
|
||||
},
|
||||
...options
|
||||
})
|
||||
},
|
||||
addMOC: (options) => {
|
||||
let name = options && options.name;
|
||||
let url = options && options.url;
|
||||
|
||||
let button = new ActionButton({
|
||||
size: "small",
|
||||
icon: {
|
||||
url: Icon.dataURLFromSVG({ svg: Icon.SVG_ICONS.MOC }),
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {
|
||||
content: "Add coverage",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
action: (e) => {
|
||||
// load the moc
|
||||
let moc = A.MOCFromURL(
|
||||
url,
|
||||
{ name },
|
||||
() => {
|
||||
if (aladin.statusBar) {
|
||||
aladin.statusBar.appendMessage({
|
||||
message:
|
||||
"Coverage of " +
|
||||
name +
|
||||
" loaded",
|
||||
duration: 2000,
|
||||
type: "info",
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
aladin.addMOC(moc);
|
||||
},
|
||||
...options
|
||||
})
|
||||
|
||||
return button;
|
||||
},
|
||||
remove: (action) => {
|
||||
return new ActionButton({
|
||||
icon: {
|
||||
url: removeIconUrl,
|
||||
monochrome: true,
|
||||
},
|
||||
size: "small",
|
||||
tooltip: {
|
||||
content: "Remove",
|
||||
},
|
||||
action
|
||||
})
|
||||
},
|
||||
close: (widget) => {
|
||||
return new ActionButton({
|
||||
size: 'small',
|
||||
content: '❌',
|
||||
action(_) {
|
||||
widget.close();
|
||||
},
|
||||
cssStyle: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
|
||||
import { DOMElement } from "./Widget";
|
||||
import { ActionButton } from "./ActionButton";
|
||||
import enlargeIconImg from '../../../../assets/icons/enlarge.svg';
|
||||
import moveIconImg from '../../../../assets/icons/move.svg';
|
||||
import { Layout } from "../Layout";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/Tab.js
|
||||
* File gui/Widgets/Box.js
|
||||
*
|
||||
* A context menu that shows when the user right clicks, or long touch on touch device
|
||||
*
|
||||
@@ -33,16 +34,6 @@ import { Layout } from "../Layout";
|
||||
* Author: Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/* Example of layout
|
||||
[{
|
||||
content: ''
|
||||
title: '',
|
||||
color: <label color>,
|
||||
backgroundColor: <background tab color>,
|
||||
action: () => {}
|
||||
},]
|
||||
*/
|
||||
export class Box extends DOMElement {
|
||||
constructor(options, target, position = "beforeend") {
|
||||
let el = document.createElement("div");
|
||||
@@ -52,7 +43,10 @@ export class Box extends DOMElement {
|
||||
|
||||
this.attachTo(target, position);
|
||||
this._show();
|
||||
this.addClass('aladin-dark-theme')
|
||||
}
|
||||
|
||||
close() {
|
||||
this._hide()
|
||||
}
|
||||
|
||||
_show(options) {
|
||||
@@ -63,26 +57,12 @@ export class Box extends DOMElement {
|
||||
|
||||
this.el.innerHTML = "";
|
||||
|
||||
let self = this;
|
||||
|
||||
let close = this.options.close === false ? false : true;
|
||||
let draggable = false;
|
||||
if (close) {
|
||||
new ActionButton({
|
||||
size: 'small',
|
||||
content: '❌',
|
||||
//tooltip: {content: 'Close the window', position: {direction: 'bottom'}},
|
||||
action(e) {
|
||||
self._hide();
|
||||
},
|
||||
cssStyle: {
|
||||
position: 'absolute',
|
||||
},
|
||||
position: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
}
|
||||
}, this.el);
|
||||
this.el.appendChild(
|
||||
ActionButton.BUTTONS(null).close(this).element()
|
||||
);
|
||||
}
|
||||
|
||||
if (this.options.onDragged) {
|
||||
@@ -97,7 +77,7 @@ export class Box extends DOMElement {
|
||||
titleEl = document.createElement('div')
|
||||
titleEl.classList.add("aladin-box-title");
|
||||
|
||||
DOMElement.appendTo(header.title, titleEl);
|
||||
DOMElement.appendTo(new Layout(header.title), titleEl);
|
||||
}
|
||||
|
||||
let draggableEl;
|
||||
@@ -120,7 +100,7 @@ export class Box extends DOMElement {
|
||||
});
|
||||
}
|
||||
|
||||
let headerEl = Layout.horizontal([draggableEl, titleEl], this.el);
|
||||
let headerEl = Layout.horizontal([draggableEl, titleEl], {}, this.el);
|
||||
if (draggable) {
|
||||
dragElement(headerEl.element(), this.el, this.options.onDragged);
|
||||
headerEl.element().style.cursor = 'move';
|
||||
@@ -137,7 +117,33 @@ export class Box extends DOMElement {
|
||||
|
||||
if (this.options.content) {
|
||||
let content = this.options.content
|
||||
this.appendContent(content);
|
||||
if (content instanceof Layout) {
|
||||
this.appendContent(content);
|
||||
} else {
|
||||
this.appendContent(Layout.vertical(content));
|
||||
}
|
||||
|
||||
this.el.lastChild.classList.add("aladin-box-content");
|
||||
}
|
||||
|
||||
if (this.options.sizeable) {
|
||||
let sizeableBtn = new ActionButton({
|
||||
icon: {
|
||||
url: enlargeIconImg,
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {content: 'Enlarge the window', global: true, aladin: this.aladin},
|
||||
cssStyle: {
|
||||
cursor: 'move',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0
|
||||
},
|
||||
});
|
||||
this.appendContent(sizeableBtn);
|
||||
|
||||
enlargeElement(sizeableBtn.element(), this.el);
|
||||
}
|
||||
|
||||
if (this.options.position) {
|
||||
@@ -216,3 +222,38 @@ function dragElement(triggerElt, elmnt, onDragged) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enlargeElement(triggerElt, elmnt) {
|
||||
let pos3 = 0, pos4 = 0;
|
||||
|
||||
triggerElt.onmousedown = dragMouseDown;
|
||||
|
||||
function dragMouseDown(e) {
|
||||
e.preventDefault();
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
document.onmouseup = closeDragElement;
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const dx = e.clientX - pos3;
|
||||
const dy = e.clientY - pos4;
|
||||
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
|
||||
const newWidth = elmnt.offsetWidth + 2*dx;
|
||||
const newHeight = elmnt.offsetHeight + 2*dy;
|
||||
|
||||
elmnt.style.width = Math.max(20, newWidth) + "px";
|
||||
elmnt.style.height = Math.max(20, newHeight) + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,13 +51,11 @@ export class ContextMenu extends DOMElement {
|
||||
|
||||
super(el, options);
|
||||
|
||||
this.addClass('aladin-dark-theme')
|
||||
|
||||
this.aladin = aladin;
|
||||
|
||||
this.cssStyleDefault = el.style;
|
||||
|
||||
if (!options || options.hideOnClick === undefined || options.hideOnClick === true || typeof options.hideOnClick === 'function') {
|
||||
/*if (!options || options.hideOnClick === undefined || options.hideOnClick === true || typeof options.hideOnClick === 'function') {
|
||||
this.aladin.aladinDiv.addEventListener('click', (e) => {
|
||||
if (!el.contains(e.target)) {
|
||||
if (options && options.hideOnClick && typeof options.hideOnClick === 'function') {
|
||||
@@ -67,7 +65,7 @@ export class ContextMenu extends DOMElement {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}*/
|
||||
|
||||
if (!options || options.hideOnResize === undefined || options.hideOnResize === true) {
|
||||
if (Utils.hasTouchScreen()) {
|
||||
@@ -176,7 +174,7 @@ export class ContextMenu extends DOMElement {
|
||||
tooltip = opt.label.tooltip
|
||||
}
|
||||
|
||||
let labelEl = Layout.horizontal({layout, tooltip});
|
||||
let labelEl = Layout.horizontal(layout, {tooltip});
|
||||
labelEl.attachTo(item)
|
||||
} else if (opt.disabled && opt.disabled.reason) {
|
||||
let tooltip = {
|
||||
@@ -184,7 +182,7 @@ export class ContextMenu extends DOMElement {
|
||||
position: {direction: 'top'}
|
||||
}
|
||||
|
||||
let labelEl = Layout.horizontal({layout: opt.label, tooltip});
|
||||
let labelEl = Layout.horizontal(opt.label, {tooltip});
|
||||
labelEl.attachTo(item)
|
||||
} else {
|
||||
let wrapEl = document.createElement('div');
|
||||
@@ -335,7 +333,7 @@ export class ContextMenu extends DOMElement {
|
||||
parent.style.display = "";
|
||||
}
|
||||
|
||||
show(options) {
|
||||
_show(options) {
|
||||
this.el.innerHTML = '';
|
||||
this.el.style = this.cssStyleDefault
|
||||
|
||||
@@ -365,13 +363,11 @@ export class ContextMenu extends DOMElement {
|
||||
super._show()
|
||||
}
|
||||
|
||||
attach(options) {
|
||||
this.menuOptions = options;
|
||||
}
|
||||
attach(options, toggler) {
|
||||
this._hide()
|
||||
this.setToggler(toggler)
|
||||
|
||||
/* Hide all the defined menus */
|
||||
static hideAll() {
|
||||
ContextMenu._menus.forEach((menu) => menu._hide())
|
||||
this.menuOptions = options;
|
||||
}
|
||||
|
||||
/// Context menu predefined items
|
||||
|
||||
@@ -142,7 +142,7 @@ export class Form extends DOMElement {
|
||||
groupLayout.push(input)
|
||||
});
|
||||
|
||||
let item = new Layout({layout: groupLayout});
|
||||
let item = new Layout(groupLayout, {vertical: true});
|
||||
item.addClass('aladin-form-group')
|
||||
|
||||
return item;
|
||||
|
||||
@@ -46,7 +46,7 @@ import { Tooltip } from "./Tooltip";
|
||||
* @property {function} [opt.action] - The callback function to execute when the button is clicked.
|
||||
* @property {string} [opt.title] - The title attribute for the button.
|
||||
* @property {string} [opt.iconURL] - The URL of the icon image for the button.
|
||||
* @property {boolean} [opt.disable=false] - Whether the button is initially disabled.
|
||||
* @property {boolean} [opt.disabled=false] - Whether the button is initially disabled.
|
||||
* @property {HTMLElement|string|Widget} [opt.content] - The content to be added to the button.
|
||||
* @property {CSSStyleSheet} [opt.cssStyle] - The CSS styles to apply to the button.
|
||||
* @property {string} [opt.tooltip] - The tooltip text for the button.
|
||||
@@ -82,7 +82,6 @@ export class Icon extends DOMElement {
|
||||
this._show();
|
||||
|
||||
this.addClass('aladin-icon')
|
||||
this.addClass('aladin-dark-theme')
|
||||
|
||||
this.attachTo(target, position)
|
||||
}
|
||||
@@ -91,9 +90,9 @@ export class Icon extends DOMElement {
|
||||
this.el.innerHTML = '';
|
||||
|
||||
if (this.options.size === 'small') {
|
||||
this.addClass('small-sized-icon')
|
||||
this.addClass('aladin-small-sized-icon')
|
||||
} else if (this.options.size === 'medium') {
|
||||
this.addClass('medium-sized-icon')
|
||||
this.addClass('aladin-medium-sized-icon')
|
||||
}
|
||||
|
||||
if (this.options.title) {
|
||||
@@ -107,7 +106,7 @@ export class Icon extends DOMElement {
|
||||
this.el.appendChild(img);
|
||||
}
|
||||
|
||||
if (this.options.disable) {
|
||||
if (this.options.disabled) {
|
||||
this.el.disabled = true;
|
||||
this.addClass('disabled')
|
||||
} else {
|
||||
@@ -119,7 +118,7 @@ export class Icon extends DOMElement {
|
||||
this.setCss(this.options.cssStyle);
|
||||
}
|
||||
|
||||
if (this.options.monochrome && this.options.monochrome === true) {
|
||||
if (this.options.monochrome === undefined || this.options.monochrome === true) {
|
||||
this.addClass('aladin-icon-monochrome');
|
||||
}
|
||||
|
||||
@@ -141,7 +140,8 @@ export class Icon extends DOMElement {
|
||||
static SVG_ICONS = {
|
||||
CATALOG: '<svg xmlns="http://www.w3.org/2000/svg"><polygon points="1,0,5,0,5,3,1,3" fill="FILLCOLOR" /><polygon points="7,0,9,0,9,3,7,3" fill="FILLCOLOR" /><polygon points="10,0,12,0,12,3,10,3" fill="FILLCOLOR" /><polygon points="13,0,15,0,15,3,13,3" fill="FILLCOLOR" /><polyline points="1,5,5,9" stroke="FILLCOLOR" /><polyline points="1,9,5,5" stroke="FILLCOLOR" /><line x1="7" y1="7" x2="15" y2="7" stroke="FILLCOLOR" stroke-width="2" /><polyline points="1,11,5,15" stroke="FILLCOLOR" /><polyline points="1,15,5,11" stroke="FILLCOLOR" /><line x1="7" y1="13" x2="15" y2="13" stroke="FILLCOLOR" stroke-width="2" /></svg>',
|
||||
MOC: '<svg xmlns="http://www.w3.org/2000/svg"><polyline points="0.5,7,2.5,7,2.5,5,7,5,7,3,10,3,10,5,13,5,13,7,15,7,15,9,13,9,13,12,10,12,10,14,7,14,7,12,2.5,12,2.5,10,0.5,10,0.5,7" stroke-width="1" stroke="FILLCOLOR" fill="transparent" /><line x1="1" y1="10" x2="6" y2="5" stroke="FILLCOLOR" stroke-width="0.5" /><line x1="2" y1="12" x2="10" y2="4" stroke="FILLCOLOR" stroke-width="0.5" /><line x1="5" y1="12" x2="12" y2="5" stroke="FILLCOLOR" stroke-width="0.5" /><line x1="7" y1="13" x2="13" y2="7" stroke="FILLCOLOR" stroke-width="0.5" /><line x1="10" y1="13" x2="13" y2="10" stroke="FILLCOLOR" stroke-width="0.5" /></svg>',
|
||||
OVERLAY: '<svg xmlns="http://www.w3.org/2000/svg"><polygon points="10,5,10,1,14,1,14,14,2,14,2,9,6,9,6,5" fill="transparent" stroke="FILLCOLOR" stroke-width="2"/></svg>'
|
||||
OVERLAY: '<svg xmlns="http://www.w3.org/2000/svg"><polygon points="10,5,10,1,14,1,14,14,2,14,2,9,6,9,6,5" fill="transparent" stroke="FILLCOLOR" stroke-width="2"/></svg>',
|
||||
COLOR: '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 112.75" style="enable-background:new 0 0 122.88 112.75" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#6BBE66;} .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FF4141;} .st2{fill-rule:evenodd;clip-rule:evenodd;fill:#00A1F1;}</style><g><path class="st0" d="M56.66,105.35c-5.94,4.6-13.4,7.34-21.5,7.34C15.74,112.69,0,96.95,0,77.53c0-13.47,7.58-25.17,18.7-31.07 c1.96,6.96,5.68,13.19,10.65,18.16c4.64,4.64,10.38,8.2,16.79,10.24c-0.06,0.9-0.09,1.81-0.09,2.73 C46.06,88.25,50.07,97.98,56.66,105.35L56.66,105.35z"/><path class="st1" d="M122.88,77.59c0,19.42-15.74,35.16-35.16,35.16S52.56,97,52.56,77.59c0-0.41,0.01-0.82,0.02-1.23 c2.03,0.3,4.11,0.46,6.23,0.46c11.5,0,21.92-4.66,29.46-12.2c5.45-5.45,9.4-12.41,11.17-20.19 C113.1,49.26,122.88,62.28,122.88,77.59L122.88,77.59z"/><path class="st2" d="M93.97,35.16c0,19.42-15.74,35.16-35.16,35.16S23.65,54.58,23.65,35.16S39.39,0,58.81,0 S93.97,15.74,93.97,35.16L93.97,35.16z"/></g></svg>'
|
||||
}
|
||||
|
||||
static dataURLFromSVG(icon) {
|
||||
@@ -150,9 +150,6 @@ export class Icon extends DOMElement {
|
||||
let elt = document.createElement('div');
|
||||
elt.innerHTML = str;
|
||||
|
||||
//elt.querySelector('svg').setAttribute('width', size);
|
||||
//elt.querySelector('svg').setAttribute('height', size);
|
||||
|
||||
elt.style.width = size;
|
||||
elt.style.height = size;
|
||||
|
||||
|
||||
@@ -92,7 +92,19 @@ export class Input extends DOMElement {
|
||||
let innerHTML = "";
|
||||
|
||||
for (const option of this.options.options) {
|
||||
innerHTML += "<option>" + option + "</option>";
|
||||
let value;
|
||||
let label;
|
||||
if (option.value) {
|
||||
value = option.value
|
||||
} else {
|
||||
value = option
|
||||
}
|
||||
if (option.label) {
|
||||
label = option.label
|
||||
} else {
|
||||
label = option
|
||||
}
|
||||
innerHTML += "<option value=\"" + value + "\">" + label + "</option>";
|
||||
}
|
||||
this.el.innerHTML = innerHTML;
|
||||
}
|
||||
@@ -330,7 +342,6 @@ export class Input extends DOMElement {
|
||||
}
|
||||
|
||||
this.el.classList.add('aladin-input');
|
||||
this.el.classList.add('aladin-dark-theme');
|
||||
|
||||
if (this.options.cssStyle) {
|
||||
this.setCss(this.options.cssStyle);
|
||||
|
||||
@@ -87,7 +87,7 @@ export class RadioButton extends DOMElement {
|
||||
}
|
||||
}
|
||||
|
||||
let el = Layout.horizontal({layout});
|
||||
let el = Layout.horizontal(layout);
|
||||
|
||||
super(el, options)
|
||||
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
// Copyright 2023 - UDS/CNRS
|
||||
// The Aladin Lite program is distributed under the terms
|
||||
// of the GNU General Public License version 3.
|
||||
//
|
||||
// This file is part of Aladin Lite.
|
||||
//
|
||||
// Aladin Lite is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Aladin Lite is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// The GNU General Public License is available in COPYING file
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
import { DOMElement } from "./Widget";
|
||||
import { FSM } from "../../FiniteStateMachine";
|
||||
import { ActionButton } from "./ActionButton";
|
||||
import { ContextMenu } from "./ContextMenu";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/Form.js
|
||||
*
|
||||
* A context menu that shows when the user right clicks, or long touch on touch device
|
||||
*
|
||||
*
|
||||
* Author: Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
Exemple of layout object
|
||||
{
|
||||
{
|
||||
label: "ID",
|
||||
type: "text",
|
||||
value: "the placeholder value...",
|
||||
},
|
||||
*/
|
||||
|
||||
/*
|
||||
options = {id: (btn option), id2: btn option, selected: id}
|
||||
*/
|
||||
export class SelectorButton extends DOMElement {
|
||||
/**
|
||||
* Create a layout
|
||||
* @param {{layout: {type: String, name: String, value: Number | String, placeholder: Number | String, change: Function } | {type: String, name: String, checked: Boolean, change: Function } | { type: String, name: String, value: String, options: Array.<String>, change: Function }, cssStyle: Object}} options - Represents the structure of the Tabs
|
||||
* @param {DOMElement} target - The parent element.
|
||||
* @param {String} position - The position of the tabs layout relative to the target.
|
||||
* For the list of possibilities, see https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
|
||||
*/
|
||||
constructor(options, aladin, target, position = 'beforeend') {
|
||||
let el;
|
||||
super(el, options)
|
||||
|
||||
this.aladin = aladin;
|
||||
|
||||
let self = this;
|
||||
let ctxMenu = new ContextMenu(this.aladin, {hideOnClick: false});
|
||||
|
||||
let openCtxMenuOnClick = (e) => {
|
||||
this.fsm.dispatch('closeCtxMenu')
|
||||
};
|
||||
const openCtxMenu = () => {
|
||||
this.aladin.aladinDiv.addEventListener('click', openCtxMenuOnClick)
|
||||
|
||||
let menuOptions = [];
|
||||
for (const id in this.options) {
|
||||
if (id === 'selected' || this.options.selected === id || id === 'tooltip') {
|
||||
continue;
|
||||
}
|
||||
let optSelect = this.options[id];
|
||||
|
||||
menuOptions.push({
|
||||
label: new ActionButton(optSelect),
|
||||
action(e) {
|
||||
if(optSelect.change) {
|
||||
optSelect.change(e)
|
||||
}
|
||||
|
||||
self.update({selected: id});
|
||||
self._show();
|
||||
|
||||
self.fsm.dispatch('closeCtxMenu')
|
||||
},
|
||||
cssStyle: {
|
||||
padding: "0",
|
||||
}
|
||||
})
|
||||
}
|
||||
ctxMenu.attach(menuOptions);
|
||||
ctxMenu.show({
|
||||
position: {
|
||||
nextTo: this.el,
|
||||
direction: 'bottom',
|
||||
}
|
||||
})
|
||||
};
|
||||
const closeCtxMenu = () => {
|
||||
this.aladin.aladinDiv.removeEventListener('click', openCtxMenuOnClick)
|
||||
ctxMenu._hide();
|
||||
};
|
||||
|
||||
this.fsm = new FSM({
|
||||
state: 'init',
|
||||
transitions: {
|
||||
init: {
|
||||
openCtxMenu
|
||||
},
|
||||
openCtxMenu: {
|
||||
closeCtxMenu
|
||||
},
|
||||
closeCtxMenu: {
|
||||
openCtxMenu
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
this._show();
|
||||
}
|
||||
|
||||
_hide() {
|
||||
this.fsm.dispatch('closeCtxMenu');
|
||||
super._hide()
|
||||
}
|
||||
|
||||
_show() {
|
||||
let self = this;
|
||||
|
||||
// remove from the DOM tree
|
||||
const selectedId = this.options.selected;
|
||||
|
||||
let {target, position} = this.remove();
|
||||
|
||||
this.el = new ActionButton({
|
||||
...this.options[selectedId],
|
||||
action: (e) => {
|
||||
if (self.fsm.state === 'openCtxMenu') {
|
||||
self.fsm.dispatch('closeCtxMenu');
|
||||
} else {
|
||||
self.fsm.dispatch('openCtxMenu');
|
||||
}
|
||||
}
|
||||
}).element();
|
||||
|
||||
// Reattach it at the same position
|
||||
this.attachTo(target, position)
|
||||
}
|
||||
}
|
||||
@@ -57,13 +57,13 @@ export class Tabs extends DOMElement {
|
||||
this.tabSelectedIdx = 0;
|
||||
|
||||
let tabs = this.buildTabs(options);
|
||||
this.el = new Layout({
|
||||
layout: [
|
||||
new Layout({layout: tabs.layout, orientation: 'horizontal'}),
|
||||
this.el = Layout.nested(
|
||||
[
|
||||
tabs.layout,
|
||||
tabs.content
|
||||
],
|
||||
classList: "aladin-table"
|
||||
}).element();
|
||||
{ classList: "aladin-table" }
|
||||
).element();
|
||||
|
||||
this._show();
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ export class Table extends DOMElement {
|
||||
|
||||
super(el, options);
|
||||
this.attachTo(target, position);
|
||||
|
||||
this.addClass("aladin-dark-theme")
|
||||
}
|
||||
|
||||
static _createTableBody = function(options) {
|
||||
|
||||
@@ -50,8 +50,7 @@ export class Tooltip extends DOMElement {
|
||||
}
|
||||
options.position.anchor = target;
|
||||
|
||||
|
||||
if (!options.delayShowUpTime) {
|
||||
if (options.delayShowUpTime === undefined) {
|
||||
options.delayShowUpTime = 500;
|
||||
}
|
||||
|
||||
@@ -76,8 +75,6 @@ export class Tooltip extends DOMElement {
|
||||
|
||||
super(wrapperEl, options)
|
||||
|
||||
this.element().classList.add('aladin-dark-theme')
|
||||
|
||||
this._show();
|
||||
}
|
||||
|
||||
@@ -176,6 +173,8 @@ export class Tooltip extends DOMElement {
|
||||
return this.el.querySelector('.aladin-tooltip');
|
||||
}
|
||||
|
||||
static hoveredEl = null;
|
||||
|
||||
static add(options, target) {
|
||||
if (target) {
|
||||
if (target.tooltip) {
|
||||
@@ -188,13 +187,42 @@ export class Tooltip extends DOMElement {
|
||||
|
||||
let targetEl = target.element()
|
||||
|
||||
if (options.mouse) {
|
||||
let tooltip = options.aladin && options.aladin.tooltip;
|
||||
|
||||
Utils.on(targetEl, 'mousemove', (e) => {
|
||||
tooltip.style.left = e.clientX + 12 + 'px';
|
||||
tooltip.style.top = e.clientY + 12 + 'px';
|
||||
});
|
||||
|
||||
Utils.on(targetEl, 'mouseover', (e) => {
|
||||
if (Tooltip.hoveredEl && Tooltip.hoveredEl.contains(targetEl))
|
||||
return;
|
||||
|
||||
Tooltip.hoveredEl = targetEl;
|
||||
// Change the content to match
|
||||
tooltip.innerHTML = options.content;
|
||||
tooltip.style.display = 'block';
|
||||
});
|
||||
|
||||
Utils.on(targetEl, 'mouseleave', (e) => {
|
||||
if (Tooltip.hoveredEl && Tooltip.hoveredEl.contains(targetEl) && Tooltip.hoveredEl !== targetEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
tooltip.style.display = 'none';
|
||||
Tooltip.hoveredEl = null;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.global) {
|
||||
let statusBar = options.aladin && options.aladin.statusBar;
|
||||
if (!statusBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
// handle global tooltip div display
|
||||
Utils.on(targetEl, 'mouseover', (e) => {
|
||||
statusBar.removeMessage('tooltip')
|
||||
statusBar.appendMessage({
|
||||
|
||||
@@ -21,6 +21,9 @@ import { DOMElement } from "./Widget";
|
||||
import { Icon } from "./Icon";
|
||||
import folderIconUrl from "../../../../assets/icons/folder.svg";
|
||||
|
||||
import { Layout } from "../Layout";
|
||||
import { ActionButton } from "./ActionButton";
|
||||
import { Input } from "./Input";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -40,6 +43,10 @@ export class Tree extends DOMElement {
|
||||
super(el, options);
|
||||
|
||||
this.click = options && options.click;
|
||||
this.dblclick = options && options.dblclick;
|
||||
this.aladin = options && options.aladin;
|
||||
|
||||
this.onlyInView = false;
|
||||
|
||||
let rootNode = options && options.root || {};
|
||||
this.params = null;
|
||||
@@ -48,9 +55,9 @@ export class Tree extends DOMElement {
|
||||
|
||||
this._setRoot(rootNode);
|
||||
|
||||
|
||||
this.attachTo(target, position);
|
||||
this._show();
|
||||
this.addClass('aladin-dark-theme')
|
||||
}
|
||||
|
||||
_setRoot(root) {
|
||||
@@ -100,8 +107,6 @@ export class Tree extends DOMElement {
|
||||
directoryLinks.reverse()
|
||||
|
||||
let directoryListEl = document.createElement('div');
|
||||
directoryListEl.classList.add('aladin-directory-path');
|
||||
directoryListEl.style.display = "inline-block"
|
||||
|
||||
for (var link of directoryLinks) {
|
||||
directoryListEl.appendChild(link);
|
||||
@@ -112,11 +117,79 @@ export class Tree extends DOMElement {
|
||||
directoryListEl.appendChild(spanSplitEl)
|
||||
}
|
||||
|
||||
this.el.appendChild(directoryListEl)
|
||||
let self = this;
|
||||
this.el.appendChild(
|
||||
new Layout({
|
||||
start: [directoryListEl],
|
||||
end: [
|
||||
Input.checkbox({
|
||||
name: "filter-out-not-in-view",
|
||||
tooltip: { content: "Mask data not in the view", position: {direction: "bottom"} },
|
||||
checked: this.onlyInView,
|
||||
click(e) {
|
||||
self.onlyInView = e.target.checked;
|
||||
|
||||
self._createDOM(self.curNode)
|
||||
},
|
||||
})
|
||||
]
|
||||
}, {classList: 'aladin-directory-path'}).element()
|
||||
)
|
||||
|
||||
let listElt = document.createElement('ul');
|
||||
|
||||
for (const label of Object.keys(node).sort()) {
|
||||
let seekMinEmInNode = (n) => {
|
||||
const isLeaf = typeof n === 'object' && 'ID' in n;
|
||||
|
||||
if (isLeaf) {
|
||||
return (+n.em_min)
|
||||
} else if (typeof n === 'object') {
|
||||
let min = Number.POSITIVE_INFINITY;
|
||||
|
||||
for (var [key, child] of Object.entries(n)) {
|
||||
if (key === "parent" || key === "label") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let val = seekMinEmInNode(child);
|
||||
if (Number.isFinite(val)) {
|
||||
min = Math.min(val, min);
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
} else {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
};
|
||||
|
||||
let labels = Object.keys(node).sort((la, lb) => {
|
||||
let na = node[la];
|
||||
let nb = node[lb];
|
||||
|
||||
let aIsLeaf = typeof na === "object" && 'ID' in na;
|
||||
let bIsLeaf = typeof nb === "object" && 'ID' in nb;
|
||||
|
||||
if (aIsLeaf !== bIsLeaf) {
|
||||
return aIsLeaf - bIsLeaf;
|
||||
} else if (typeof na === "object" && typeof nb === "object") {
|
||||
let emNa = seekMinEmInNode(na)
|
||||
let emNb = seekMinEmInNode(nb)
|
||||
|
||||
if (emNa > emNb) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else if (la < lb) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
});
|
||||
|
||||
let noEltsListed = true;
|
||||
for (const label of labels) {
|
||||
if (label !== 'parent' && label !== "label") {
|
||||
let elt = document.createElement('li');
|
||||
// points towards the parent node
|
||||
@@ -126,10 +199,88 @@ export class Tree extends DOMElement {
|
||||
if(this.params && this.filter && !this.filter(child, this.params)) {
|
||||
elt.style.display = "none";
|
||||
} else {
|
||||
elt.style.display = "block";
|
||||
elt.style.display = "";
|
||||
noEltsListed = false;
|
||||
}
|
||||
|
||||
elt.innerHTML = this.label(child);
|
||||
let label = this.label(child);
|
||||
let layout = {start: [label], end: []};
|
||||
|
||||
if (child.dataproduct_subtype === "color") {
|
||||
layout.end.push(new Icon({
|
||||
size: "small",
|
||||
url: Icon.dataURLFromSVG({ svg: Icon.SVG_ICONS.COLOR }),
|
||||
}))
|
||||
}
|
||||
|
||||
layout.end.push(ActionButton.BUTTONS(this.aladin)
|
||||
.infoHiPS({
|
||||
url: child.hips_service_url,
|
||||
tooltip: {
|
||||
aladin: this.aladin,
|
||||
global: true,
|
||||
content: "More info on the survey ?",
|
||||
},
|
||||
}).element()
|
||||
)
|
||||
|
||||
layout.end = layout.end.concat([
|
||||
ActionButton.BUTTONS(this.aladin)
|
||||
.targetHiPSLocation({
|
||||
ra: child.hips_initial_ra,
|
||||
dec: child.hips_initial_dec,
|
||||
fov: child.hips_initial_fov,
|
||||
tooltip: {
|
||||
aladin: this.aladin,
|
||||
global: true,
|
||||
content: "Move to an interesting location",
|
||||
},
|
||||
})
|
||||
.element(),
|
||||
ActionButton.BUTTONS(this.aladin)
|
||||
.addMOC({
|
||||
name: label,
|
||||
url: child.hips_service_url + '/Moc.fits',
|
||||
tooltip: {
|
||||
aladin: this.aladin,
|
||||
global: true,
|
||||
content: "Click to add its coverage",
|
||||
},
|
||||
})
|
||||
.element(),
|
||||
])
|
||||
|
||||
let childElt = new Layout(
|
||||
layout,
|
||||
{
|
||||
vertical: false,
|
||||
tooltip: {
|
||||
content: '<figure class="aladin-fig"><img ' +
|
||||
`src="${child.hips_service_url + "/preview.jpg"}"` +
|
||||
`alt="${label}" />` +
|
||||
`<figcaption>${label}</figcaption>` +
|
||||
'</figure>',
|
||||
mouse: true,
|
||||
aladin: this.aladin,
|
||||
}
|
||||
}).element();
|
||||
|
||||
if (this.highlight) {
|
||||
if(this.highlight.includes(child.ID)) {
|
||||
childElt.classList.add("aladin-valid");
|
||||
childElt.classList.remove("aladin-not-found");
|
||||
} else {
|
||||
childElt.classList.remove("aladin-valid");
|
||||
childElt.classList.add("aladin-not-found");
|
||||
|
||||
if (this.onlyInView) {
|
||||
childElt.style.display = "none";
|
||||
} else {
|
||||
childElt.style.display = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
elt.appendChild(childElt);
|
||||
} else {
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
@@ -138,16 +289,34 @@ export class Tree extends DOMElement {
|
||||
let numTotal = this.numChildMatchingFilter(child, false);
|
||||
|
||||
let name = label;
|
||||
elt.innerHTML = name + ` (${numFilteringMatching}/${numTotal})`
|
||||
elt.appendChild(Layout.horizontal([
|
||||
new Icon({
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
url: folderIconUrl,
|
||||
}),
|
||||
name + ` (${numFilteringMatching}/${numTotal})`
|
||||
]).element())
|
||||
|
||||
if (numFilteringMatching == 0) {
|
||||
elt.style.display = "none";
|
||||
} else {
|
||||
elt.style.display = "block";
|
||||
elt.style.display = "";
|
||||
noEltsListed = false;
|
||||
}
|
||||
}
|
||||
|
||||
elt.style.color = this.hasChildLocatedInFov(child) ? 'yellowgreen' : 'orange';
|
||||
if(this.hasChildLocatedInFov(child)) {
|
||||
elt.classList.add("aladin-valid");
|
||||
elt.classList.remove("aladin-not-found");
|
||||
} else {
|
||||
elt.classList.remove("aladin-valid");
|
||||
elt.classList.add("aladin-not-found");
|
||||
|
||||
if (this.onlyInView) {
|
||||
elt.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
child.label = label;
|
||||
child.parent = node;
|
||||
@@ -163,12 +332,21 @@ export class Tree extends DOMElement {
|
||||
this._createDOM(child);
|
||||
}
|
||||
})
|
||||
elt.addEventListener('dblclick', (e) => {
|
||||
if (isLeaf) {
|
||||
this.dblclick(child)
|
||||
}
|
||||
})
|
||||
|
||||
listElt.appendChild(elt)
|
||||
}
|
||||
}
|
||||
|
||||
this.el.appendChild(listElt);
|
||||
if (noEltsListed && this.curNode !== this.root) {
|
||||
this.navigate(1)
|
||||
} else {
|
||||
this.el.appendChild(listElt);
|
||||
}
|
||||
}
|
||||
|
||||
setHierarchy(root) {
|
||||
@@ -188,44 +366,7 @@ export class Tree extends DOMElement {
|
||||
highlightNodes(highlight) {
|
||||
this.highlight = highlight
|
||||
|
||||
let elts = this.el.querySelectorAll("li");
|
||||
let i = 0;
|
||||
|
||||
for (const label of Object.keys(this.curNode).sort()) {
|
||||
if (label !== 'parent' && label !== "label") {
|
||||
let elt = elts[i];
|
||||
i += 1;
|
||||
// points towards the parent node
|
||||
let child = this.curNode[label];
|
||||
let isLeaf = typeof child === "object" && 'ID' in child;
|
||||
if (isLeaf) {
|
||||
// Check if its ID is found in the view
|
||||
if (this.highlight) {
|
||||
elt.style.color = this.highlight.includes(child.ID) ? 'yellowgreen' : 'orange';
|
||||
}
|
||||
} else {
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
// * the number of children matching the filter params
|
||||
elt.style.color = this.hasChildLocatedInFov(child) ? 'yellowgreen' : 'orange';
|
||||
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
// * the number of children matching the filter params
|
||||
let numFilteringMatching = this.numChildMatchingFilter(child, true);
|
||||
let numTotal = this.numChildMatchingFilter(child, false);
|
||||
|
||||
let name = elt.innerText.split('(');
|
||||
elt.innerHTML = name[0] + ` (${numFilteringMatching}/${numTotal})`
|
||||
|
||||
if (numFilteringMatching == 0) {
|
||||
elt.style.display = "none";
|
||||
} else {
|
||||
elt.style.display = "block";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this._createDOM(this.curNode);
|
||||
}
|
||||
|
||||
// Set params to null, undefined or {} to disable the filtering
|
||||
@@ -236,39 +377,7 @@ export class Tree extends DOMElement {
|
||||
|
||||
this.params = params;
|
||||
|
||||
let elts = this.el.querySelectorAll("li");
|
||||
let i = 0;
|
||||
|
||||
for (const label of Object.keys(this.curNode).sort()) {
|
||||
if (label !== 'parent' && label !== "label") {
|
||||
let elt = elts[i];
|
||||
i += 1;
|
||||
// points towards the parent node
|
||||
let child = this.curNode[label];
|
||||
let isLeaf = typeof child === "object" && 'ID' in child;
|
||||
if (isLeaf) {
|
||||
if(this.params && this.filter && !this.filter(child, this.params)) {
|
||||
elt.style.display = "none"
|
||||
} else {
|
||||
elt.style.display = "block"
|
||||
}
|
||||
} else {
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
// * the number of children matching the filter params
|
||||
let numFilteringMatching = this.numChildMatchingFilter(child, true);
|
||||
let numTotal = this.numChildMatchingFilter(child, false);
|
||||
|
||||
let name = elt.innerText.split('(');
|
||||
elt.innerHTML = name[0] + ` (${numFilteringMatching}/${numTotal})`
|
||||
if (numFilteringMatching == 0) {
|
||||
elt.style.display = "none";
|
||||
} else {
|
||||
elt.style.display = "block";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this._createDOM(this.curNode);
|
||||
}
|
||||
|
||||
hasChildLocatedInFov(node) {
|
||||
@@ -282,12 +391,12 @@ export class Tree extends DOMElement {
|
||||
|
||||
let isLeaf = typeof node === "object" && 'ID' in node;
|
||||
if (isLeaf) {
|
||||
if (this.highlight.includes(node.ID)) {
|
||||
if (this.highlight.includes(node.ID) && this.params && this.filter && this.filter(node, this.params)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
for (const label of Object.keys(node).sort()) {
|
||||
if (label === "parent")
|
||||
for (const label of Object.keys(node)) {
|
||||
if (label === "parent" || label === "label")
|
||||
continue;
|
||||
|
||||
let child = node[label];
|
||||
@@ -314,7 +423,7 @@ export class Tree extends DOMElement {
|
||||
}
|
||||
} else {
|
||||
let num = 0;
|
||||
for (const label of Object.keys(node).sort()) {
|
||||
for (const label of Object.keys(node)) {
|
||||
if (label === "parent")
|
||||
continue;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
//
|
||||
|
||||
import { Utils } from "../../Utils";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -47,28 +46,6 @@ export class DOMElement {
|
||||
this.options = options;
|
||||
this.name = options && options.name || Utils.uuidv4()
|
||||
this.isHidden = true;
|
||||
|
||||
/*this.el.addEventListener("mouseup", (e) => {
|
||||
var wasDragging = view.realDragging === true;
|
||||
|
||||
if (view.dragging) { // if we were dragging, reset to default cursor
|
||||
if(view.mode === View.PAN) {
|
||||
view.setCursor('default');
|
||||
}
|
||||
|
||||
view.dragging = false;
|
||||
if (wasDragging) {
|
||||
view.realDragging = false;
|
||||
|
||||
// call the positionChanged once more with a dragging = false
|
||||
view.throttledPositionChanged(false);
|
||||
}
|
||||
|
||||
if (view.spectraDisplayer) {
|
||||
view.spectraDisplayer.enableInteraction();
|
||||
}
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
element() {
|
||||
@@ -119,14 +96,19 @@ export class DOMElement {
|
||||
static appendTo(elmt, parent) {
|
||||
if(elmt) {
|
||||
// Append the updated content
|
||||
if (elmt instanceof DOMElement) {
|
||||
if (Array.isArray(elmt)) {
|
||||
for (var elt of elmt) {
|
||||
DOMElement.appendTo(elt, parent)
|
||||
}
|
||||
} else if (elmt instanceof DOMElement) {
|
||||
elmt.attachTo(parent)
|
||||
} else if (elmt instanceof Element) {
|
||||
parent.insertAdjacentElement('beforeend', elmt);
|
||||
} else {
|
||||
let wrapEl = document.createElement('div');
|
||||
wrapEl.innerHTML = elmt;
|
||||
parent.insertAdjacentElement('beforeend', wrapEl);
|
||||
const template = document.createElement('template');
|
||||
template.innerHTML = elmt;
|
||||
|
||||
parent.append(template.content.cloneNode(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,9 +213,11 @@ export class DOMElement {
|
||||
let aDivRect = aladinDiv.getBoundingClientRect();
|
||||
const offViewX = aDivRect.x;
|
||||
const offViewY = aDivRect.y;
|
||||
|
||||
if (!dir) {
|
||||
// determine the direction with respect to the element given
|
||||
let elX = options.nextTo.el.getBoundingClientRect().left + options.nextTo.el.getBoundingClientRect().width * 0.5 - offViewX;
|
||||
const nextElementRect = nextTo.el.getBoundingClientRect();
|
||||
let elX = nextElementRect.left + nextElementRect.width * 0.5 - offViewX;
|
||||
dir = (elX < innerWidth / 2) ? 'right' : 'left';
|
||||
}
|
||||
|
||||
@@ -242,23 +226,28 @@ export class DOMElement {
|
||||
}
|
||||
|
||||
let rect = nextTo.getBoundingClientRect();
|
||||
this.el.classList.remove('left', 'right', 'top', 'bottom');
|
||||
|
||||
switch (dir) {
|
||||
case 'left':
|
||||
left = rect.x - offsetWidth - offViewX;
|
||||
left = rect.x - offViewX;
|
||||
top = rect.y - offViewY;
|
||||
this.el.classList.add('left');
|
||||
break;
|
||||
case 'right':
|
||||
left = rect.x + rect.width - offViewX;
|
||||
top = rect.y - offViewY;
|
||||
this.el.classList.add('right');
|
||||
break;
|
||||
case 'top':
|
||||
left = rect.x - offViewX;
|
||||
top = rect.y - offsetHeight - offViewY;
|
||||
top = rect.y - offViewY;
|
||||
this.el.classList.add('top');
|
||||
break;
|
||||
case 'bottom':
|
||||
left = rect.x - offViewX;
|
||||
top = rect.y + rect.height - offViewY;
|
||||
this.el.classList.add('bottom');
|
||||
break;
|
||||
default:
|
||||
left = 0;
|
||||
@@ -268,11 +257,11 @@ export class DOMElement {
|
||||
|
||||
// Translate if the div in
|
||||
if (typeof top === 'number') {
|
||||
if (top + offsetHeight >= innerHeight) {
|
||||
/*if (top + offsetHeight >= innerHeight) {
|
||||
y = '-' + (top + offsetHeight - innerHeight) + 'px';
|
||||
} else if (top < 0) {
|
||||
y = Math.abs(top) + 'px';
|
||||
}
|
||||
}*/
|
||||
|
||||
top = top + 'px';
|
||||
}
|
||||
@@ -280,11 +269,11 @@ export class DOMElement {
|
||||
bottom = bottom + 'px';
|
||||
}
|
||||
if (typeof left === 'number') {
|
||||
if (left + offsetWidth > innerWidth) {
|
||||
/*if (left + offsetWidth > innerWidth) {
|
||||
x = '-' + (left + offsetWidth - innerWidth) + 'px';
|
||||
} else if (left < 0) {
|
||||
x = Math.abs(left) + 'px';
|
||||
}
|
||||
}*/
|
||||
|
||||
left = left + 'px';
|
||||
}
|
||||
@@ -316,12 +305,24 @@ export class DOMElement {
|
||||
}
|
||||
}
|
||||
|
||||
setToggler(toggler) {
|
||||
this.toggler = toggler;
|
||||
}
|
||||
|
||||
_show() {
|
||||
if (this.toggler) {
|
||||
this.toggler.notify(true)
|
||||
}
|
||||
|
||||
this.el.style.display = ""
|
||||
this.isHidden = false;
|
||||
}
|
||||
|
||||
_hide() {
|
||||
if (this.toggler) {
|
||||
this.toggler.notify(false)
|
||||
}
|
||||
|
||||
this.isHidden = true;
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ export let Circle = (function() {
|
||||
return;
|
||||
}
|
||||
this.isHovered = true;
|
||||
this.setLineWidth(this.getLineWidth() + 2)
|
||||
if (this.overlay) {
|
||||
this.overlay.reportChange();
|
||||
}
|
||||
@@ -169,6 +170,8 @@ export let Circle = (function() {
|
||||
return;
|
||||
}
|
||||
this.isHovered = false;
|
||||
this.setLineWidth(this.getLineWidth() - 2)
|
||||
|
||||
if (this.overlay) {
|
||||
this.overlay.reportChange();
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ export let Ellipse = (function() {
|
||||
return;
|
||||
}
|
||||
this.isHovered = true;
|
||||
this.setLineWidth(this.getLineWidth() + 2)
|
||||
if (this.overlay) {
|
||||
this.overlay.reportChange();
|
||||
}
|
||||
@@ -174,6 +175,7 @@ export let Ellipse = (function() {
|
||||
return;
|
||||
}
|
||||
this.isHovered = false;
|
||||
this.setLineWidth(this.getLineWidth() - 2)
|
||||
if (this.overlay) {
|
||||
this.overlay.reportChange();
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ export let Polyline = (function() {
|
||||
return;
|
||||
}
|
||||
this.isHovered = true;
|
||||
this.setLineWidth(this.getLineWidth() + 2)
|
||||
if (this.overlay) {
|
||||
this.overlay.reportChange();
|
||||
}
|
||||
@@ -159,6 +160,7 @@ export let Polyline = (function() {
|
||||
return;
|
||||
}
|
||||
this.isHovered = false;
|
||||
this.setLineWidth(this.getLineWidth() - 2)
|
||||
if (this.overlay) {
|
||||
this.overlay.reportChange();
|
||||
}
|
||||
@@ -456,51 +458,111 @@ export let Polyline = (function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline.prototype.intersectsBBox = function(x, y, w, h, view) {
|
||||
for (let i = 0; i < this.raDecArray.length - 1; i++) {
|
||||
let p1 = this.raDecArray[i];
|
||||
let p2 = this.raDecArray[i + 1];
|
||||
Polyline.prototype.intersectsBBox = function (x, y, w, h, view) {
|
||||
let n = this.raDecArray.length;
|
||||
if (n < 2) return false;
|
||||
|
||||
let xy1 = view.aladin.world2pix(p1[0], p1[1]);
|
||||
let xy2 = view.aladin.world2pix(p2[0], p2[1]);
|
||||
// 2️⃣ Edge intersection test
|
||||
let i = this.closed ? n - 1 : 0;
|
||||
let j = this.closed ? 0 : 1;
|
||||
|
||||
let poly = [];
|
||||
while (j < n) {
|
||||
const p1 = this.raDecArray[i];
|
||||
const p2 = this.raDecArray[j];
|
||||
|
||||
const xy1 = view.aladin.world2pix(p1[0], p1[1]);
|
||||
const xy2 = view.aladin.world2pix(p2[0], p2[1]);
|
||||
|
||||
// Skip invalid segments, do NOT abort
|
||||
if (!xy1 || !xy2) {
|
||||
return false;
|
||||
i = j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
xy1 = {x: xy1[0], y: xy1[1]};
|
||||
xy2 = {x: xy2[0], y: xy2[1]};
|
||||
|
||||
// Check if line segment intersects with the bounding box
|
||||
if (this.lineIntersectsBox(xy1, xy2, x, y, w, h)) {
|
||||
const a = { x: xy1[0], y: xy1[1] };
|
||||
const b = { x: xy2[0], y: xy2[1] };
|
||||
|
||||
poly.push(a);
|
||||
|
||||
if (Polyline.segmentIntersectsBox(a, b, x, y, w, h)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
i = j++;
|
||||
}
|
||||
|
||||
if (this.closed && poly.length === this.raDecArray.length) {
|
||||
console.log("closed poly")
|
||||
const corners = [
|
||||
{ x, y },
|
||||
{ x: x + w, y },
|
||||
{ x: x + w, y: y + h },
|
||||
{ x, y: y + h }
|
||||
];
|
||||
|
||||
for (const c of corners) {
|
||||
if (Polyline.pointInPolygon(c, poly)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline.prototype.lineIntersectsBox = function(p1, p2, x, y, w, h) {
|
||||
// Check if line segment is completely outside the box
|
||||
if ((p1.x < x && p2.x < x) ||
|
||||
(p1.y < y && p2.y < y) ||
|
||||
(p1.x > x + w && p2.x > x + w) ||
|
||||
(p1.y > y + h && p2.y > y + h)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let m = (p2.y - p1.y) / (p2.x - p1.x); // Slope of the line
|
||||
let c = p1.y - m * p1.x; // y-intercept of the line
|
||||
Polyline.segmentIntersectsBox = function (p1, p2, x, y, w, h) {
|
||||
const x2 = x + w;
|
||||
const y2 = y + h;
|
||||
|
||||
// Check if line intersects with the sides of the box
|
||||
if ((p1.y >= y && p1.y <= y + h) ||
|
||||
(p2.y >= y && p2.y <= y + h) ||
|
||||
(m * x + c >= y && m * x + c <= y + h) ||
|
||||
(m * (x + w) + c >= y && m * (x + w) + c <= y + h)) {
|
||||
// 1️⃣ Endpoint inside box
|
||||
if (Polyline.pointInBox(p1, x, y, x2, y2) ||
|
||||
Polyline.pointInBox(p2, x, y, x2, y2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// 2️⃣ Check intersection with 4 box edges
|
||||
return (
|
||||
Polyline.segmentsIntersect(p1, p2, { x, y }, { x: x2, y }) || // top
|
||||
Polyline.segmentsIntersect(p1, p2, { x: x2, y }, { x: x2, y: y2 }) || // right
|
||||
Polyline.segmentsIntersect(p1, p2, { x: x2, y: y2 }, { x, y: y2 }) || // bottom
|
||||
Polyline.segmentsIntersect(p1, p2, { x, y: y2 }, { x, y }) // left
|
||||
);
|
||||
};
|
||||
|
||||
Polyline.pointInBox = function (p, x1, y1, x2, y2) {
|
||||
return p.x >= x1 && p.x <= x2 && p.y >= y1 && p.y <= y2;
|
||||
};
|
||||
|
||||
Polyline.pointInPolygon = function (xy, poly) {
|
||||
let inside = false;
|
||||
|
||||
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
||||
const xi = poly[i].x, yi = poly[i].y;
|
||||
const xj = poly[j].x, yj = poly[j].y;
|
||||
|
||||
const intersect =
|
||||
((yi > xy.y) !== (yj > xy.y)) &&
|
||||
(xy.x < (xj - xi) * (xy.y - yi) / (yj - yi) + xi);
|
||||
|
||||
if (intersect) inside = !inside;
|
||||
}
|
||||
|
||||
return inside;
|
||||
};
|
||||
|
||||
Polyline.segmentsIntersect = function (p1, p2, p3, p4) {
|
||||
function orient(a, b, c) {
|
||||
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
||||
}
|
||||
|
||||
const o1 = orient(p1, p2, p3);
|
||||
const o2 = orient(p1, p2, p4);
|
||||
const o3 = orient(p3, p4, p1);
|
||||
const o4 = orient(p3, p4, p2);
|
||||
|
||||
return o1 * o2 < 0 && o3 * o4 < 0;
|
||||
};
|
||||
|
||||
// static methods
|
||||
@@ -516,10 +578,10 @@ export let Polyline = (function() {
|
||||
|
||||
// check if the line has hit any of the rectangle's sides
|
||||
// uses the Line/Line function below
|
||||
let left = Polyline._intersectLine(x1, y1, x2, y2, 0, 0, 0, rh);
|
||||
let right = Polyline._intersectLine(x1, y1, x2, y2, rw, 0, rw, rh);
|
||||
let top = Polyline._intersectLine(x1, y1, x2, y2, 0, 0, rw, 0);
|
||||
let bottom = Polyline._intersectLine(x1, y1, x2, y2, 0, rh, rw, rh);
|
||||
let left = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: 0, y: 0}, {x: 0, y: rh});
|
||||
let right = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: rw, y: 0}, {x: rw, y: rh});
|
||||
let top = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: 0, y: 0}, {x: rw, y: 0});
|
||||
let bottom = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: 0, y: rh}, {x: rw, y: rh});
|
||||
|
||||
// if ANY of the above are true, the line
|
||||
// has hit the rectangle
|
||||
@@ -530,17 +592,5 @@ export let Polyline = (function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline._intersectLine = function(x1, y1, x2, y2, x3, y3, x4, y4) {
|
||||
// Calculate the direction of the lines
|
||||
let uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
|
||||
let uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
|
||||
|
||||
// If uA and uB are between 0-1, lines are colliding
|
||||
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return Polyline;
|
||||
})();
|
||||
|
||||
@@ -193,7 +193,7 @@ export let Vector = (function() {
|
||||
xy2 = {x: xy2[0], y: xy2[1]};
|
||||
|
||||
// Check if line segment intersects with the bounding box
|
||||
if (this.lineIntersectsBox(xy1, xy2, x, y, w, h)) {
|
||||
if (Polyline.segmentIntersectsBox(xy1, xy2, x, y, w, h)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ export let Datalink = (function() {
|
||||
title: 'HiPS cube player',
|
||||
draggable: true,
|
||||
},
|
||||
content: Layout.horizontal([prevBtn, nextBtn, slicer, (idxSlice + 1) + '/' + numSlices]),
|
||||
content: [prevBtn, nextBtn, slicer, (idxSlice + 1) + '/' + numSlices],
|
||||
position: {anchor: 'center top'},
|
||||
});
|
||||
aladinInstance.addUI(cubeDisplayer)
|
||||
|
||||
Reference in New Issue
Block a user