diff --git a/examples/al-event-listeners.html b/examples/al-event-listeners.html
index cc21781d..51d8fe5b 100644
--- a/examples/al-event-listeners.html
+++ b/examples/al-event-listeners.html
@@ -52,6 +52,14 @@
$('#infoDiv').html(msg);
});
+ aladin.on('resizeChanged', function() {
+ console.log("resize")
+ });
+
+ aladin.on('projectionChanged', function(proj) {
+ console.log(proj)
+ });
+
cat.sources[0].actionClicked();
});
diff --git a/examples/al-init-custom-options.html b/examples/al-init-custom-options.html
index bbf6154f..ab7d0f68 100644
--- a/examples/al-init-custom-options.html
+++ b/examples/al-init-custom-options.html
@@ -24,6 +24,7 @@
showFrame: true,
showZoomControl:true,
showSettingsControl:true,
+ showCooGrid: true,
}
);
diff --git a/package.json b/package.json
index 5a4e649b..ecab5837 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"homepage": "https://aladin.u-strasbg.fr/",
"name": "aladin-lite",
"type": "module",
- "version": "3.4.3-beta",
+ "version": "3.4.4-beta",
"description": "An astronomical HiPS visualizer in the browser",
"author": "Thomas Boch and Matthieu Baumann",
"license": "GPL-3",
diff --git a/src/core/src/camera/viewport.rs b/src/core/src/camera/viewport.rs
index ffe87b6d..d5a6bfd5 100644
--- a/src/core/src/camera/viewport.rs
+++ b/src/core/src/camera/viewport.rs
@@ -470,12 +470,17 @@ impl CameraViewPort {
self.update_rot_matrices(proj);
}
- /// lonlat must be given in icrs frame
+ /// center lonlat must be given in icrs frame
pub fn set_center(&mut self, lonlat: &LonLatT, proj: &ProjectionType) {
let icrs_pos: Vector4<_> = lonlat.vector();
let view_pos = CooSystem::ICRS.to(self.get_coo_system()) * icrs_pos;
- let rot = Rotation::from_sky_position(&view_pos);
+ let rot_to_center = Rotation::from_sky_position(&view_pos);
+
+ let phi = self.get_center_pos_angle();
+ let third_euler_rot = Rotation::from_axis_angle(&view_pos.truncate(), phi);
+
+ let rot = third_euler_rot * rot_to_center;
// Apply the rotation to the camera to go
// to the next lonlat
diff --git a/src/core/src/renderable/grid/mod.rs b/src/core/src/renderable/grid/mod.rs
index aca1a2a5..7aef4437 100644
--- a/src/core/src/renderable/grid/mod.rs
+++ b/src/core/src/renderable/grid/mod.rs
@@ -297,7 +297,9 @@ impl ProjetedGrid {
crate::shader::get_shader(&self.gl, shaders, "line_inst_ndc.vert", "line_base.frag")?
.bind(&self.gl)
.attach_uniform("u_color", &self.color)
- .attach_uniform("u_width", &self.thickness)
+ .attach_uniform("u_width", &(camera.get_width()))
+ .attach_uniform("u_height", &(camera.get_height()))
+ .attach_uniform("u_thickness", &self.thickness)
.bind_vertex_array_object_ref(&self.vao)
.draw_elements_instanced_with_i32(
WebGl2RenderingContext::TRIANGLES,
diff --git a/src/core/src/renderable/image/grid.rs b/src/core/src/renderable/image/grid.rs
index e7eb782f..11d23667 100644
--- a/src/core/src/renderable/image/grid.rs
+++ b/src/core/src/renderable/image/grid.rs
@@ -11,7 +11,8 @@ use wcs::WCS;
pub fn get_grid_params(
xy_min: &(f64, f64),
xy_max: &(f64, f64),
- max_tex_size: u64,
+ max_tex_size_x: u64,
+ max_tex_size_y: u64,
num_tri_per_tex_patch: u64,
) -> (
impl Iterator- + Clone,
@@ -31,8 +32,8 @@ pub fn get_grid_params(
let step = (step_x.max(step_y)).max(1); // at least one pixel!
(
- get_coord_uv_it(xmin, xmax, step, max_tex_size),
- get_coord_uv_it(ymin, ymax, step, max_tex_size),
+ get_coord_uv_it(xmin, xmax, step, max_tex_size_x),
+ get_coord_uv_it(ymin, ymax, step, max_tex_size_y),
)
}
@@ -169,13 +170,20 @@ fn build_range_indices(it: impl Iterator
- + Clone) -> Vec (Vec, Vec, Vec, Vec) {
- let (x_it, y_it) = get_grid_params(xy_min, xy_max, max_tex_size, num_tri_per_tex_patch);
+ let (x_it, y_it) = get_grid_params(
+ xy_min,
+ xy_max,
+ max_tex_size_x,
+ max_tex_size_y,
+ num_tri_per_tex_patch,
+ );
let idx_x_ranges = build_range_indices(x_it.clone());
let idx_y_ranges = build_range_indices(y_it.clone());
diff --git a/src/core/src/renderable/image/mod.rs b/src/core/src/renderable/image/mod.rs
index fad4923f..15fc4bb6 100644
--- a/src/core/src/renderable/image/mod.rs
+++ b/src/core/src/renderable/image/mod.rs
@@ -62,13 +62,15 @@ pub struct Image {
/// Texture indices that must be drawn
idx_tex: Vec,
/// The maximum webgl supported texture size
- max_tex_size: usize,
+ max_tex_size_x: usize,
+ max_tex_size_y: usize,
reg: Region,
// The coo system in which the polygonal region has been defined
coo_sys: CooSystem,
}
-
+use al_core::pixel::Pixel;
+use al_core::texture::TEX_PARAMS;
use fitsrs::hdu::header::extension;
use fitsrs::hdu::AsyncHDU;
use futures::io::BufReader;
@@ -76,7 +78,7 @@ use futures::AsyncReadExt;
impl Image {
pub async fn from_reader_and_wcs(
gl: &WebGlContext,
- reader: R,
+ mut reader: R,
wcs: WCS,
mut scale: Option,
mut offset: Option,
@@ -94,20 +96,86 @@ impl Image {
WebGl2RenderingContext::get_parameter(gl, WebGl2RenderingContext::MAX_TEXTURE_SIZE)?
.as_f64()
.unwrap_or(4096.0) as usize;
- let (textures, mut cuts) =
- subdivide_texture::build::(gl, width, height, reader, max_tex_size, blank)
- .await?;
+
+ let mut max_tex_size_x = max_tex_size;
+ let mut max_tex_size_y = max_tex_size;
// apply bscale to the cuts
if F::NUM_CHANNELS == 1 {
offset = offset.or(Some(0.0));
scale = scale.or(Some(1.0));
blank = blank.or(Some(std::f32::NAN));
- cuts = cuts.map(|cuts| {
- let start = cuts.start * scale.unwrap() + offset.unwrap();
- let end = cuts.end * scale.unwrap() + offset.unwrap();
- start..end
- });
+ }
+
+ let (textures, mut cuts) = if width <= max_tex_size as u64 && height <= max_tex_size as u64
+ {
+ max_tex_size_x = width as usize;
+ max_tex_size_y = height as usize;
+ // can fit in one texture
+
+ let num_pixels_to_read = (width as usize) * (height as usize);
+ let num_bytes_to_read =
+ num_pixels_to_read * std::mem::size_of::<::Item>() * F::NUM_CHANNELS;
+ let mut buf = vec![0; num_bytes_to_read];
+
+ let _ = reader.read_exact(&mut buf[..]).await.map_err(|e| {
+ JsValue::from_str("invalid data with respect to the NAXIS given in the WCS")
+ })?;
+
+ unsafe {
+ let slice = std::slice::from_raw_parts(
+ buf.as_mut_ptr() as *const ::Item,
+ num_bytes_to_read / std::mem::size_of::<::Item>(),
+ );
+
+ let cuts = if F::NUM_CHANNELS == 1 {
+ let mut samples = slice
+ .iter()
+ .filter_map(|item| {
+ let t: f32 =
+ <::Item as al_core::convert::Cast>::cast(*item);
+ if t.is_nan() || t == blank.unwrap() {
+ None
+ } else {
+ Some(t)
+ }
+ })
+ .collect::>();
+
+ let cuts = cuts::first_and_last_percent(&mut samples, 1, 99);
+ Some(cuts)
+ } else {
+ None
+ };
+
+ (
+ vec![Texture2D::create_from_raw_pixels::(
+ gl,
+ width as i32,
+ height as i32,
+ TEX_PARAMS,
+ Some(slice),
+ )?],
+ cuts,
+ )
+ }
+ } else {
+ subdivide_texture::crop_image::(
+ gl,
+ width,
+ height,
+ reader,
+ max_tex_size as u64,
+ blank,
+ )
+ .await?
+ };
+
+ if let Some(cuts) = cuts.as_mut() {
+ let start = cuts.start * scale.unwrap() + offset.unwrap();
+ let end = cuts.end * scale.unwrap() + offset.unwrap();
+
+ *cuts = start..end;
}
let num_indices = vec![];
@@ -213,7 +281,8 @@ impl Image {
channel: F::CHANNEL_TYPE,
textures,
cuts,
- max_tex_size,
+ max_tex_size_x,
+ max_tex_size_y,
// Indices of textures that must be drawn
idx_tex,
// The polygonal region in the sky
@@ -484,7 +553,8 @@ impl Image {
let (pos, uv, indices, num_indices) = grid::vertices(
&(x_mesh_range.start, y_mesh_range.start),
&(x_mesh_range.end.ceil(), y_mesh_range.end.ceil()),
- self.max_tex_size as u64,
+ self.max_tex_size_x as u64,
+ self.max_tex_size_y as u64,
num_vertices,
camera,
&self.wcs,
diff --git a/src/core/src/renderable/image/subdivide_texture.rs b/src/core/src/renderable/image/subdivide_texture.rs
index f1dd8fa1..61e7bf5d 100644
--- a/src/core/src/renderable/image/subdivide_texture.rs
+++ b/src/core/src/renderable/image/subdivide_texture.rs
@@ -10,26 +10,30 @@ use al_core::Texture2D;
use al_core::WebGlContext;
use std::ops::Range;
-pub async fn build<'a, F, R>(
+pub async fn crop_image<'a, F, R>(
gl: &WebGlContext,
width: u64,
height: u64,
mut reader: R,
- max_tex_size: usize,
+ max_tex_size: u64,
blank: Option,
) -> Result<(Vec, Option>), JsValue>
where
F: ImageFormat,
R: AsyncReadExt + Unpin,
{
- let mut buf =
- vec![0; max_tex_size * std::mem::size_of::<::Item>() * F::NUM_CHANNELS];
- let max_tex_size = max_tex_size as u64;
+ let mut tex_chunks = vec![];
// Subdivision
let num_textures = ((width / max_tex_size) + 1) * ((height / max_tex_size) + 1);
- let mut tex_chunks = vec![];
+ let mut buf = vec![
+ 0;
+ (max_tex_size as usize)
+ * std::mem::size_of::<::Item>()
+ * F::NUM_CHANNELS
+ ];
+
for _ in 0..num_textures {
tex_chunks.push(Texture2D::create_from_raw_pixels::(
gl,
diff --git a/src/core/src/renderable/moc/mod.rs b/src/core/src/renderable/moc/mod.rs
index 67a78206..bf8fc0ad 100644
--- a/src/core/src/renderable/moc/mod.rs
+++ b/src/core/src/renderable/moc/mod.rs
@@ -451,7 +451,9 @@ impl MOCIntern {
.attach_uniforms_from(camera)
.attach_uniform("u_2world", &icrs2world)
.attach_uniform("u_color", &color)
- .attach_uniform("u_width", &thickness)
+ .attach_uniform("u_width", &(camera.get_width()))
+ .attach_uniform("u_height", &(camera.get_height()))
+ .attach_uniform("u_thickness", &thickness)
.attach_uniform("u_proj", proj)
.bind_vertex_array_object_ref(&self.vao)
.draw_elements_instanced_with_i32(
@@ -487,7 +489,9 @@ impl MOCIntern {
.attach_uniforms_from(camera)
.attach_uniform("u_2world", &icrs2world)
.attach_uniform("u_color", &color)
- .attach_uniform("u_width", &thickness)
+ .attach_uniform("u_width", &(camera.get_width()))
+ .attach_uniform("u_height", &(camera.get_height()))
+ .attach_uniform("u_thickness", &thickness)
.attach_uniform("u_proj", proj)
.bind_vertex_array_object_ref(&self.vao)
.draw_elements_instanced_with_i32(
diff --git a/src/css/aladin.css b/src/css/aladin.css
index 84eefc1b..fca00590 100644
--- a/src/css/aladin.css
+++ b/src/css/aladin.css
@@ -328,10 +328,10 @@ canvas {
}
.aladin-btn.aladin-dark-theme.toggled {
- border-color: greenyellow;
+ border-color: dodgerblue;
}
.aladin-btn.aladin-dark-theme:hover, .aladin-input-select.aladin-dark-theme:hover {
- border-color: red;
+ border-color: greenyellow;
}
.aladin-btn.disabled {
@@ -1176,13 +1176,13 @@ canvas {
line-height: 1.7rem;
}
-.aladin-fov .aladin-zoom-in {
+.aladin-fov .aladin-zoom-out {
margin-right: 0;
border-right: none;
border-radius: 5px 0px 0px 5px;
}
-.aladin-fov .aladin-zoom-out {
+.aladin-fov .aladin-zoom-in {
border-radius: 0px 5px 5px 0px;
}
diff --git a/src/glsl/webgl2/line/base.vert b/src/glsl/webgl2/line/base.vert
index fef41d55..a5ce9c2e 100644
--- a/src/glsl/webgl2/line/base.vert
+++ b/src/glsl/webgl2/line/base.vert
@@ -1,5 +1,5 @@
#version 300 es
-precision lowp float;
+precision highp float;
layout (location = 0) in vec2 ndc_pos;
out float l;
diff --git a/src/glsl/webgl2/line/inst_lonlat.vert b/src/glsl/webgl2/line/inst_lonlat.vert
index 9687b972..309b9140 100644
--- a/src/glsl/webgl2/line/inst_lonlat.vert
+++ b/src/glsl/webgl2/line/inst_lonlat.vert
@@ -8,6 +8,8 @@ uniform mat4 u_2world;
uniform vec2 ndc_to_clip;
uniform float czf;
uniform float u_width;
+uniform float u_height;
+uniform float u_thickness;
out float l;
@@ -34,6 +36,7 @@ void main() {
vec2 x_b = p_b_ndc - p_a_ndc;
vec2 y_b = normalize(vec2(-x_b.y, x_b.x));
- vec2 p_ndc = p_a_ndc + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y;
+ float ndc2pix = 2.0 / u_width;
+ vec2 p_ndc = p_a_ndc + x_b * vertex.x + u_thickness * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix;
gl_Position = vec4(p_ndc, 0.f, 1.f);
}
\ No newline at end of file
diff --git a/src/glsl/webgl2/line/inst_ndc.vert b/src/glsl/webgl2/line/inst_ndc.vert
index f12f6f54..2a982ab3 100644
--- a/src/glsl/webgl2/line/inst_ndc.vert
+++ b/src/glsl/webgl2/line/inst_ndc.vert
@@ -1,5 +1,5 @@
#version 300 es
-precision lowp float;
+precision highp float;
layout (location = 0) in vec2 p_a;
layout (location = 1) in vec2 p_b;
layout (location = 2) in vec2 vertex;
@@ -7,11 +7,15 @@ layout (location = 2) in vec2 vertex;
out float l;
uniform float u_width;
+uniform float u_height;
+uniform float u_thickness;
void main() {
vec2 x_b = p_b - p_a;
vec2 y_b = normalize(vec2(-x_b.y, x_b.x));
- vec2 p = p_a + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y;
+ float ndc2pix = 2.0 / u_width;
+
+ vec2 p = p_a + x_b * vertex.x + u_thickness * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix;
gl_Position = vec4(p, 0.f, 1.f);
}
\ No newline at end of file
diff --git a/src/js/A.js b/src/js/A.js
index f2b75dbd..6b6dbe6d 100644
--- a/src/js/A.js
+++ b/src/js/A.js
@@ -201,7 +201,7 @@ A.polygon = function (raDecArray, options) {
}
options = options || {};
- //options.closed = true;
+ options.closed = true;
return new Polyline(raDecArray, options);
};
diff --git a/src/js/Aladin.js b/src/js/Aladin.js
index 52f8ff5f..8dc4812c 100644
--- a/src/js/Aladin.js
+++ b/src/js/Aladin.js
@@ -88,6 +88,8 @@ import { Polyline } from "./shapes/Polyline";
* @property {string} [target="0 +0"] - Target coordinates for the initial view.
* @property {CooFrame} [cooFrame="J2000"] - Coordinate frame.
* @property {number} [fov=60] - Field of view in degrees.
+ * @property {number} [northPoleOrientation=0] - North pole orientation in degrees. By default it is set to 0 deg i.e. the north pole will be found vertically north to the view.
+ * Positive orientation goes towards east i.e. in counter clockwise order as the east lies in the left direction of the view.
* @property {string} [backgroundColor="rgb(60, 60, 60)"] - Background color in RGB format.
*
* @property {boolean} [showZoomControl=true] - Whether to show the zoom control toolbar.
@@ -246,7 +248,9 @@ import { Polyline } from "./shapes/Polyline";
'mouseMove',
'fullScreenToggled',
- 'cooFrameChanged'
+ 'cooFrameChanged',
+ 'resizeChanged',
+ 'projectionChanged',
*/
export let Aladin = (function () {
@@ -564,6 +568,10 @@ export let Aladin = (function () {
if (options.inertia !== undefined) {
this.wasm.setInertia(options.inertia);
}
+
+ if (options.northPoleOrientation) {
+ this.setViewCenter2NorthPoleAngle(options.northPoleOrientation);
+ }
};
Aladin.prototype._setupUI = function (options) {
@@ -704,6 +712,7 @@ export let Aladin = (function () {
target: "0 +0",
cooFrame: "J2000",
fov: 60,
+ northPoleOrientation: 0,
inertia: true,
backgroundColor: "rgb(60, 60, 60)",
// Zoom toolbar
@@ -739,7 +748,7 @@ export let Aladin = (function () {
gridOptions: {
enabled: false,
showLabels: true,
- thickness: 3,
+ thickness: 2,
labelSize: 15,
},
projection: "SIN",
@@ -815,7 +824,7 @@ export let Aladin = (function () {
var fullScreenToggledFn =
self.callbacksByEventName["fullScreenToggled"];
typeof fullScreenToggledFn === "function" &&
- fullScreenToggledFn(isInFullscreen);
+ fullScreenToggledFn(self.isInFullscreen);
};
Aladin.prototype.getOptionsFromQueryString = function () {
@@ -1966,6 +1975,8 @@ export let Aladin = (function () {
"fullScreenToggled",
"cooFrameChanged",
+ "resizeChanged",
+ "projectionChanged"
];
/**
diff --git a/src/js/ImageFITS.js b/src/js/ImageFITS.js
index 297f77a1..38d29868 100644
--- a/src/js/ImageFITS.js
+++ b/src/js/ImageFITS.js
@@ -247,7 +247,7 @@ export let Image = (function () {
promise =
new Promise((resolve, reject) => {
- img.src = Aladin.JSONP_PROXY + '?url=' + this.url;
+ img.src = this.url;
img.crossOrigin = "Anonymous";
img.onload = () => {
var canvas = document.createElement("canvas");
@@ -264,11 +264,19 @@ export let Image = (function () {
const blob = new Blob([imageData.data]);
const stream = blob.stream(1024);
- return resolve(stream)
+ resolve(stream)
}
+ let proxyUsed = false;
img.onerror = () => {
- return reject('Error parsing img ' + self.url)
+ // use proxy
+ if (proxyUsed) {
+ reject('Error parsing img ' + self.url)
+ return;
+ }
+
+ proxyUsed = true;
+ img.src = Aladin.JSONP_PROXY + '?url=' + self.url;
}
})
.then((readableStream) => {
diff --git a/src/js/Source.js b/src/js/Source.js
index 585d614b..54e92049 100644
--- a/src/js/Source.js
+++ b/src/js/Source.js
@@ -131,7 +131,7 @@ export let Source = (function() {
if (!obj) {
obj = this;
}
- view.selectObjects([obj]);
+ view.selectObjects([[obj]]);
}
else if (this.catalog.onClick == 'showPopup') {
view.aladin.popup.setTitle('
');
diff --git a/src/js/View.js b/src/js/View.js
index 4491bff5..5f33b833 100644
--- a/src/js/View.js
+++ b/src/js/View.js
@@ -153,6 +153,14 @@ export let View = (function () {
View.CALLBACKS_THROTTLE_TIME_MS,
);
+ this.throttledDivResized = Utils.throttle(
+ () => {
+ const resizeFn = self.aladin.callbacksByEventName['resizeChanged'];
+ (typeof resizeFn === 'function') && resizeFn(self.width, self.height);
+ },
+ View.CALLBACKS_THROTTLE_TIME_MS,
+ );
+
this.mustClearCatalog = true;
this.mode = View.PAN;
@@ -416,6 +424,8 @@ export let View = (function () {
this.computeNorder();
this.aladinDiv.style.removeProperty('line-height');
+
+ this.throttledDivResized();
};
var pixelateCanvasContext = function (ctx, pixelateFlag) {
@@ -1907,11 +1917,14 @@ export let View = (function () {
}
this.projection = ProjectionEnum[projName];
-
+
// Change the projection here
this.wasm.setProjection(projName);
this.updateZoomState();
+ const projFn = this.aladin.callbacksByEventName['projectionChanged'];
+ (typeof projFn === 'function') && projFn(projName);
+
this.requestRedraw();
};
@@ -1992,7 +2005,6 @@ export let View = (function () {
this.viewCenter.lon = ra;
this.viewCenter.lat = dec;
- //this.updateLocation({lon: this.viewCenter.lon, lat: this.viewCenter.lat});
// Put a javascript code here to do some animation
this.wasm.setCenter(this.viewCenter.lon, this.viewCenter.lat);
diff --git a/src/js/gui/FoV.js b/src/js/gui/FoV.js
index 13d93a2d..c29ea48a 100644
--- a/src/js/gui/FoV.js
+++ b/src/js/gui/FoV.js
@@ -73,8 +73,8 @@ export class FoV extends DOMElement {
zoomIn.el.classList.add('aladin-zoom-in');
zoomOut.el.classList.add('aladin-zoom-out');
- layout.push(zoomIn)
layout.push(zoomOut)
+ layout.push(zoomIn)
}
if (options.showFov) {
diff --git a/src/js/vo/samp.js b/src/js/vo/samp.js
index cdfb5ca5..5cdb4161 100644
--- a/src/js/vo/samp.js
+++ b/src/js/vo/samp.js
@@ -144,7 +144,8 @@ export class SAMPConnector {
let catalog = selectCatalog(id, url)
if (catalog) {
- aladin.selectObjects([catalog.sources[row]]);
+ const source = catalog.sources[row];
+ aladin.selectObjects([[source]]);
}
};