Compare commits

..

4 Commits
vr ... SAMP

Author SHA1 Message Date
Matthieu Baumann
e14b2694ca add subscribers 2023-10-30 18:14:38 +01:00
Matthieu Baumann
e0c2288306 first SAMP commit 2023-10-30 15:37:24 +01:00
Matthieu Baumann
328129896f force MOC.fill = true if opacity is defined 2023-10-23 10:14:28 +02:00
Matthieu Baumann
733f81fc6b big circle draw fix for #126. Try to make the source inside the circle 2023-10-23 10:00:13 +02:00
19 changed files with 1547 additions and 469 deletions

View File

@@ -10,11 +10,14 @@
import A from '../src/js/A.js';
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: 180});
var overlay = A.graphicOverlay({color: '#ee2345', lineWidth: 3});
aladin.addOverlay(overlay);
overlay.add(A.circle(83.66067, 22.03081, 40.0, {color: 'cyan'})); // radius in degrees
overlay.add(A.circle(83.66067, 0, 30, {color: 'cyan'})); // radius in degrees
var cat = A.catalog({name: 'Some markers', sourceSize: 18});
aladin.addCatalog(cat);
cat.addSources([A.marker(83, 29, {popupTitle: 'Point1', popupDesc: 'Does not show up in circle'})]);
aladin.on("footprintClicked", (footprint) => {
console.log("footprint clicked catched", footprint)

View File

@@ -8,7 +8,7 @@
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {projection: "TAN", target: '15 16 57.636 -60 55 7.49', showCooGrid: true, fov: 90, fullScreen: true});
aladin = A.aladin('#aladin-lite-div', {projection: "TAN", target: '15 16 57.636 -60 55 7.49', samp: true, showCooGrid: true, fov: 90, fullScreen: true});
var moc_0_99 = A.MOCFromURL("./gw/gw_0.9.fits",{ name: "GW 90%", color: "#ff0000", opacity: 0.7, lineWidth: 5, perimeter: true});
var moc_0_95 = A.MOCFromURL("./gw/gw_0.6.fits",{ name: "GW 60%", color: "#00ff00", opacity: 0.8, lineWidth: 5, perimeter: true});

View File

@@ -12,13 +12,13 @@
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {target: '00 00 00 +07 00 00', fov: 130, survey: 'P/Mellinger/color'});
var moc11 = A.MOCFromURL('http://skies.esac.esa.int/HST/NICMOS/Moc.fits', {color: '#84f', lineWidth: 3, opacity: 1.0}, (moc) => {
var moc11 = A.MOCFromURL('http://skies.esac.esa.int/HST/NICMOS/Moc.fits', {color: '#84f', lineWidth: 3, fill: true}, (moc) => {
// moc is ready
console.log(moc.contains(205.9019247, +2.4492764));
console.log(moc.contains(-205.9019247, +2.4492764));
});
var moc10 = A.MOCFromURL('https://alasky.unistra.fr/MocServer/query?ivorn=ivo%3A%2F%2FCDS%2FV%2F139%2Fsdss9&get=moc&order=11&fmt=fits', {color: '#ffffff', perimeter: true, fillColor: '#aabbcc', opacity: 0.1, fill: true, lineWidth: 3});
var moc10 = A.MOCFromURL('https://alasky.unistra.fr/MocServer/query?ivorn=ivo%3A%2F%2FCDS%2FV%2F139%2Fsdss9&get=moc&order=11&fmt=fits', {color: '#ffffff', perimeter: true, fillColor: '#aabbcc', opacity: 0.1, lineWidth: 3});
var moc9 = A.MOCFromURL('https://alasky.unistra.fr/MocServer/query?ivorn=ivo%3A%2F%2FCDS%2FV%2F139%2Fsdss9&get=moc&order=4&fmt=fits', {color: '#00ff00', opacity: 0.5, lineWidth: 3, perimeter: true});
aladin.addMOC(moc11);

View File

@@ -1,113 +0,0 @@
<!doctype html>
<html>
<head>
</head>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.157.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.157.0/examples/jsm/"
}
}
</script>
<body>
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
<script type="module">
import A from '../src/js/A.js';
import * as THREE from 'three';
let aladin;
A.init.then(() => {
aladin = A.aladin(
'#aladin-lite-div',
{
survey: 'P/DSS2/color', // set a survey
projection: 'TAN', // set a projection
fov: 70, // initial field of view in degrees
target: '338.98958 33.96', // initial target
cooFrame: 'equatorial', // set galactic frame
showCooGrid: true, // set the grid
fullScreen: true,
vr: {animation: animate.bind(renderer)},
}
);
//aladin.setOverlayImageLayer("https://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam+MIRI")
initScene(aladin.view.imageCanvas);
aladin.setRenderer(renderer);
});
let renderer = null;
let scene = null;
let camera = null;
let cubeMesh = null;
// let controls = null;
/**
* Initializes a 3D scene, camera, and renderer for virtual reality (VR).
*
* @param {HTMLCanvasElement} canvas - The HTML canvas element to render the
* 3D scene
*/
function initScene(canvas) {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
scene.add(camera);
renderer = new THREE.WebGLRenderer({canvas: canvas, context: canvas.getContext('webgl2', {xrCompatible: true})}); // NOTE Une différence ici
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
// renderer.xr.setReferenceSpaceType('local');
renderer.autoClear = false;
const light = new THREE.PointLight(0xffffff, 10);
light.position.set(0, 2, 1);
scene.add(light);
const planeGeometry = new THREE.PlaneGeometry(10, 10);
const planeMaterial = new THREE.MeshPhongMaterial({ color: 0xff00ff });
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
planeMesh.position.set(0, -1, 0);
planeMesh.rotation.x = -Math.PI / 2;
scene.add(planeMesh);
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
cubeMesh = new THREE.Mesh(cubeGeometry, cubeMaterial);
cubeMesh.position.set(0, 0, -2);
scene.add(cubeMesh);
}
/**
* Function to animate the 3D scene and rendering it.
*/
function animate() {
cubeMesh.rotation.x += 0.001;
cubeMesh.rotation.y += 0.001;
renderer.render( scene, camera );
}
// /**
// * Initializes a WebGL2 context and handles potential errors.
// */
// function initWebGL2() {
// // canvas = aladin.view.imageCanvas;
// canvas = document.getElementById(aladin.view.imageCanvas);
// // gl = canvas.getContext("webgl2", { alpha: true });
// gl = canvas.getContext('webgl2');
// if (!gl) { // If the gl didn't create properly
// alert('This browser doesn\'t support WebGL2');
// return;
// }
// }
</script>
</body>
</html>

View File

@@ -9,8 +9,8 @@ pub mod vao {
use crate::object::element_array_buffer::ElementArrayBuffer;
use crate::webgl_ctx::WebGlContext;
use crate::Abort;
use std::collections::HashMap;
use crate::Abort;
pub struct VertexArrayObject {
array_buffer: HashMap<&'static str, ArrayBuffer>,
@@ -88,10 +88,7 @@ pub mod vao {
}*/
pub fn num_elements(&self) -> usize {
self.element_array_buffer
.as_ref()
.unwrap_abort()
.num_elements()
self.element_array_buffer.as_ref().unwrap_abort().num_elements()
}
pub fn num_instances(&self) -> i32 {
@@ -158,7 +155,6 @@ pub mod vao {
pub fn unbind(&self) {
self.vao.gl.bind_vertex_array(None);
self._shader.unbind(&self.vao.gl);
}
}
@@ -174,9 +170,8 @@ pub mod vao {
}
impl<'a, 'b> ShaderVertexArrayObjectBoundRef<'a, 'b> {
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) -> &Self {
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) {
self.vao.gl.draw_arrays(mode, byte_offset, size);
self
}
pub fn draw_elements_with_i32(
@@ -185,12 +180,11 @@ pub mod vao {
num_elements: Option<i32>,
type_: u32,
byte_offset: i32,
) -> &Self {
) {
let num_elements = num_elements.unwrap_or(self.vao.num_elements() as i32);
self.vao
.gl
.draw_elements_with_i32(mode, num_elements, type_, byte_offset);
self
}
pub fn draw_elements_instanced_with_i32(
@@ -198,7 +192,7 @@ pub mod vao {
mode: u32,
offset_element_idx: i32,
num_instances: i32,
) -> &Self {
) {
self.vao.gl.draw_elements_instanced_with_i32(
mode,
self.vao.num_elements() as i32,
@@ -206,12 +200,10 @@ pub mod vao {
offset_element_idx,
num_instances,
);
self
}
pub fn unbind(&self) {
self.vao.gl.bind_vertex_array(None);
self._shader.unbind(&self.vao.gl);
}
}
@@ -452,10 +444,7 @@ pub mod vao {
}*/
pub fn num_elements(&self) -> usize {
self.element_array_buffer
.as_ref()
.unwrap_abort()
.num_elements()
self.element_array_buffer.as_ref().unwrap_abort().num_elements()
}
pub fn num_instances(&self) -> i32 {
@@ -522,8 +511,7 @@ pub mod vao {
}
pub fn unbind(&self) {
self.vao.gl.bind_vertex_array(None);
self._shader.unbind(&self.vao.gl);
//self.vao.gl.bind_vertex_array(None);
}
}
@@ -540,15 +528,13 @@ pub mod vao {
}
use crate::object::array_buffer::VertexBufferObject;
impl<'a, 'b> ShaderVertexArrayObjectBoundRef<'a, 'b> {
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) -> &Self {
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) {
for (attr, buf) in self.vao.array_buffer.iter() {
buf.bind();
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
}
self.vao.gl.draw_arrays(mode, byte_offset, size);
self
}
pub fn draw_elements_with_i32(
@@ -557,7 +543,7 @@ pub mod vao {
num_elements: Option<i32>,
type_: u32,
byte_offset: i32,
) -> &Self {
) {
for (attr, buf) in self.vao.array_buffer.iter() {
buf.bind();
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
@@ -569,7 +555,6 @@ pub mod vao {
self.vao
.gl
.draw_elements_with_i32(mode, num_elements, type_, byte_offset);
self
}
pub fn draw_elements_instanced_with_i32(
@@ -577,7 +562,7 @@ pub mod vao {
mode: u32,
offset_element_idx: i32,
num_instances: i32,
) -> &Self {
) {
for (attr, buf) in self.vao.array_buffer.iter() {
buf.bind();
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
@@ -602,12 +587,10 @@ pub mod vao {
offset_element_idx,
num_instances,
);
self
}
pub fn unbind(&self) {
self.vao.gl.bind_vertex_array(None);
self.shader.unbind(&self.vao.gl);
//self.vao.gl.bind_vertex_array(None);
}
}
@@ -733,9 +716,6 @@ pub mod vao {
pub fn unbind(&self) {
//self.vao.gl.bind_vertex_array(None);
self.vao.gl.bind_vertex_array(None);
self.shader.unbind(&self.vao.gl);
}
}

View File

@@ -875,7 +875,7 @@ impl App {
&self.colormaps,
&self.projection,
)?;
/*
// Draw the catalog
//let fbo_view = &self.fbo_view;
//catalogs.draw(&gl, shaders, camera, colormaps, fbo_view)?;
@@ -903,7 +903,7 @@ impl App {
self.line_renderer.draw(&self.camera)?;
//let dpi = self.camera.get_dpi();
//ui.draw(&gl, dpi)?;
*/
// Reset the flags about the user action
self.camera.reset();

View File

@@ -1047,8 +1047,7 @@ impl HiPS {
Some(self.num_idx as i32),
WebGl2RenderingContext::UNSIGNED_SHORT,
0,
)
.unbind();
);
}
Ok(())

View File

@@ -225,8 +225,7 @@ impl RayTracer {
None,
WebGl2RenderingContext::UNSIGNED_SHORT,
0,
)
.unbind();
);
#[cfg(feature = "webgl2")]
shader
.attach_uniform("position_tex", &self.position_tex)
@@ -237,7 +236,6 @@ impl RayTracer {
WebGl2RenderingContext::UNSIGNED_SHORT,
0,
)
.unbind();
}
pub fn is_rendering(&self, camera: &CameraViewPort) -> bool {

View File

@@ -612,8 +612,7 @@ impl Image {
Some(num_indices),
WebGl2RenderingContext::UNSIGNED_SHORT,
((off_indices as usize) * std::mem::size_of::<u16>()) as i32,
)
.unbind();
);
off_indices += self.num_indices[idx];
}

View File

@@ -259,8 +259,7 @@ impl Layers {
None,
WebGl2RenderingContext::UNSIGNED_SHORT,
0,
)
.unbind();
);
}
// The first layer must be paint independently of its alpha channel

View File

@@ -165,8 +165,6 @@ A.MOCFromJSON = function (jsonMOC, options) {
};
// TODO: try first without proxy, and then with, if param useProxy not set
// API
A.catalogFromURL = function (url, options, successCallback, errorCallback, useProxy) {
var catalog = A.catalog(options);

View File

@@ -50,8 +50,8 @@ import { ContextMenu } from "./gui/ContextMenu.js";
import { ALEvent } from "./events/ALEvent.js";
import { Color } from './Color.js';
import { ImageFITS } from "./ImageFITS.js";
import { VRButton } from "./VRButton.js";
import { DefaultActionsForContextMenu } from "./DefaultActionsForContextMenu.js";
import { SAMPConnector } from "./vo/samp.js";
import A from "./A.js";
import $ from 'jquery';
@@ -459,8 +459,7 @@ export let Aladin = (function () {
//this.discoverytree = new DiscoveryTree(this);
//}
// [ ] That might pose problems
//this.view.redraw();
this.view.redraw();
// go to full screen ?
if (options.fullScreen) {
@@ -474,9 +473,11 @@ export let Aladin = (function () {
this.contextMenu.attachTo(this.view.catalogCanvas, DefaultActionsForContextMenu.getDefaultActions(this));
}
// initialize the VR button
if (options.vr) {
this.aladinDiv.appendChild(VRButton.createButton(this.view));
if (options.samp) {
this.samp = new SAMPConnector(this);
ALEvent.SAMP_AVAILABILITY.listenedBy(this.aladinDiv, function (e) {
console.log('is hub running samp', e.detail.isHubRunning)
});
}
};
@@ -511,6 +512,7 @@ export let Aladin = (function () {
reticleColor: "rgb(178, 50, 178)",
reticleSize: 22,
log: true,
samp: true,
allowFullZoomout: false,
realFullscreen: false,
showAllskyRing: false,
@@ -678,11 +680,6 @@ export let Aladin = (function () {
});
};
// @API
Aladin.prototype.setRenderer = function(renderer) {
this.options.vr.renderer = renderer;
}
Aladin.prototype.setFrame = function (frameName) {
if (!frameName) {
return;

View File

@@ -167,8 +167,8 @@ export let Circle = (function() {
let hidden = true;
var ra, dec, vertOnCircle, dx, dy;
if (view.fov > 90) {
this.radius = Number.POSITIVE_INFINITY;
//if (this.radiusDegrees > 30) {
this.radius = Number.NEGATIVE_INFINITY;
// Project 4 points lying on the circle and take the minimal dist with the center as radius
[[-1, 0], [1, 0], [0, -1], [0, 1]].forEach(([cardDirRa, cardDirDec]) => {
@@ -181,12 +181,12 @@ export let Circle = (function() {
dx = vertOnCircle[0] - this.center.x;
dy = vertOnCircle[1] - this.center.y;
this.radius = Math.min(Math.sqrt(dx*dx + dy*dy), this.radius);
this.radius = Math.max(Math.sqrt(dx*dx + dy*dy), this.radius);
hidden = false;
}
});
} else {
/*} else {
ra = this.centerRaDec[0] + this.radiusDegrees;
dec = this.centerRaDec[1];
@@ -199,7 +199,7 @@ export let Circle = (function() {
this.radius = Math.sqrt(dx*dx + dy*dy);
hidden = false;
}
}
}*/
if (hidden) {
return;

View File

@@ -37,12 +37,19 @@ export let MOC = (function() {
} else {
this.perimeter = false;
}
this.opacity = options.opacity || 1;
if (options && options.fill) {
this.fill = true;
} else {
this.fill = false;
}
if (options && options.opacity) {
this.fill = true;
}
if (options && options.edge) {
this.edge = true;
} else {
@@ -53,8 +60,6 @@ export let MOC = (function() {
this.edge = true;
}
this.opacity = options.opacity || 1;
this.opacity = Math.max(0, Math.min(1, this.opacity)); // 0 <= this.opacity <= 1
this.lineWidth = options["lineWidth"] || 1;

View File

@@ -1,252 +0,0 @@
/**
* This is an adaptation of the original VRButton.
* Original at:
* https://github.com/mrdoob/three.js/blob/dev/examples/jsm/webxr/VRButton.js
*/
/**
* VRButton class that handles the creation of a VR session
*
* @class VRButton
*/
class VRButton {
/**
* Constructs a VRButton
*
* @static
* @param {View} view - The aladin view
* @return {HTMLButtonElement|HTMLAnchorElement} The VR mode button or an
* error message
*/
static createButton(view) {
const button = document.createElement('button');
/**
* Function for handling the process of entering VR mode.
*/
function showEnterVR(/* device*/) {
let currentSession = null;
/**
* Callback function to handle when the XR session is started
*
* @param {XRSession} session - The XR session that has been started
*/
async function onSessionStarted(session) {
session.addEventListener('end', onSessionEnded);
let gl = view.imageCanvas.getContext('webgl2');
await gl.makeXRCompatible();
session.updateRenderState({
baseLayer: new XRWebGLLayer(session, gl)
});
await view.options.vr.renderer.xr.setSession(session);
button.textContent = 'EXIT VR';
// view.options.vr.renderer.setAnimationLoop(view.redrawVR.bind(view));
session.requestReferenceSpace('local-floor').then((refSpace) => {
const xrRefSpace = refSpace;
session.requestAnimationFrame((t, frame) => {view.redrawVR(t, frame, xrRefSpace)});
});
currentSession = session;
}
/**
* Function to render the whole scene
*/
// NOTE A supprimer
function onXRAnimationFrame(t, xrFrame) {
currentSession.requestAnimationFrame(onXRAnimationFrame);
view.redrawVR();
}
/**
* Callback function to handle when the XR session ends
*/
function onSessionEnded(/* event*/) {
currentSession.removeEventListener('end', onSessionEnded);
button.textContent = 'ENTER VR';
currentSession = null;
}
//
button.style.display = '';
button.style.cursor = 'pointer';
button.style.left = 'calc(50% - 50px)';
button.style.width = '100px';
button.textContent = 'ENTER VR';
button.onmouseenter = function() {
button.style.opacity = '1.0';
};
button.onmouseleave = function() {
button.style.opacity = '0.5';
};
button.onclick = function() {
if (currentSession === null) {
// WebXR's requestReferenceSpace only works if the corresponding
// feature was requested at session creation time. For simplicity,
// just ask for the interesting ones as optional features, but be
// aware that the requestReferenceSpace call will fail if it turns
// out to be unavailable.
// ('local' is always available for immersive sessions and doesn't
// need to be requested separately.)
const sessionInit = {optionalFeatures: ['local-floor']};
navigator.xr.requestSession(
'immersive-vr', sessionInit).then(onSessionStarted);
} else {
currentSession.end();
}
};
}
/**
* Function for disabling the VR mode button
*
* @param {HTMLButtonElement} button - The VR mode button element to
* be disabled
*/
function disableButton() {
button.style.display = '';
button.style.cursor = 'auto';
button.style.left = 'calc(50% - 75px)';
button.style.width = '150px';
button.onmouseenter = null;
button.onmouseleave = null;
button.onclick = null;
}
/**
* Function for handling the case where WebXR is not supported
*
* @description This function disables the VR mode button and displays a
* message indicating that VR is not supported
*
* @param {HTMLButtonElement} button - The VR mode button element to be
* disabled and updated with a message
*/
function showWebXRNotFound() {
disableButton();
button.textContent = 'VR NOT SUPPORTED';
}
/**
* Function for handling the case where VR is not allowed due to an
* exception
*
* @description This function disables the VR mode button, logs an
* exception to the console, and displays a message indicating that VR
* is not allowed
*
* @param {any} exception - The exception object or error that indicates
* why VR is not allowed
* @param {HTMLButtonElement} button - The VR mode button element to be
* disabled and updated with a message
*/
function showVRNotAllowed(exception) {
disableButton();
console.warn('Exception when trying to call xr.isSessionSupported',
exception);
button.textContent = 'VR NOT ALLOWED';
}
/**
* Function for styling an HTML element with specific CSS properties
*
* @param {HTMLElement} element - The HTML element to be styled
*/
function stylizeElement(element) {
element.style.position = 'absolute';
element.style.bottom = '20px';
element.style.padding = '12px 6px';
element.style.border = '1px solid #fff';
element.style.borderRadius = '4px';
element.style.background = 'rgba(0,0,0,0.1)';
element.style.color = '#fff';
element.style.font = 'normal 13px sans-serif';
element.style.textAlign = 'center';
element.style.opacity = '0.5';
element.style.outline = 'none';
element.style.zIndex = '999';
}
if ('xr' in navigator) {
button.id = 'VRButton';
button.style.display = 'none';
stylizeElement(button);
navigator.xr.isSessionSupported('immersive-vr').then(function(supported) {
supported ? showEnterVR() : showWebXRNotFound();
if (supported && VRButton.xrSessionIsGranted) {
button.click();
}
}).catch(showVRNotAllowed);
return button;
} else {
const message = document.createElement('a');
if (window.isSecureContext === false) {
message.href = document.location.href.replace(/^http:/, 'https:');
message.innerHTML = 'WEBXR NEEDS HTTPS';
} else {
message.href = 'https://immersiveweb.dev/';
message.innerHTML = 'WEBXR NOT AVAILABLE';
}
message.style.left = 'calc(50% - 90px)';
message.style.width = '180px';
message.style.textDecoration = 'none';
stylizeElement(message);
return message;
}
}
/**
* Registers a listener for the "sessiongranted" event to track the XR
* session being granted.
*
* @description This method checks if the WebXR API is available and
* registers a listener for the "sessiongranted" event to track when an
* XR session is granted. It sets the `VRButton.xrSessionIsGranted`
* property to `true` when the event is triggered.
*/
static registerSessionGrantedListener() {
if ('xr' in navigator) {
// WebXRViewer (based on Firefox) has a bug where addEventListener
// throws a silent exception and aborts execution entirely.
if (/WebXRViewer\//i.test(navigator.userAgent)) return;
navigator.xr.addEventListener('sessiongranted', () => {
VRButton.xrSessionIsGranted = true;
});
}
}
}
VRButton.xrSessionIsGranted = false;
VRButton.registerSessionGrantedListener();
export {VRButton};

View File

@@ -370,7 +370,6 @@ export let View = (function () {
}
this.computeNorder();
//this.redraw();
};
var pixelateCanvasContext = function (ctx, pixelateFlag) {
@@ -1059,41 +1058,6 @@ export let View = (function () {
View.FPS_INTERVAL = 1000 / 140;
View.prototype.redrawVR = function (t, frame, xrRefSpace) {
const session = frame.session;
session.requestAnimationFrame((t, frame) => {this.redrawVR(t, frame, xrRefSpace)});
let pose = frame.getViewerPose(xrRefSpace);
if (!pose) return;
// Elapsed time since last loop
const now = Date.now();
const elapsedTime = now - this.then;
// If enough time has elapsed, draw the next frame
//if (elapsedTime >= View.FPS_INTERVAL) {
// Get ready for next frame by setting then=now, but also adjust for your
// specified fpsInterval not being a multiple of RAF's interval (16.7ms)
// Drawing code
try {
this.moving = this.wasm.update(elapsedTime);
} catch (e) {
console.warn(e)
}
////// 2. Draw catalogues////////
const isViewRendering = this.wasm.isRendering();
if (isViewRendering || this.needRedraw) {
this.drawAllOverlays();
}
this.needRedraw = false;
this.options.vr.animation();
}
/**
* redraw the whole view
*/

View File

@@ -55,6 +55,8 @@ export class ALEvent {
static GRAPHIC_OVERLAY_LAYER_CHANGED = new ALEvent("AL:GraphicOverlayLayer.changed");
static SAMP_AVAILABILITY = new ALEvent("AL:samp.started");
constructor(name) {
this.name = name;
}

1319
src/js/libs/samp.js Normal file

File diff suppressed because it is too large Load Diff

180
src/js/vo/samp.js Normal file
View File

@@ -0,0 +1,180 @@
// Copyright 2013 - UDS/CNRS
// The Aladin Lite program is distributed under the terms
// of the GNU General Public License version 3.
//
// This file is part of Aladin Lite.
//
// Aladin Lite is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Aladin Lite is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available in COPYING file
// along with Aladin Lite.
//
/******************************************************************************
* Aladin Lite project
*
* File vo/samp.js
*
*
* Author: Matthieu Baumann [CDS, matthieu.baumann@astro.unistra.fr]
*
*****************************************************************************/
import { ALEvent } from "../events/ALEvent";
import { samp } from '../libs/samp';
export class SAMPConnector {
constructor(aladin) {
// Define listeners
let cc = new samp.ClientTracker();
let callHandler = cc.callHandler;
callHandler["script.aladin.send"] = function(senderId, message, isCall) {
var params = message["samp.params"];
aladin.setBaseImageLayer(params["url"])
};
callHandler["coord.pointAt.sky"] = function(senderId, message, isCall) {
var params = message["samp.params"];
aladin.gotoRaDec(+params["ra"], +params["dec"])
};
callHandler["coverage.load.moc.fits"] = function(senderId, message, isCall) {
var params = message["samp.params"];
let name = params["name"];
let moc = A.MOCFromURL(params["url"], {name: name, lineWidth: 3});
aladin.addMOC(moc);
};
callHandler["image.load.fits"] = function(senderId, message, isCall) {
let params = message["samp.params"];
let url = params["url"];
let name = params["name"];
const image = aladin.createImageFITS(url, name, options, (e) => window.alert(e));
aladin.setOverlayImageLayer(image, name);
};
callHandler["table.load.votable"] = function(senderId, message, isCall) {
let params = message["samp.params"];
let url = params["url"];
let name = params["name"];
let cat = A.catalogFromURL(
url,
{name: name, onClick: 'showTable'},
null,
(e) => window.alert(e)
);
aladin.addCatalog(cat)
};
let subs = cc.calculateSubscriptions();
let meta = {
"samp.name": "Aladin Lite",
"samp.description": "Aladin Lite web visualizer SAMP connector"
};
// Arrange for document to be adjusted for presence of hub every 2 sec.
this.connector = new samp.Connector("Aladin Lite", meta, cc, subs);
window.addEventListener('load', (e) => {
this.connector.onHubAvailability((isHubRunning) => {
// Communicate to Aladin Lite
ALEvent.SAMP_AVAILABILITY.dispatchedTo(aladin.aladinDiv, { isHubRunning: isHubRunning } );
}, 2000);
});
window.addEventListener('unload', (e) => {
this.connector.unregister();
});
// TODO put that in a button
//this.connector.register();
}
// Broadcasts a message given a hub connection.
_send(mtype, params) {
// Provides execution of a SAMP operation with register-on-demand.
this.connector.runWithConnection(
(connection) => {
let msg = new samp.Message(mtype, params);
connection.notifyAll([msg]);
},
(e) => {
window.alert(e)
}
)
}
/**
* Load a VOTable by url
* @param {String} url - URL of the VOTable document to load
* @param {String} [tableId] - Identifier which may be used to refer to the loaded table in subsequent messages
* @param {String} [name] - Name which may be used to label the loaded table in the application GUI
*/
loadVOTable(url, tableId, name) {
this._send("table.load.votable", {
url: url,
"table-id": tableId,
name: name
})
}
/**
* Load a fits image by url
* @param {String} url - URL of the FITS image to load
* @param {String} [imageId] - Identifier which may be used to refer to the loaded image in subsequent messages
* @param {String} [name] - Name which may be used to label the loaded image in the application GUI
*/
loadImageFITS(url, imageId, name) {
this._send("image.load.fits", {
"url": url,
"image-id": imageId,
"name": name
})
}
/**
* Load a Multi-Order-Coverage FITS file
* @param {String} url - URL of a FITS file containing the MOC to load
* @param {String} [coverageId] - Identifier which may be used to refer to the loaded coverage specification in subsequent messages
* @param {String} [name] - Name which may be used to label the loaded image in the application GUI
*/
loadMocFITS(url, coverageId, name) {
this._send("coverage.load.moc.fits", {
"url": url,
"coverage-id": coverageId,
"name": name
})
}
/**
* Load a HiPS by an url
* @param {String} url - base URL for the HiPS to load
*/
loadHiPS(url) {
const cmd = 'load ' + url;
this._send("script.aladin.send", { "script": cmd })
}
/**
* Send a ra, dec position to the hub
* @param {Float} ra - right ascension in degrees
* @param {Float} dec - declination in degrees
*/
centerAtRaDec(ra, dec) {
this._send("coord.pointAt.sky", { "ra": ra.toString(), "dec": dec.toString() })
}
}