Compare commits

...

16 Commits
3.6.1 ... 3.6

Author SHA1 Message Date
Matthieu Baumann
bde5a37b51 codemeta 3.6.5 2025-04-09 13:33:29 +02:00
Matthieu Baumann
fbdc7e2e76 3.6.5 2025-04-09 11:57:10 +02:00
Matthieu Baumann
312b9844d1 Fix allsky fits display
Bug introduced in #254. Allsky is also downloaded if the tile_size is <= 256
2025-04-09 11:47:53 +02:00
bmatthieu3
0e740454bd Fix #278
When creating a new default survey the DSS2 survey is chosen. We use
the one cached instead of creating a plain new one.
2025-04-08 18:09:09 +02:00
bmatthieu3
18e98e9f5f fix: fullscreen closing
Bug happening when realFullscreen is true and we click on the
fullscreen button. Following #151 fix, commit #a19a050
2025-04-03 18:01:58 +02:00
Matthieu Baumann
c938a58cbc Fix selection of footprints not associated with catalog sources
Targets #274

* fix: handleSelect now call selectObjects with not only the list of catalog sources but also with the footprints
* fix: View.closestFootprints: if no lineWidth was given to a footprint then it could happen that this method set it to 1px, erasing its previous undefined value
* Circle and Ellipse now behaves like PolyLine and Vector, if no linewidth is given, the one from its GraphicOverlay is taken.
2025-04-03 18:01:46 +02:00
Matthieu Baumann
4a5d66768c 3.6.4 2025-04-01 11:10:17 +02:00
Matthieu Baumann
239ae2ce74 fix make it work for safari 16.1
Revert wasm-bindgen version to 0.2.92 to make it work for safari 16.1 (and maybe older?)
(This is very obscure)
2025-03-31 17:09:05 +02:00
Matthieu Baumann
9bf898c104 3.6.3 2025-03-26 18:06:12 +01:00
Matthieu Baumann
6f085429f5 background color set to (0.1, 0.1, 0.1)
jpeg HiPS that does not cover all the sky are plotted as black when data is missing. This allow to recognize the border of the projection
2025-03-26 17:18:23 +01:00
Matthieu Baumann
b49c763e07 Improved distant HiPS url detection
This targets #270

* Use js URL object to detect if the user gives an url
* There is important point: a user can give a path pointing towards a local HiPS. For those Aladin Lite will think the path is an ID but it is not. That is why after failing fetching the MocServer for its properties, we simply try to reconsider it as an URL so that a local HiPS can be load afterwards.
2025-03-26 17:10:13 +01:00
Matthieu Baumann
fcacda0c19 Several fixes:
* use Utils.copy2Clipboard in contextmenu and shareview
* check for a mousedown before computing distance from the position when the mouse has been clicked
* smartphone 2 fingers pinched rotation between lon pi and 2*pi seems to have been fixed. The bug seem to be there from a long time ago.
2025-03-26 15:47:32 +01:00
Matthieu Baumann
f6acb3a324 3.6.2 2025-03-26 11:51:57 +01:00
Matthieu Baumann
14d54b03bc Fix css selector
Add a width: 100% to make the selector fits in its parent
2025-03-26 11:42:32 +01:00
Matthieu Baumann
9e2779837d Remove Shift shortcut
We will work on keyboard shortcuts for a next version
2025-03-26 11:03:04 +01:00
Matthieu Baumann
e29b5202b3 Fix context menu showing up
Change heuristic for showing up the contextual menu. Before we were waiting 100ms before changing the cuts but this does not work for users doing long timed right click without moving. Now, we look for the mouse offset after rightclicking. If it exceeds an offset of 10px then the contextual menu will not open and the cuts will change instead.
2025-03-26 10:34:32 +01:00
32 changed files with 229 additions and 207 deletions

View File

@@ -8,8 +8,8 @@
"dateModified": "2023-01-31",
"issueTracker": "https://github.com/cds-astro/aladin-lite/issues",
"name": "Aladin Lite",
"version": "3.6.1",
"softwareVersion": "3.6.1",
"version": "3.6.5",
"softwareVersion": "3.6.5",
"description": "An astronomical HiPS visualizer in the browser.",
"identifier": "10.5281/zenodo.7638833",
"applicationCategory": "Astronomy, Visualization",

View File

@@ -11,9 +11,9 @@
let aladin;
A.init.then(() => {
// Start up Aladin Lite
aladin = A.aladin('#aladin-lite-div', {survey: "CDS/P/DSS2/color", target: 'M 1', fov: 0.2, showContextMenu: true, fullScreen: true});
aladin = A.aladin('#aladin-lite-div', {target: 'M 1', fov: 0.2, showContextMenu: true, fullScreen: true});
var overlay = A.graphicOverlay({color: '#ee2345', lineWidth: 3, lineDash: [2, 2]});
/*aladin.addOverlay(overlay);
aladin.addOverlay(overlay);
overlay.addFootprints([
A.polygon([[83.64287, 22.01713], [83.59872, 22.01692], [83.59852, 21.97629], [83.64295, 21.97629]], {hoverColor: 'green'}),
A.polygon([[83.62807, 22.06330], [83.58397, 22.02280], [83.62792, 22.02258]]),
@@ -21,7 +21,7 @@
]);
overlay.add(A.circle(83.66067, 22.03081, 0.04, {color: 'cyan'})); // radius in degrees
overlay.add(A.vector(83.66067, 22.03081, 0.04, {color: 'cyan'})); // radius in degrees
*/
aladin.on("footprintClicked", (footprint, xyMouseCoords) => {
console.log("footprint clicked catched: ", footprint, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
})
@@ -35,8 +35,8 @@
console.log("Object hovered stopped: ", object, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
})
const cat = A.catalogFromVizieR('B/assocdata/obscore', 'M 1', 10, {onClick: 'showTable', selectionColor: "orange", hoverColor: 'red', limit: 10000});
aladin.addCatalog(cat);
//const cat = A.catalogFromVizieR('B/assocdata/obscore', 'M 1', 10, {onClick: 'showTable', selectionColor: "orange", hoverColor: 'red', limit: 10000});
//aladin.addCatalog(cat);
});
</script>
</body>

View File

@@ -7,7 +7,7 @@
<script type="module">
import A from '../src/js/A.js';
A.init.then(() => {
let aladin = A.aladin('#aladin-lite-div', {fov: 30, survey: "CDS/P/DSS2/color", target: "280 +0", projection: "AIT", showShareControl:true, showSettingsControl: true, showContextMenu:true});
let aladin = A.aladin('#aladin-lite-div', {fov: 30, target: "280 +0", projection: "AIT", showShareControl:true, showSettingsControl: true, showContextMenu:true});
aladin.setOverlayImageLayer(A.image(
"https://www.virtualastronomy.org/images/sig05-013.jpg",

View File

@@ -29,6 +29,7 @@
showCooGrid: true,
fullScreen: true,
samp: true,
realFullscreen: true,
}
);

View File

@@ -2,7 +2,7 @@
"homepage": "https://aladin.u-strasbg.fr/",
"name": "aladin-lite",
"type": "module",
"version": "3.6.1",
"version": "3.6.5",
"description": "An astronomical HiPS visualizer in the browser",
"author": "Thomas Boch and Matthieu Baumann",
"license": "GPL-3",

View File

@@ -3,7 +3,7 @@ name = "aladin-lite"
description = "Aladin Lite v3 introduces a new graphical engine written in Rust with the use of WebGL"
license = "BSD-3-Clause"
repository = "https://github.com/cds-astro/aladin-lite"
version = "3.6.1"
version = "3.6.5"
authors = [ "baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr",]
edition = "2018"
@@ -22,7 +22,7 @@ url-lite = "0.1.0"
serde_json = "1.0.104"
serde-wasm-bindgen = "0.5"
enum_dispatch = "0.3.8"
wasm-bindgen = "0.2.100"
wasm-bindgen = "=0.2.92"
wasm-streams = "0.3.0"
async-channel = "1.8.0"
mapproj = "0.3.0"
@@ -64,7 +64,7 @@ path = "./al-core"
path = "./al-api"
[dependencies.web-sys]
version = "*"
version = "0.3.56"
features = [ "console", "CssStyleDeclaration", "Document", "Element", "HtmlCollection", "HtmlElement", "HtmlImageElement", "HtmlCanvasElement", "Blob", "ImageBitmap", "ImageData", "CanvasRenderingContext2d", "WebGlBuffer", "WebGlContextAttributes", "WebGlFramebuffer", "WebGlProgram", "WebGlShader", "WebGlUniformLocation", "WebGlTexture", "WebGlActiveInfo", "Headers", "Window", "Request", "RequestInit", "RequestMode", "Response", "XmlHttpRequest", "XmlHttpRequestResponseType", "PerformanceTiming", "Performance", "Url", "ReadableStream", "File", "FileList",]
[dev-dependencies.image-decoder]

View File

@@ -1,6 +1,6 @@
[package]
name = "al-api"
version = "0.1.0"
version = "3.6.5"
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
edition = "2018"

View File

@@ -1,6 +1,6 @@
[package]
name = "al-core"
version = "0.1.0"
version = "3.6.5"
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
edition = "2018"
@@ -17,9 +17,7 @@ serde-wasm-bindgen = "0.4"
wasm-streams = "0.3.0"
futures = "0.3.25"
colorgrad = "0.6.2"
[dependencies.wasm-bindgen]
version = "0.2.92"
wasm-bindgen = "0.2.92"
[dev-dependencies]
fontdue = "0.7.2"
@@ -38,7 +36,7 @@ webgl2 = [
]
[dependencies.web-sys]
version = "0.3.77"
version = "0.3.56"
features = [
'console',
'CssStyleDeclaration',

View File

@@ -1,6 +1,7 @@
use crate::renderable::ImageLayer;
use crate::tile_fetcher::HiPSLocalFiles;
use crate::math::angle::ToAngle;
use crate::renderable::hips::HiPS;
use crate::{
//async_task::{BuildCatalogIndex, ParseTableTask, TaskExecutor, TaskResult, TaskType},
@@ -21,7 +22,6 @@ use crate::{
time::DeltaTime,
};
use al_api::moc::MOCOptions;
use crate::math::angle::ToAngle;
use wcs::WCS;
use wasm_bindgen::prelude::*;
@@ -188,7 +188,7 @@ impl App {
let request_for_new_tiles = true;
let moc = MOCRenderer::new(&gl)?;
gl.clear_color(0.0, 0.0, 0.0, 1.0);
gl.clear_color(0.1, 0.1, 0.1, 1.0);
let (img_send, img_recv) = async_channel::unbounded::<ImageLayer>();
let (ack_img_send, ack_img_recv) = async_channel::unbounded::<ImageParams>();
@@ -714,8 +714,8 @@ impl App {
)?,
}
self.time_start_blending = Time::now();
},
_ => ()
}
_ => (),
};
}
}
@@ -1277,8 +1277,7 @@ impl App {
// Set the new meta
// keep the old meta data
let new_img_ext = meta.img_format;
self.layers
.set_layer_cfg(layer.clone(), meta)?;
self.layers.set_layer_cfg(layer.clone(), meta)?;
if old_meta.img_format != new_img_ext {
// The image format has been changed

View File

@@ -5,8 +5,8 @@ pub enum UserAction {
Moving = 3,
Starting = 4,
}
use web_sys::WebGl2RenderingContext;
use web_sys::WebGl2RenderingContext;
// Longitude reversed identity matrix
const ID_R: &Matrix4<f64> = &Matrix4::new(
-1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
@@ -488,11 +488,11 @@ impl CameraViewPort {
pub fn set_center(&mut self, lonlat: &LonLatT<f64>, proj: &ProjectionType) {
let icrs_pos: Vector4<_> = lonlat.vector();
let view_pos = CooSystem::ICRS.to(self.get_coo_system()) * icrs_pos;
let rot_to_center = Rotation::from_sky_position(&view_pos);
let center = (CooSystem::ICRS.to(self.get_coo_system()) * icrs_pos).truncate();
let rot_to_center = Rotation::from_sky_position(&center);
let phi = self.get_center_pos_angle();
let third_euler_rot = Rotation::from_axis_angle(&view_pos.truncate(), phi);
let third_euler_rot = Rotation::from_axis_angle(&center, phi);
let rot = third_euler_rot * rot_to_center;
@@ -502,8 +502,9 @@ impl CameraViewPort {
}
pub fn set_center_pos_angle(&mut self, phi: Angle<f64>, proj: &ProjectionType) {
let rot_to_center = Rotation::from_sky_position(&self.center);
let third_euler_rot = Rotation::from_axis_angle(&self.center.truncate(), phi);
let c = self.center.truncate();
let rot_to_center = Rotation::from_sky_position(&c);
let third_euler_rot = Rotation::from_axis_angle(&c, phi);
let total_rot = third_euler_rot * rot_to_center;
self.set_rotation(&total_rot, proj);
@@ -523,7 +524,7 @@ impl CameraViewPort {
// Compute the center position according to the new coordinate frame system
let new_center = coosys::apply_coo_system(self.coo_sys, new_coo_sys, &self.center);
// Create a rotation object from that position
let new_rotation = Rotation::from_sky_position(&new_center);
let new_rotation = Rotation::from_sky_position(&new_center.truncate());
// Apply it to the center of the view
self.set_rotation(&new_rotation, proj);

View File

@@ -130,9 +130,9 @@ impl From<query::Allsky> for AllskyRequest {
Ok(allsky_tiles)
}
_ => {
let opts = RequestInit::new();
opts.set_method("GET");
opts.set_mode(RequestMode::Cors);
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let window = web_sys::window().unwrap_abort();
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts)?;
@@ -185,14 +185,24 @@ impl From<query::Allsky> for AllskyRequest {
.collect())
}
InMemData::F32(data) => {
let data = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 4) };
let data = unsafe {
std::slice::from_raw_parts(
data.as_ptr() as *const u8,
data.len() * 4,
)
};
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
.map(|image| ImageType::RawRgba8u { image })
.collect())
}
InMemData::F64(data) => {
let data = data.iter().map(|v| *v as f32).collect::<Vec<_>>();
let data = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 4) };
let data = unsafe {
std::slice::from_raw_parts(
data.as_ptr() as *const u8,
data.len() * 4,
)
};
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
.map(|image| ImageType::RawRgba8u { image })
@@ -228,71 +238,77 @@ fn handle_allsky_file<F: ImageFormat>(
let num_allsky_tiles_per_tile = (tile_size / allsky_tile_size) * (tile_size / allsky_tile_size);
let mut src_idx = 0;
let tiles = (0..num_tiles)
.map(move |_| {
let mut base_tile =
let tiles = (0..num_tiles).map(move |_| {
let mut base_tile =
ImageBuffer::<F>::allocate(&<F as ImageFormat>::P::BLACK, tile_size, tile_size);
for idx_tile in 0..num_allsky_tiles_per_tile {
let (x, y) = crate::utils::unmortonize(idx_tile as u64);
let dx = x * (allsky_tile_size as u32);
let dy = y * (allsky_tile_size as u32);
for idx_tile in 0..num_allsky_tiles_per_tile {
let (x, y) = crate::utils::unmortonize(idx_tile as u64);
let dx = x * (allsky_tile_size as u32);
let dy = y * (allsky_tile_size as u32);
let sx = (src_idx % 27) * allsky_tile_size;
let sy = (src_idx / 27) * allsky_tile_size;
let s = ImageBufferView {
x: sx as i32,
y: sy as i32,
w: allsky_tile_size as i32,
h: allsky_tile_size as i32,
};
let d = ImageBufferView {
x: dx as i32,
y: dy as i32,
w: allsky_tile_size as i32,
h: allsky_tile_size as i32,
};
let sx = (src_idx % 27) * allsky_tile_size;
let sy = (src_idx / 27) * allsky_tile_size;
let s = ImageBufferView {
x: sx as i32,
y: sy as i32,
w: allsky_tile_size as i32,
h: allsky_tile_size as i32,
};
let d = ImageBufferView {
x: dx as i32,
y: dy as i32,
w: allsky_tile_size as i32,
h: allsky_tile_size as i32,
};
base_tile.tex_sub(&allsky, &s, &d);
base_tile.tex_sub(&allsky, &s, &d);
src_idx += 1;
}
src_idx += 1;
}
base_tile
});
base_tile
});
Ok(tiles)
}
fn handle_allsky_fits<F: ImageFormat>(
allsky_data: &[<<F as ImageFormat>::P as Pixel>::Item],
tile_size: i32,
texture_size: i32,
) -> Result<impl Iterator<Item=ImageBuffer<F>>, JsValue> {
) -> Result<impl Iterator<Item = ImageBuffer<F>>, JsValue> {
let allsky_tile_size = std::cmp::min(tile_size, 64);
let width_allsky_px = 27 * allsky_tile_size;
let height_allsky_px = 29 * allsky_tile_size;
// The fits image layout stores rows in reverse
let reversed_rows_data = allsky_data
.chunks(width_allsky_px as usize)
.chunks(width_allsky_px as usize * F::NUM_CHANNELS)
.rev()
.flatten()
.copied()
.collect::<Vec<_>>();
let allsky = ImageBuffer::<F>::new(reversed_rows_data, width_allsky_px, height_allsky_px);
let allsky_tiles_iter = handle_allsky_file::<F>(allsky, allsky_tile_size, texture_size, tile_size)?
.map(move |image| {
// The GPU does a specific transformation on the UV
// for FITS tiles
// We must revert this to be compatible with this GPU transformation
let mut new_image_data = Vec::with_capacity(tile_size as usize);
for c in image.get_data().chunks((tile_size * tile_size) as usize) {
new_image_data.extend(c.chunks(tile_size as usize).rev().flatten());
}
let allsky_tiles_iter =
handle_allsky_file::<F>(allsky, allsky_tile_size, texture_size, tile_size)?.map(
move |image| {
// The GPU does a specific transformation on the UV for FITS tiles
// We must revert this to be compatible with this GPU transformation
let new_image_data = image
.get_data()
.chunks((tile_size * tile_size) as usize * F::NUM_CHANNELS)
.flat_map(|c| {
c.chunks(tile_size as usize * F::NUM_CHANNELS)
.rev()
.flatten()
})
.cloned()
.collect();
ImageBuffer::<F>::new(new_image_data, tile_size, tile_size)
});
ImageBuffer::<F>::new(new_image_data, tile_size, tile_size)
},
);
Ok(allsky_tiles_iter)
}

View File

@@ -61,9 +61,9 @@ impl From<query::PixelMetadata> for PixelMetadataRequest {
let request = match channel {
ChannelType::R32F | ChannelType::R32I | ChannelType::R16I | ChannelType::R8UI => {
Request::new(async move {
let opts = RequestInit::new();
opts.set_method("GET");
opts.set_mode(RequestMode::Cors);
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let request =
web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();

View File

@@ -61,9 +61,9 @@ impl From<query::Moc> for MOCRequest {
let window = web_sys::window().unwrap_abort();
let request = Request::new(async move {
let opts = RequestInit::new();
opts.set_method("GET");
opts.set_mode(RequestMode::Cors);
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;

View File

@@ -142,9 +142,9 @@ impl From<query::Tile> for TileRequest {
| ChannelType::R32I
| ChannelType::R16I
| ChannelType::R8UI => Request::new(async move {
let opts = RequestInit::new();
opts.set_method("GET");
opts.set_mode(RequestMode::Cors);
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let request =
web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();

View File

@@ -523,7 +523,7 @@ impl WebClient {
/// Get if the longitude axis is reversed
#[wasm_bindgen(js_name = getLongitudeReversed)]
pub fn get_longitude_reversed(&mut self) -> bool {
pub fn get_longitude_reversed(&self) -> bool {
self.app.get_longitude_reversed()
}

View File

@@ -1,8 +1,8 @@
use crate::math;
use crate::math::angle::ToAngle;
use cgmath::{BaseFloat, InnerSpace};
use cgmath::{Euler, Quaternion};
use cgmath::{Vector3, Vector4};
use crate::math::angle::ToAngle;
#[derive(Clone, Copy, Debug)]
// Internal structure of a rotation, a quaternion
@@ -109,13 +109,13 @@ where
// Define a rotation from an axis and a angle
pub fn from_axis_angle(axis: &Vector3<S>, angle: Angle<S>) -> Rotation<S> {
let angle: Rad<S> = angle.into();
let mat4 = Matrix4::from_axis_angle(*axis, angle);
let mat4 = Matrix4::from_axis_angle(axis.normalize(), angle);
(&mat4).into()
}
// Define a rotation from a normalized vector
pub fn from_sky_position(pos: &Vector4<S>) -> Rotation<S> {
let (lon, lat) = math::lonlat::xyzw_to_radec(&pos.normalize());
pub fn from_sky_position(pos: &Vector3<S>) -> Rotation<S> {
let (lon, lat) = math::lonlat::xyz_to_radec(&pos);
let rot_y = Matrix4::from_angle_y(lon);
let rot_x = Matrix4::from_angle_x(-lat);

View File

@@ -95,7 +95,7 @@ impl Renderer for TextRenderManager {
// reset the font and color
self.ctx
.set_font(&format!("{}px verdana, sans-serif", self.font_size));
self.ctx.set_fill_style_str(&self.color);
self.ctx.set_fill_style(&JsValue::from_str(&self.color));
}
fn end(&mut self) {}

View File

@@ -2,10 +2,10 @@ use crate::downloader::{query, Downloader};
use crate::time::{DeltaTime, Time};
use crate::Abort;
use al_api::moc::MOCOptions;
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::rc::Rc;
use al_api::moc::MOCOptions;
const MAX_NUM_TILE_FETCHING: usize = 8;
const MAX_QUERY_QUEUE_LENGTH: usize = 100;
@@ -214,7 +214,7 @@ impl TileFetcherQueue {
let tile_size = cfg.get_tile_size();
//Request the allsky for the small tile size or if base tiles are not available
if tile_size <= 128 || cfg.get_min_depth_tile() > 0 {
if tile_size <= 256 || cfg.get_min_depth_tile() > 0 {
// Request the allsky
downloader.borrow_mut().fetch(query::Allsky::new(
cfg,

View File

@@ -505,12 +505,15 @@
.aladin-form .aladin-form-input {
display: flex;
justify-content: flex-end;
align-items: center;
justify-content: space-between;
}
.aladin-form-group > * {
margin-bottom: 0.4rem;
}
.aladin-form .aladin-form-input:last-of-type {
.aladin-form-group > *:last-of-type {
margin-bottom: 0;
}
@@ -527,10 +530,6 @@
width: 100%;
}
.aladin-form .aladin-form-input > label {
flex: 1;
}
.aladin-form .aladin-form-input .aladin-input {
flex: 2;
}
@@ -840,13 +839,18 @@
box-shadow: 0 0 1em 0 rgba(0, 0, 0, 0.2);
cursor: pointer;
font-family: monospace;
width: 100%;
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)
otherwise it fits its content options. If those are too big the select can go out of its parent */
.aladin-horizontal-list .aladin-input-select {
width: 100%;
}
.aladin-input-select option {
color: inherit;
background-color: #320a28;

View File

@@ -1036,7 +1036,7 @@ A.init = (async () => {
.createElement('canvas')
.getContext('webgl2');
await init({});
await init();
// Check for webgl2 support
if (isWebGL2Supported) {
Aladin.wasmLibs.core = module;

View File

@@ -426,6 +426,8 @@ export let Aladin = (function () {
// Merge what is already in the cache for that HiPS with new properties
// coming from the MOCServer
this.hipsFavorites.push(hipsObj);
// Favorites are also directly pushed to the cache
this.hipsCache.append(hipsObj.id, hipsObj)
}
this._setupUI(options);
@@ -445,11 +447,7 @@ export let Aladin = (function () {
});
} else if (options.survey === HiPS.DEFAULT_SURVEY_ID) {
// DSS is cached inside HiPS class, no need to provide any further information
const survey = this.createImageSurvey(
HiPS.DEFAULT_SURVEY_ID
);
this.setBaseImageLayer(survey);
this.setBaseImageLayer(HiPS.DEFAULT_SURVEY_ID);
} else {
this.setBaseImageLayer(options.survey);
}
@@ -485,22 +483,24 @@ export let Aladin = (function () {
// maximize control
if (options.showFullscreenControl) {
// react to fullscreenchange event to restore initial width/height (if user pressed ESC to go back from full screen)
// This event is only triggered with realFullscreen on
Utils.on(
document,
"fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange",
function (e) {
() => {
var fullscreenElt =
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement ||
document.msFullscreenElement;
if (fullscreenElt === null || fullscreenElt === undefined) {
self.toggleFullscreen(options.realFullscreen);
var fullScreenToggledFn =
self.callbacksByEventName["fullScreenToggled"];
typeof fullScreenToggledFn === "function" &&
fullScreenToggledFn(self.isInFullscreen);
// fix: Only toggle off the screen once because in case of closing the real fullscreen from the ui button, this could be called 2 times
// * one toggleFullscreen from the button itself
// * one toggleFullscreen from the fullscreenchange event
// => resulting in closing and opening the fullscreen again.
if (self.isInFullscreen) {
self.toggleFullscreen(options.realFullscreen);
}
}
}
);
@@ -716,7 +716,6 @@ export let Aladin = (function () {
Aladin.prototype.toggleFullscreen = function (realFullscreen) {
let self = this;
realFullscreen = Boolean(realFullscreen);
self.isInFullscreen = !self.isInFullscreen;
ContextMenu.hideAll();
@@ -727,13 +726,7 @@ export let Aladin = (function () {
ui.toggle();
}
})
if (this.aladinDiv.classList.contains("aladin-fullscreen")) {
this.aladinDiv.classList.remove("aladin-fullscreen");
} else {
this.aladinDiv.classList.add("aladin-fullscreen");
}
if (realFullscreen) {
// go to "real" full screen mode
if (self.isInFullscreen) {
@@ -764,6 +757,8 @@ export let Aladin = (function () {
}
}
this.aladinDiv.classList.toggle("aladin-fullscreen");
// Delay the fixLayoutDimensions layout for firefox
/*setTimeout(function () {
self.view.fixLayoutDimensions();
@@ -1569,10 +1564,8 @@ export let Aladin = (function () {
let hipsOptions = { id, name, maxOrder, url, cooFrame, ...options };
let hips = new HiPS(id, url || id, hipsOptions)
// This allows to retrieve the survey's options when it will be
// added later to the view.
if (this instanceof Aladin && !this.hipsCache.contains(hips.id)) {
// Add it to the cache as soon as possible if we have a reference to the aladin object
// A HiPS can be refered by its unique ID thus we add it to the cache (cf excample/al-cfht.html that refers to HiPS object just by their unique ID)
if (this instanceof Aladin) {
this.hipsCache.append(hips.id, hipsOptions)
}
@@ -1929,12 +1922,14 @@ export let Aladin = (function () {
let imageLayer;
let hipsCache = this.hipsCache;
// 1. User gives an ID
if (typeof urlOrHiPSOrFITS === "string") {
const idOrUrl = urlOrHiPSOrFITS;
// many cases here
// 1/ It has been already added to the cache
let cachedOptions = hipsCache.get(idOrUrl)
if (cachedOptions) {
imageLayer = A.HiPS(idOrUrl, cachedOptions);
} else {
@@ -1954,7 +1949,7 @@ export let Aladin = (function () {
if (!cachedLayerOptions) {
hipsCache.append(imageLayer.id, imageLayer.options)
} else {
// set the options from what is in the cache
// Set the options from what is in the cache
imageLayer.setOptions(cachedLayerOptions);
}
}

View File

@@ -613,7 +613,6 @@ export let Catalog = (function () {
// Set the same color of the shape than the catalog.
// FIXME: the color/shape could be a parameter at the source level, allowing the user single catalogs handling different shapes
shape.setColor(this.color)
shape.setSelectionColor(this.selectionColor);
shape.setHoverColor(this.hoverColor);
}

View File

@@ -35,6 +35,7 @@ import cameraIconUrl from '../../assets/icons/camera.svg'
import targetIconUrl from '../../assets/icons/target.svg';
import uploadIconUrl from '../../assets/icons/upload.svg';
import selectIconUrl from '../../assets/icons/select.svg';
import { Utils } from "./Utils";
export let DefaultActionsForContextMenu = (function () {
@@ -55,7 +56,7 @@ export let DefaultActionsForContextMenu = (function () {
return false;
}
navigator.clipboard.writeText(text)
Utils.copy2Clipboard(text)
.then(() => {
msg = 'successful'
if (aladinInstance.statusBar) {

View File

@@ -30,6 +30,8 @@ import { ColorCfg } from "./ColorCfg.js";
import { HiPSProperties } from "./HiPSProperties.js";
import { Aladin } from "./Aladin.js";
import { CooFrameEnum } from "./CooFrameEnum.js";
import { Utils } from "./Utils"
let PropertyParser = {};
// Utilitary functions for parsing the properties and giving default values
/// Mandatory tileSize property
@@ -860,9 +862,8 @@ export let HiPS = (function () {
let isIncompleteOptions = true;
// This is very dirty but it allows me to differentiate the location from whether it is an ID or a plain url
let isID = this.url.includes("P/") || this.url.includes("C/")
let isID = Utils.isUrl(this.url) === undefined;
if (this.imgFormat === "fits") {
// a fits is given
isIncompleteOptions = !(
@@ -887,7 +888,6 @@ export let HiPS = (function () {
if (isIncompleteOptions) {
// ID typed url
if (self.startUrl && isID) {
// First download the properties from the start url
await HiPSProperties.fetchFromUrl(self.startUrl)
.then((p) => {
@@ -909,9 +909,16 @@ export let HiPS = (function () {
HiPSProperties.fetchFromID(id)
.then((p) => {
//self.url = self.startUrl;
self._fetchFasterUrlFromProperties(p);
})
.catch(() => {
// If no ID has been found then it may actually be a path
// url pointing to a local HiPS
return HiPSProperties.fetchFromUrl(id)
.then((p) => {
self._parseProperties(p);
})
})
},
1000
);
@@ -932,6 +939,14 @@ export let HiPS = (function () {
self._parseProperties(p);
self._fetchFasterUrlFromProperties(p);
})
.catch(() => {
// If no ID has been found then it may actually be a path
// url pointing to a local HiPS
return HiPSProperties.fetchFromUrl(id)
.then((p) => {
self._parseProperties(p);
})
})
} catch (e) {
throw e;
}

View File

@@ -38,7 +38,7 @@ HiPSProperties.fetchFromID = async function(ID) {
const params = {
get: "record",
fmt: "json",
ID: "*" + ID + "*",
ID: "*" + decodeURI(ID) + "*",
};
let metadata = await Utils.loadFromUrls(MocServer.MIRRORS_HTTPS, {

View File

@@ -246,8 +246,6 @@ export let View = (function () {
// some variables for mouse handling
this.dragging = false;
this.dragCoo = null;
this.rightclickx = null;
this.rightclicky = null;
this.selectedLayer = 'base';
this.needRedraw = true;
@@ -618,6 +616,7 @@ export let View = (function () {
};
var longTouchTimer;
var longTouchDuration = 800;
var showContextMenu = true;
var xystart;
var handleSelect = function(xy, tolerance) {
@@ -631,6 +630,7 @@ export let View = (function () {
var footprintClickedFunction = view.aladin.callbacksByEventName['footprintClicked'];
let objsByCats = {};
let shapes = [];
for (let o of objs) {
// classify the different objects by catalog
let cat = o.getCatalog && o.getCatalog();
@@ -649,11 +649,22 @@ export let View = (function () {
footprintClickedFunction(o, xy);
}
}
// If this shape has a catalog then it will be selected from its source
// so we will not add it
if (!cat) {
shapes.push(o);
}
}
// rewrite objs
// Rewrite objs
objs = Array.from(Object.values(objsByCats));
// Add the external shapes (i.e. which are not associated with catalog sources e.g. those from GraphicOverlay)
if (shapes.length > 0) {
objs.push(shapes)
}
view.selectObjects(objs);
view.lastClickedObject = objs;
} else {
@@ -688,9 +699,7 @@ export let View = (function () {
if (e.which === 3 || e.button === 2) {
view.rightClick = true;
view.rightClickTimeStart = Date.now();
view.rightclickx = xymouse.x;
view.rightclicky = xymouse.y;
showContextMenu = true;
if (view.selectedLayer) {
const imageLayer = view.imageLayers.get(view.selectedLayer);
@@ -776,15 +785,11 @@ export let View = (function () {
});
if (view.rightClick) {
const rightClickDurationMs = Date.now() - view.rightClickTimeStart;
if (rightClickDurationMs < 100) {
if (showContextMenu) {
view.aladin.contextMenu && view.aladin.contextMenu.show({e});
}
view.rightClick = false;
view.rightclickx = null;
view.rightclicky = null;
view.rightClickTimeStart = undefined;
return;
}
@@ -815,11 +820,10 @@ export let View = (function () {
view.aladin.statusBar.removeMessage('opening-ctxmenu')
}
clearTimeout(longTouchTimer)
longTouchTimer = undefined;
}
}
xystart = undefined;
if ((e.type === 'touchend' || e.type === 'touchcancel') && view.pinchZoomParameters.isPinching) {
view.pinchZoomParameters.isPinching = false;
view.pinchZoomParameters.initialFov = view.pinchZoomParameters.initialDistance = undefined;
@@ -921,7 +925,6 @@ export let View = (function () {
var lastMouseMovePos = null;
Utils.on(view.catalogCanvas, "mousemove touchmove", function (e) {
e.preventDefault();
//e.stopPropagation();
const xymouse = Utils.relMouseCoords(e);
@@ -935,16 +938,18 @@ export let View = (function () {
xy: xymouse,
});
let dist;
if (xystart) {
dist = (xymouse.x - xystart.x)*(xymouse.x - xystart.x) + (xymouse.y - xystart.y)*(xymouse.y - xystart.y);
}
if (e.type === 'touchmove' && xystart) {
let dist = (() => {
return (xymouse.x - xystart.x)*(xymouse.x - xystart.x) + (xymouse.y - xystart.y)*(xymouse.y - xystart.y)
})();
if (longTouchTimer && dist > 100) {
if (view.aladin.statusBar) {
view.aladin.statusBar.removeMessage('opening-ctxmenu')
}
clearTimeout(longTouchTimer)
xystart = undefined;
longTouchTimer = undefined;
}
}
@@ -957,11 +962,12 @@ export let View = (function () {
return;
}
const rightClickDurationMs = Date.now() - view.rightClickTimeStart;
if (rightClickDurationMs < 100) {
if (dist < 100) {
return;
}
showContextMenu = false;
if(view.selectedLayer) {
let selectedLayer = view.imageLayers.get(view.selectedLayer);
@@ -1255,17 +1261,9 @@ export let View = (function () {
return;
switch (e.keyCode) {
// shift
case 16:
view.aladin.select('rect', (selection) => {
view.selectObjects(selection);
})
break;
// escape
case 27:
// if there is a selection occuring
view.selector && view.selector.cancel()
// Called when realfullscreen is false. Escaping from real fullscreen does not seem to trigger the keydown event
if (view.aladin.isInFullscreen) {
view.aladin.toggleFullscreen(view.aladin.options.realFullscreen);
}
@@ -2174,26 +2172,21 @@ export let View = (function () {
}
let closests = [];
const fLineWidth = (footprints && footprints[0] && footprints[0].getLineWidth()) || 1;
let lw = fLineWidth + 3;
//for (var lw = startLw + 1; lw <= startLw + 3; lw++) {
footprints.forEach((footprint) => {
if (!footprint.source || !footprint.source.tooSmallFootprint) {
// Hidden footprints are not considered
//let originLineWidth = footprint.getLineWidth();
footprint.setLineWidth(lw);
if (footprint.isShowing && footprint.isInStroke(ctx, this, x * window.devicePixelRatio, y * window.devicePixelRatio)) {
closests.push(footprint);
}
footprint.setLineWidth(fLineWidth);
}
})
/* if (closests.length > 0) {
break;
footprints.forEach((footprint) => {
if (!footprint.source || !footprint.source.tooSmallFootprint) {
const originLineWidth = footprint.getLineWidth();
let spreadedLineWidth = (originLineWidth || 1) + 3;
footprint.setLineWidth(spreadedLineWidth);
if (footprint.isShowing && footprint.isInStroke(ctx, this, x * window.devicePixelRatio, y * window.devicePixelRatio)) {
closests.push(footprint);
}
footprint.setLineWidth(originLineWidth);
}
}*/
})
return closests;
};
@@ -2205,13 +2198,11 @@ export let View = (function () {
var canvas = this.catalogCanvas;
var ctx = canvas.getContext("2d");
// this makes footprint selection easier as the catch-zone is larger
//let pastLineWidth = ctx.lineWidth;
let closests = [];
if (this.overlays) {
for (var k = 0; k < this.overlays.length; k++) {
overlay = this.overlays[k];
closests = closests.concat(this.closestFootprints(overlay.overlayItems, ctx, x, y));
}
}

View File

@@ -279,7 +279,7 @@ import { ActionButton } from "../Widgets/ActionButton.js";
header: Layout.horizontal([selectorBtn, 'Cone search']),
subInputs: [
{
label: "ra:",
label: "RA:",
name: "ra",
type: "text",
value: defaultRa,
@@ -291,7 +291,7 @@ import { ActionButton } from "../Widgets/ActionButton.js";
}
},
{
label: "dec:",
label: "Dec:",
name: "dec",
type: "text",
value: defaultDec,

View File

@@ -528,15 +528,7 @@ export class OverlayStackBox extends Box {
position: self.position,
});*/
self.aladin.addNewImageLayer(
A.imageHiPS('P/DSS2/color', {
errorCallback: (e) => {
aladin.addStatusBarMessage({
duration: 2000,
type: 'info',
message: 'DSS2 colored HiPS could not plot',
})
}
})
'P/DSS2/color'
);
},
},
@@ -940,6 +932,7 @@ export class OverlayStackBox extends Box {
options.push(value)
}
let HiPSSelector = Input.select({
value,
options,

View File

@@ -57,8 +57,8 @@ export class FullScreenActionButton extends ActionButton {
if (aladin.statusBar) {
aladin.statusBar.removeMessage('tooltip')
}
aladin.toggleFullscreen(aladin.options.realFullscreen);
aladin.toggleFullscreen(aladin.options.realFullscreen);
}
})

View File

@@ -22,7 +22,7 @@ import shareIconUrl from '../../../../assets/icons/share.svg';
import cameraIconUrl from '../../../../assets/icons/camera.svg';
import linkIconUrl from '../../../../assets/icons/link.svg';
import jupyterIconUrl from '../../../../assets/icons/jupyter.svg';
import { Utils } from "../../Utils";
/******************************************************************************
* Aladin Lite project
*
@@ -62,15 +62,16 @@ import jupyterIconUrl from '../../../../assets/icons/jupyter.svg';
},
action(o) {
var url = aladin.getShareURL();
navigator.clipboard.writeText(url);
if (aladin.statusBar) {
aladin.statusBar.appendMessage({
message: 'View URL saved into your clipboard!',
duration: 2000,
type: 'info'
Utils.copy2Clipboard(url)
.then(() => {
if (aladin.statusBar) {
aladin.statusBar.appendMessage({
message: 'View URL saved into your clipboard!',
duration: 2000,
type: 'info'
})
}
})
}
}
},
{

View File

@@ -48,7 +48,7 @@ export let Circle = (function() {
this.color = options['color'] || undefined;
this.fillColor = options['fillColor'] || undefined;
this.lineWidth = options["lineWidth"] || 2;
this.lineWidth = options["lineWidth"] || undefined;
this.selectionColor = options["selectionColor"] || '#00ff00';
this.hoverColor = options["hoverColor"] || undefined;
this.opacity = options['opacity'] || 1;
@@ -297,6 +297,10 @@ export let Circle = (function() {
ctx.strokeStyle = baseColor;
}
if (!this.lineWidth) {
this.lineWidth = (this.overlay && this.overlay.lineWidth) || 2;
}
ctx.lineWidth = this.lineWidth;
ctx.globalAlpha = this.opacity;
ctx.beginPath();

View File

@@ -51,7 +51,7 @@ export let Ellipse = (function() {
this.color = options['color'] || undefined;
this.fillColor = options['fillColor'] || undefined;
this.lineWidth = options["lineWidth"] || 2;
this.lineWidth = options["lineWidth"] || undefined;
this.selectionColor = options["selectionColor"] || '#00ff00';
this.hoverColor = options["hoverColor"] || undefined;
this.opacity = options['opacity'] || 1;
@@ -283,6 +283,10 @@ export let Ellipse = (function() {
ctx.strokeStyle = baseColor;
}
if (!this.lineWidth) {
this.lineWidth = (this.overlay && this.overlay.lineWidth) || 2;
}
ctx.lineWidth = this.lineWidth;
ctx.globalAlpha = this.opacity;
ctx.beginPath();