mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-25 12:25:52 -08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e14b2694ca | ||
|
|
e0c2288306 | ||
|
|
328129896f | ||
|
|
733f81fc6b |
@@ -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)
|
||||
|
||||
@@ -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});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -1047,8 +1047,7 @@ impl HiPS {
|
||||
Some(self.num_idx as i32),
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
0,
|
||||
)
|
||||
.unbind();
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -259,8 +259,7 @@ impl Layers {
|
||||
None,
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
0,
|
||||
)
|
||||
.unbind();
|
||||
);
|
||||
}
|
||||
|
||||
// The first layer must be paint independently of its alpha channel
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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};
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
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
180
src/js/vo/samp.js
Normal 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() })
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user