Compare commits

...

5 Commits

Author SHA1 Message Date
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
16 changed files with 132 additions and 115 deletions

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.4",
"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.4"
version = "3.6.5"
authors = [ "baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr",]
edition = "2018"

View File

@@ -1,6 +1,6 @@
[package]
name = "al-api"
version = "3.6.4"
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 = "3.6.4"
version = "3.6.5"
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
edition = "2018"

View File

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

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

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

@@ -630,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();
@@ -648,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 {
@@ -1251,7 +1263,7 @@ export let View = (function () {
switch (e.keyCode) {
// escape
case 27:
// if there is a selection occuring
// 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);
}
@@ -2160,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;
};
@@ -2191,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

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

@@ -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();