Compare commits

...

9 Commits
3.6.1 ... 3.6.4

Author SHA1 Message Date
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
22 changed files with 102 additions and 96 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.3",
"softwareVersion": "3.6.3",
"description": "An astronomical HiPS visualizer in the browser.",
"identifier": "10.5281/zenodo.7638833",
"applicationCategory": "Astronomy, Visualization",

View File

@@ -2,7 +2,7 @@
"homepage": "https://aladin.u-strasbg.fr/",
"name": "aladin-lite",
"type": "module",
"version": "3.6.1",
"version": "3.6.4",
"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.4"
authors = [ "baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr",]
edition = "2018"
@@ -22,7 +22,8 @@ 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"
# We had to revert from 0.2.100 to 0.2.92 for make it work on safari 16.1
wasm-bindgen = "=0.2.92"
wasm-streams = "0.3.0"
async-channel = "1.8.0"
mapproj = "0.3.0"
@@ -64,7 +65,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.4"
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.4"
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)?;

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

@@ -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

@@ -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) {
@@ -688,9 +687,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 +773,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 +808,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 +913,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 +926,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 +950,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 +1249,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()
if (view.aladin.isInFullscreen) {
view.aladin.toggleFullscreen(view.aladin.options.realFullscreen);
}

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

@@ -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'
})
}
})
}
}
},
{