mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-25 12:25:52 -08:00
Compare commits
17 Commits
select-imp
...
hips_cube
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60339e529a | ||
|
|
9bccdefcc5 | ||
|
|
16f978810f | ||
|
|
424c3cebba | ||
|
|
66326b59e4 | ||
|
|
7b80efa324 | ||
|
|
fd9a7b0de2 | ||
|
|
72d7e4e6bb | ||
|
|
186e634a86 | ||
|
|
5fd6bedeb9 | ||
|
|
6dd8ee2b85 | ||
|
|
a8c07137a4 | ||
|
|
7dc4a737ac | ||
|
|
a1b7b255bd | ||
|
|
1c3d6e90c9 | ||
|
|
ebb2172833 | ||
|
|
256e440ac5 |
@@ -1,14 +1,11 @@
|
||||
# Changelogs
|
||||
|
||||
## 3.5.1-beta
|
||||
## [Unreleased]
|
||||
|
||||
* [feat] Add support for name removing in `removeOverlay` method
|
||||
* [test] Add support of playwright. Instructions in the readme for running the test matching snapshots [PR #176]
|
||||
* [fix] Order of overlays in the stack now matches the addMOC/addCatalog/addOverlay calls ordering
|
||||
* [fixed] Order of overlays in the stack now matches the addMOC/addCatalog/addOverlay calls ordering
|
||||
* [doc] Expose the API of Coo class
|
||||
* [fix] Insert aladin css inside the aladin lite so that it should be compliant with the use of shadow DOMs [cds-astro/ipyaladin#113], [marimo-team/marimo#2106]
|
||||
* [feat] Add possibility of giving a local JS FileList to load a locally-stored HiPS without starting an HTTP server [cds-astro/aladin-lite#103]
|
||||
* [fix] removeOverlayByName
|
||||
|
||||
## 3.5.0-beta
|
||||
|
||||
|
||||
169
README.md
169
README.md
@@ -1,4 +1,4 @@
|
||||
# [Aladin Lite](https://aladin.u-strasbg.fr/AladinLite)
|
||||
# Aladin Lite v3
|
||||
|
||||
**An astronomical HiPS visualizer in the browser** <img src="aladin-logo.png" alt="Aladin Lite logo" width="220">
|
||||
|
||||
@@ -12,37 +12,20 @@ More details on [Aladin Lite documentation page](http://aladin.u-strasbg.fr/Alad
|
||||
A new [API technical documentation](https://cds-astro.github.io/aladin-lite/) is now available.
|
||||
|
||||
[](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml)
|
||||
[](https://cds-astro.github.io/aladin-lite)
|
||||
[](https://cds-astro.github.io/aladin-lite)
|
||||
|
||||
Aladin Lite is available [at this link](https://aladin.u-strasbg.fr/AladinLite).
|
||||
# How to test it ?
|
||||
|
||||
## Running & editable JS examples
|
||||
|
||||
<!-- Examples -->
|
||||
<table><tbody>
|
||||
<tr><td>Basic Aladin Lite setup</td><td>Load SIMBAD & NED catalog data</td><td>Load a FITS image</td></tr>
|
||||
<tr><td align="left"><a href="https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/AL-in-responsive-div/"><img height="200" src="https://github.com/cds-astro/aladin-lite/blob/develop/assets/vignettes/Basic%20Aladin%20Lite%20instanciation.png?raw=true"></img></a></td>
|
||||
<td align="center"><a href="https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/easy-access-simbad-ned/"><img height="200" src="https://github.com/cds-astro/aladin-lite/blob/develop/assets/vignettes/Load%20SIMBAD%20&%20NED%20catalogs%20data.png?raw=true"></img></a></td>
|
||||
<td align="right"><a href="https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/load-FITS-image-URL/"><img height="200" src="https://github.com/cds-astro/aladin-lite/blob/develop/assets/vignettes/Load%20a%20FITS%20image.png?raw=true"></img></a></td></tr><tr>
|
||||
<td>American Astronomical Society 225<br/>example</td><td>Display proper motion vectors</td><td>Visualization of Mars</td></tr><tr>
|
||||
<td align="left"><a href="https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/AAS225/"><img height="200" src="https://github.com/cds-astro/aladin-lite/blob/develop/assets/vignettes/American%20Astronomical%20Society%20225%20demonstration.png?raw=true"></img></a></td>
|
||||
<td align="center"><a href="https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/show-proper-motions/"><img height="200" src="https://github.com/cds-astro/aladin-lite/blob/develop/assets/vignettes/Display%20proper%20motions.png?raw=true"></img></a></td>
|
||||
<td align="right"><a href="https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/mars-visualisation/"><img height="200" src="https://github.com/cds-astro/aladin-lite/blob/develop/assets/vignettes/Visualization%20of%20Mars.png?raw=true"></img></a></td></tr></tbody></table>
|
||||
<!-- Examples -->
|
||||
Aladin Lite v3 is out! Please play with [Aladin Lite v3 at this link](https://aladin.u-strasbg.fr/AladinLite).
|
||||
|
||||
## Releases
|
||||
|
||||
A [release page](https://aladin.cds.unistra.fr/AladinLite/doc/release/) keeps track of all the current and previous builds.
|
||||
A ``release`` and ``beta`` versions, regularly updated are available. The ``beta`` version is usually more advanced than the ``release`` one but features more error prone and not production-ready code.
|
||||
For integrating Aladin Lite into your personal website, please refer to this [release page](https://aladin.cds.unistra.fr/AladinLite/doc/release/).
|
||||
Always prefer using the latest version. If you want the new features without minding about the bugs coming with it, then the beta is the good way to go.
|
||||
|
||||
> [!TIP]
|
||||
> If you are working on a project that uses Aladin Lite, prefer working with a fixed version. Every build is tagged with a version number and accessible with:
|
||||
>
|
||||
> ```https://aladin.cds.unistra.fr/AladinLite/api/v3/<version>/aladin.js```
|
||||
## API documentation
|
||||
|
||||
## Documentation
|
||||
|
||||
There is a new API documentation available [here](https://cds-astro.github.io/aladin-lite).
|
||||
There is a new in progress API documentation at [this link](https://cds-astro.github.io/aladin-lite).
|
||||
Editable examples showing the API can also be found [here](https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/).
|
||||
|
||||
## Embed it into your projects
|
||||
@@ -53,7 +36,7 @@ You can embed Aladin Lite it into your webpages in two ways
|
||||
|
||||
Please include [the javascript script of Aladin Lite v3](https://aladin.cds.unistra.fr/AladinLite/api/v3/latest/aladin.js) into your project. API differences from the v2 are minimal, here is a snippet of code you can use to embed it into your webpages:
|
||||
|
||||
```html
|
||||
```js
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -76,36 +59,60 @@ Please include [the javascript script of Aladin Lite v3](https://aladin.cds.unis
|
||||
</html>
|
||||
```
|
||||
|
||||
### NPM deployment
|
||||
### Using the aladin lite NPM package
|
||||
|
||||
A [NPM package](https://www.npmjs.com/package/aladin-lite) is deployed and maintained. It is used by [ipyaladin](https://github.com/cds-astro/ipyaladin), a jupyter widget allowing to run aladin lite in a notebook.
|
||||
First, install it with npm:
|
||||
|
||||
```npm i aladin-lite```
|
||||
|
||||
Aladin Lite can be imported with:
|
||||
Second, you can use it that way:
|
||||
|
||||
```js
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Mandatory when setting up Aladin Lite v3 for a smartphones/tablet usage -->
|
||||
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="aladin-lite-div" style="width: 500px; height: 400px"></div>
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import A from 'aladin-lite';
|
||||
|
||||
A.init.then(() => {
|
||||
let aladin = A.aladin('#aladin-lite-div', {fov: 360, projection: "AIT", cooFrame: 'equatorial', showCooGridControl: true, showSimbadPointerControl: true, showCooGrid: true});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## New features
|
||||
## Goals of v3
|
||||
|
||||
* [X] Rust/WebGL2 new rendering engine
|
||||
* [X] Remove jQuery dep
|
||||
* [ ] UI dev, better support for smartphones
|
||||
* [X] FITS images support
|
||||
* [X] WCS parsing, displaying an (JPEG/PNG) image in aladin lite view
|
||||
* [X] Display customized shapes (e.g. proper motions) from astronomical catalog data
|
||||
* [X] AVM tags parsing support
|
||||
* [X] Easy sharing of current « view »
|
||||
* [ ] All VOTable serializations
|
||||
* [ ] FITS tables
|
||||
* [X] Creating HiPS instance from an URL
|
||||
* [X] Local HiPS loading
|
||||
* [X] Multiple mirrors handling for HiPS tile retrival
|
||||
* [ ] HiPS cube
|
||||
- Rust/WebGL new core integration
|
||||
|
||||
- Remove jQuery dep
|
||||
|
||||
- UI dev, better support for smartphones
|
||||
|
||||
- FITS images support
|
||||
|
||||
- easy sharing of current « view »
|
||||
|
||||
- support of all VOTable serializations (using votable.js?)
|
||||
|
||||
- support of FITS tables?
|
||||
|
||||
- creating HiPS instance from an URL
|
||||
|
||||
- multiple mirrors handling for HiPS tile retrival
|
||||
|
||||
## Source code
|
||||
|
||||
Source code is available in the ``src`` directory.
|
||||
|
||||
## Licence
|
||||
|
||||
@@ -113,7 +120,7 @@ Aladin Lite is currently licensed under GPL v3.0
|
||||
|
||||
If you think this license might prevent you from using Aladin Lite in your pages/application/portal, please open an issue or [contact us](mailto:cds-question@unistra.fr)
|
||||
|
||||
## Contribution guidelines
|
||||
## Contributing
|
||||
|
||||
There are several ways to contribute to Aladin Lite:
|
||||
|
||||
@@ -124,12 +131,12 @@ There are several ways to contribute to Aladin Lite:
|
||||
- **develop new features/provide code fixing bugs**. As open development is a new thing for us, we will in a first time only take into consideration code contribution (_i.e._ Pull Requests) from our close partners.
|
||||
In any case, please get in touch before starting a major update or rewrite.
|
||||
|
||||
### Building steps
|
||||
### Building the application steps
|
||||
|
||||
First you need to install the dependencies from the package.json
|
||||
Please run:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
@@ -140,73 +147,63 @@ You will also need [wasm-pack](https://rustwasm.github.io/wasm-pack/), a tool he
|
||||
|
||||
Once it's installed you will need to switch to the nightly rust version:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
rustup default nightly
|
||||
```
|
||||
|
||||
Then you can build the project:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> **If you are experimenting Rust compiling issues:**
|
||||
> - Make sure you have your **wasm-pack** version updated. To do so:
|
||||
> ```sh
|
||||
> cargo install wasm-pack --version ~0.12
|
||||
> ```
|
||||
> - Make sure you are using the rust **nightly** toolchain
|
||||
> ```sh
|
||||
> rustup default nightly
|
||||
> ```
|
||||
> - Remove your `src/core/Cargo.lock` file and `src/core/target` directory -- this ensures that you'd escape any bad compilation state:
|
||||
> ```sh
|
||||
> git clean -di
|
||||
> ```
|
||||
> - then recompile with `npm run build`.
|
||||
:warning: **If you are experimenting rust error compilations**:
|
||||
|
||||
It will generate the aladin lite compiled code into a `dist/` directory located at the root of the repository. This directory contains two javascript files. `aladin.umd.cjs` follows the UMD module export convention and it is the one you need to use for your project.
|
||||
- Make sure you have your **wasm-pack** version updated. To do so:
|
||||
|
||||
### Testing guidelines
|
||||
```bash
|
||||
cargo install wasm-pack --version ~0.12
|
||||
```
|
||||
|
||||
#### Run the examples
|
||||
- Make sure you are using the rust **nightly** toolchain
|
||||
- Remove your `src/core/Cargo.lock` file and `src/core/target` directory -- this ensures that you'd escape any bad compilation state:
|
||||
|
||||
A bunch of examples are located into the `examples` directory.
|
||||
To run them, start a localhost server:
|
||||
```bash
|
||||
git clean -di
|
||||
```
|
||||
|
||||
- then recompile with `npm run build`.
|
||||
|
||||
```sh
|
||||
It will generate the aladin lite compiled code into a `dist/` directory located at the root of the repository. This directory contains two javascript files. `aladin.umd.cjs` follows the UMD module export convention and it is the one you can use for your project.
|
||||
|
||||
To run the examples, you can start a localhost server with the following command:
|
||||
|
||||
```bash
|
||||
npm run serve
|
||||
```
|
||||
|
||||
#### Rust tests
|
||||
For just compiling the rust core, from the root location do:
|
||||
|
||||
These can be executed separately from the JS part:
|
||||
|
||||
* Compile the Rust code:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
cd src/core
|
||||
cargo check --features webgl2
|
||||
```
|
||||
|
||||
* Run the tests:
|
||||
and run the tests:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
cd src/core
|
||||
cargo test --features webgl2
|
||||
```
|
||||
|
||||
#### Snapshot comparisons
|
||||
For running the playwright test locally please first install playwright like so:
|
||||
|
||||
We use [playwright](https://playwright.dev/) for snapshot comparison testing. Only ground truth snapshots have been generated for MacOS/Darwin architecture.
|
||||
First install playwright:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npx playwright install
|
||||
```
|
||||
|
||||
Run the tests, advises are given for opening the UI mode or for generating your own ground truth snapshots.
|
||||
After that you will be able to run them. These are generated snapshots that will be compared to ground truth snapshots:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npm run test:playwright
|
||||
```
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 962 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 MiB |
@@ -8,8 +8,8 @@
|
||||
"dateModified": "2023-01-31",
|
||||
"issueTracker": "https://github.com/cds-astro/aladin-lite/issues",
|
||||
"name": "Aladin Lite",
|
||||
"version": "3.5.1-beta",
|
||||
"softwareVersion": "3.5.1-beta",
|
||||
"version": "3.5.0-beta",
|
||||
"softwareVersion": "3.5.0-beta",
|
||||
"description": "An astronomical HiPS visualizer in the browser.",
|
||||
"identifier": "10.5281/zenodo.7638833",
|
||||
"applicationCategory": "Astronomy, Visualization",
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
import A from '../src/js/A.js';
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {showSettingsControl: true, survey: "P/PanSTARRS/DR1/color-z-zg-g", showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: 1000, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGridControl: false});
|
||||
aladin.showHealpixGrid(true);
|
||||
aladin = A.aladin('#aladin-lite-div', {survey: "P/PanSTARRS/DR1/color-z-zg-g", showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: 1000, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGrid: true, showCooGridControl: false});
|
||||
|
||||
const chft = aladin.createImageSurvey('CFHT', "CFHT deep view of NGC7331 and Stephan's quintet u+g+r", "https://cds.unistra.fr/~derriere/PR_HiPS/2022_Duc/", null, null, {imgFormat: 'png'});
|
||||
const nircamJWST = aladin.createImageSurvey('Nircam', "Stephans Quintet NIRCam+MIRI", "http://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam+MIRI/", null, null, {imgFormat: 'png', colormap: "viridis"});
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="shadow-host"></div>
|
||||
|
||||
<script type="text/javascript" src="./../dist/aladin.umd.cjs" charset="utf-8"></script>
|
||||
<script type="text/javascript">
|
||||
const shadowEl = document.querySelector(".shadow-host");
|
||||
const shadow = shadowEl.attachShadow({mode: 'open'});
|
||||
|
||||
let aladinLiteEl = document.createElement('div');
|
||||
aladinLiteEl.id = "aladin-lite-div"
|
||||
aladinLiteEl.style = "width: 768px; height: 512px";
|
||||
shadow.appendChild(aladinLiteEl)
|
||||
|
||||
A.init.then(() => {
|
||||
let aladin = A.aladin(
|
||||
aladinLiteEl,
|
||||
{
|
||||
survey: 'P/allWISE/color', // set initial image survey
|
||||
projection: 'AIT', // set a projection
|
||||
fov: 1.5, // initial field of view in degrees
|
||||
target: 'orion', // initial target
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -13,7 +13,6 @@
|
||||
aladin = A.aladin(
|
||||
'#aladin-lite-div',
|
||||
{
|
||||
showSimbadPointerControl: true,
|
||||
survey: 'P/allWISE/color', // set initial image survey
|
||||
projection: 'AIT', // set a projection
|
||||
fov: 1.5, // initial field of view in degrees
|
||||
@@ -31,14 +30,7 @@
|
||||
}
|
||||
);
|
||||
|
||||
/*let id;
|
||||
aladin.on("zoomChanged", () => {
|
||||
if (id)
|
||||
clearTimeout(id);
|
||||
id = setTimeout(() => {
|
||||
console.log("wheel stopped, new cone search here")
|
||||
}, 500);
|
||||
})*/
|
||||
//aladin.removeHiPSFromFavorites('CDS/P/allWISE/color')
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import A from '../src/js/A.js';
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {inertia: false, target: '00 00 00 +07 00 00', fov: 130, survey: 'P/Mellinger/color', showContextMenu: true, fullScreen: true});
|
||||
aladin = A.aladin('#aladin-lite-div', {target: '00 00 00 +07 00 00', fov: 130, survey: 'P/Mellinger/color', showContextMenu: true, fullScreen: true});
|
||||
var moc11 = A.MOCFromURL('http://skies.esac.esa.int/HST/NICMOS/Moc.fits', {color: '#84f', lineWidth: 3}, (moc) => {
|
||||
// moc is ready
|
||||
console.log(moc.contains(205.9019247, +2.4492764));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {projection: 'MOL', fullScreen: true, fov: 360, survey: ['P/DM/vizMine', 'P/HST/GOODS/color', 'P/MATLAS/g'], target: '0 0', showProjectionControl: false, showSettingsControl: false, showLayersControl: false, showCooGrid: false, showFrame: false, showCooLocation: false});
|
||||
aladin = A.aladin('#aladin-lite-div', {projection: 'MOL', fullScreen: true, fov: 360, survey: ['P/DM/vizMine', 'P/HST/GOODS/color', 'P/MATLAS/g'], target: '0 0', showProjectionControl: true, showSettingsControl: true, showCooGrid: true});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -11,17 +11,10 @@
|
||||
|
||||
A.init.then(() => {
|
||||
let vertices = A.Utils.HEALPix.vertices(Math.pow(2, 3), BigInt(276))
|
||||
let lonlat = A.Utils.HEALPix.pix2ang(8, 0n)
|
||||
let ipix = A.Utils.HEALPix.ang2pix(8, 0.1, 0.4)
|
||||
console.log("vertices", vertices, lonlat, ipix)
|
||||
|
||||
A.Utils.Sesame.resolveAstronomicalName("M101", (o) => {
|
||||
console.log("object found", o)
|
||||
},
|
||||
(err) => {
|
||||
console.error("errr", err)
|
||||
}
|
||||
)
|
||||
//let lonlat = A.Utils.HEALPix.pix2ang(8, 0n)
|
||||
//let ipix = A.Utils.HEALPix.ang2pix(8, 0.1, 0.4)
|
||||
//console.log("vertices", vertices, lonlat, ipix)
|
||||
console.log(vertices)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
"module": "./dist/aladin.js",
|
||||
"main": "./dist/aladin.js",
|
||||
"files": [
|
||||
"dist/aladin.js"
|
||||
"dist/aladin.js",
|
||||
"dist/aladin.umd.cjs",
|
||||
"dist/index.html"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
@@ -34,8 +36,8 @@
|
||||
"wasm:dbg": "wasm-pack build --dev ./src/core --target web --out-name core -- --features=webgl2,dbg -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort ",
|
||||
"predeploy": "npm run build && rm -rf aladin-lite*.tgz && npm pack",
|
||||
"deploy": "python3 deploy/deploy.py",
|
||||
"build": "npm run wasm && vite build",
|
||||
"build:dbg": "npm run wasm:dbg && vite build",
|
||||
"build": "npm run wasm && vite build && cp examples/index.html dist/index.html",
|
||||
"build:dbg": "npm run wasm:dbg && vite build && cp examples/index.html dist/index.html",
|
||||
"dev": "npm run build && vite",
|
||||
"dev:dbg": "npm run build:dbg && vite",
|
||||
"serve": "npm run dev",
|
||||
@@ -51,6 +53,7 @@
|
||||
"@playwright/test": "^1.47.0",
|
||||
"jsdoc": "^4.0.2",
|
||||
"vite": "^4.3.8",
|
||||
"vite-plugin-css-injected-by-js": "^3.1.1",
|
||||
"vite-plugin-glsl": "^1.1.2",
|
||||
"vite-plugin-top-level-await": "^1.4.1",
|
||||
"vite-plugin-wasm": "^3.2.2",
|
||||
|
||||
@@ -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.5.1-beta"
|
||||
version = "3.5.0-beta"
|
||||
authors = [ "baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr",]
|
||||
edition = "2018"
|
||||
|
||||
@@ -70,7 +70,7 @@ path = "./al-api"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "*"
|
||||
features = [ "console", "CssStyleDeclaration", "Document", "Element", "HtmlCollection", "HtmlElement", "HtmlImageElement", "HtmlCanvasElement", "Blob", "ImageBitmap", "ImageData", "CanvasRenderingContext2d", "WebGlBuffer", "WebGlContextAttributes", "WebGlFramebuffer", "WebGlProgram", "WebGlShader", "WebGlUniformLocation", "WebGlTexture", "WebGlActiveInfo", "Headers", "Window", "Request", "RequestInit", "RequestMode", "Response", "XmlHttpRequest", "XmlHttpRequestResponseType", "PerformanceTiming", "Performance", "Url", "ReadableStream", "File", "FileList",]
|
||||
features = [ "console", "CssStyleDeclaration", "Document", "Element", "HtmlCollection", "HtmlElement", "HtmlImageElement", "HtmlCanvasElement", "Blob", "ImageBitmap", "ImageData", "CanvasRenderingContext2d", "WebGlBuffer", "WebGlContextAttributes", "WebGlFramebuffer", "WebGlProgram", "WebGlShader", "WebGlUniformLocation", "WebGlTexture", "WebGlActiveInfo", "Headers", "Window", "Request", "RequestInit", "RequestMode", "Response", "XmlHttpRequest", "XmlHttpRequestResponseType", "PerformanceTiming", "Performance", "Url", "ReadableStream",]
|
||||
|
||||
[dev-dependencies.image-decoder]
|
||||
package = "image"
|
||||
|
||||
@@ -61,8 +61,6 @@ features = [
|
||||
'PerformanceTiming',
|
||||
'Performance',
|
||||
'Url',
|
||||
'File',
|
||||
'FileList'
|
||||
]
|
||||
|
||||
[profile.dev]
|
||||
|
||||
@@ -73,8 +73,6 @@ features = [
|
||||
'PerformanceTiming',
|
||||
'Performance',
|
||||
'Url',
|
||||
'File',
|
||||
'FileList'
|
||||
]
|
||||
|
||||
[profile.dev]
|
||||
|
||||
@@ -232,7 +232,7 @@ where
|
||||
use crate::Abort;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
/*impl<I> Image for Arc<Mutex<Option<I>>>
|
||||
impl<I> Image for Arc<Mutex<Option<I>>>
|
||||
where
|
||||
I: Image,
|
||||
{
|
||||
@@ -249,7 +249,7 @@ where
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
#[cfg(feature = "webgl2")]
|
||||
use crate::image::format::{R16I, R32I, R64F, R8UI};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::renderable::ImageLayer;
|
||||
use crate::tile_fetcher::HiPSLocalFiles;
|
||||
use crate::{
|
||||
//async_task::{BuildCatalogIndex, ParseTableTask, TaskExecutor, TaskResult, TaskType},
|
||||
camera::CameraViewPort,
|
||||
@@ -303,6 +302,16 @@ impl App {
|
||||
ancestors.insert(ancestor_tile_cell);
|
||||
}
|
||||
}
|
||||
//let ancestor_next_tile_cell = next_tile_cell.ancestor(3);
|
||||
//if !survey.contains_tile(&ancestor_tile_cell) {
|
||||
//self.tile_fetcher.append(
|
||||
// query::Tile::new(&ancestor_tile_cell, hips_url.clone(), format),
|
||||
// &mut self.downloader,
|
||||
//);
|
||||
//}
|
||||
//if ancestor_tile_cell != ancestor_next_tile_cell {
|
||||
|
||||
//}
|
||||
}
|
||||
}
|
||||
// Request for ancestor
|
||||
@@ -612,7 +621,7 @@ impl App {
|
||||
//let _depth = tile.cell().depth();
|
||||
// do not perform tex_sub costly GPU calls while the camera is zooming
|
||||
if tile.cell().is_root() || included_or_near_coverage {
|
||||
//let is_missing = tile.missing();
|
||||
let is_missing = tile.missing();
|
||||
/*self.tile_fetcher.notify_tile(
|
||||
&tile,
|
||||
true,
|
||||
@@ -626,77 +635,75 @@ impl App {
|
||||
..
|
||||
} = tile;
|
||||
|
||||
/*let image = if is_missing {
|
||||
let image = if is_missing {
|
||||
// Otherwise we push nothing, it is probably the case where:
|
||||
// - an request error occured on a valid tile
|
||||
// - the tile is not present, e.g. chandra HiPS have not the 0, 1 and 2 order tiles
|
||||
None
|
||||
} else {
|
||||
Some(image)
|
||||
};*/
|
||||
};
|
||||
use al_core::image::ImageType;
|
||||
use fitsrs::fits::Fits;
|
||||
use std::io::Cursor;
|
||||
//if let Some(image) = image.as_ref() {
|
||||
match &*image.lock().unwrap_abort() {
|
||||
Some(ImageType::FitsImage {
|
||||
raw_bytes: raw_bytes_buf,
|
||||
}) => {
|
||||
// check if the metadata has not been set
|
||||
if !cfg.fits_metadata {
|
||||
let num_bytes = raw_bytes_buf.length() as usize;
|
||||
let mut raw_bytes = vec![0; num_bytes];
|
||||
raw_bytes_buf.copy_to(&mut raw_bytes[..]);
|
||||
if let Some(image) = image.as_ref() {
|
||||
match &*image.lock().unwrap_abort() {
|
||||
Some(ImageType::FitsImage {
|
||||
raw_bytes: raw_bytes_buf,
|
||||
}) => {
|
||||
// check if the metadata has not been set
|
||||
if !cfg.fits_metadata {
|
||||
let num_bytes = raw_bytes_buf.length() as usize;
|
||||
let mut raw_bytes = vec![0; num_bytes];
|
||||
raw_bytes_buf.copy_to(&mut raw_bytes[..]);
|
||||
|
||||
let mut bytes_reader =
|
||||
Cursor::new(raw_bytes.as_slice());
|
||||
let Fits { hdu } =
|
||||
Fits::from_reader(&mut bytes_reader).map_err(
|
||||
|_| JsValue::from_str("Parsing fits error"),
|
||||
)?;
|
||||
let mut bytes_reader =
|
||||
Cursor::new(raw_bytes.as_slice());
|
||||
let Fits { hdu } =
|
||||
Fits::from_reader(&mut bytes_reader)
|
||||
.map_err(|_| {
|
||||
JsValue::from_str(
|
||||
"Parsing fits error",
|
||||
)
|
||||
})?;
|
||||
|
||||
let header = hdu.get_header();
|
||||
let bscale = if let Some(
|
||||
fitsrs::card::Value::Float(bscale),
|
||||
) = header.get(b"BSCALE ")
|
||||
{
|
||||
*bscale as f32
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
let bzero = if let Some(
|
||||
fitsrs::card::Value::Float(bzero),
|
||||
) = header.get(b"BZERO ")
|
||||
{
|
||||
*bzero as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let blank = if let Some(
|
||||
fitsrs::card::Value::Float(blank),
|
||||
) = header.get(b"BLANK ")
|
||||
{
|
||||
*blank as f32
|
||||
} else {
|
||||
std::f32::NAN
|
||||
};
|
||||
let header = hdu.get_header();
|
||||
let bscale = if let Some(
|
||||
fitsrs::card::Value::Float(bscale),
|
||||
) = header.get(b"BSCALE ")
|
||||
{
|
||||
*bscale as f32
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
let bzero = if let Some(
|
||||
fitsrs::card::Value::Float(bzero),
|
||||
) = header.get(b"BZERO ")
|
||||
{
|
||||
*bzero as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let blank = if let Some(
|
||||
fitsrs::card::Value::Float(blank),
|
||||
) = header.get(b"BLANK ")
|
||||
{
|
||||
*blank as f32
|
||||
} else {
|
||||
std::f32::NAN
|
||||
};
|
||||
|
||||
cfg.set_fits_metadata(bscale, bzero, blank);
|
||||
cfg.set_fits_metadata(bscale, bzero, blank);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
//}
|
||||
}
|
||||
|
||||
match &*image.lock().unwrap_abort() {
|
||||
Some(img) => {
|
||||
survey.add_tile(&cell, img, time_req)?;
|
||||
self.request_redraw = true;
|
||||
survey.add_tile(&cell, image, time_req)?;
|
||||
self.request_redraw = true;
|
||||
|
||||
self.time_start_blending = Time::now();
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
self.time_start_blending = Time::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -798,12 +805,8 @@ impl App {
|
||||
// Check for async retrieval
|
||||
if let Ok(img) = self.img_recv.try_recv() {
|
||||
let params = img.get_params();
|
||||
self.layers.add_image(
|
||||
img,
|
||||
&mut self.camera,
|
||||
&self.projection,
|
||||
&mut self.tile_fetcher,
|
||||
)?;
|
||||
self.layers
|
||||
.add_image(img, &mut self.camera, &self.projection)?;
|
||||
self.request_redraw = true;
|
||||
|
||||
// Send the ack to the js promise so that she finished
|
||||
@@ -955,12 +958,8 @@ impl App {
|
||||
}
|
||||
|
||||
pub(crate) fn remove_layer(&mut self, layer: &str) -> Result<(), JsValue> {
|
||||
self.layers.remove_layer(
|
||||
layer,
|
||||
&mut self.camera,
|
||||
&self.projection,
|
||||
&mut self.tile_fetcher,
|
||||
)?;
|
||||
self.layers
|
||||
.remove_layer(layer, &mut self.camera, &self.projection)?;
|
||||
|
||||
self.request_redraw = true;
|
||||
|
||||
@@ -983,31 +982,17 @@ impl App {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn add_image_hips(
|
||||
&mut self,
|
||||
hips_cfg: HiPSCfg,
|
||||
local_files: Option<HiPSLocalFiles>,
|
||||
) -> Result<(), JsValue> {
|
||||
let cdid = hips_cfg.properties.get_creator_did().to_string();
|
||||
|
||||
let hips = self.layers.add_image_hips(
|
||||
&self.gl,
|
||||
hips_cfg,
|
||||
&mut self.camera,
|
||||
&self.projection,
|
||||
&mut self.tile_fetcher,
|
||||
)?;
|
||||
|
||||
if let Some(local_files) = local_files {
|
||||
self.tile_fetcher.insert_hips_local_files(cdid, local_files);
|
||||
}
|
||||
|
||||
pub(crate) fn add_image_hips(&mut self, hips_cfg: HiPSCfg) -> Result<(), JsValue> {
|
||||
let hips =
|
||||
self.layers
|
||||
.add_image_hips(&self.gl, hips_cfg, &mut self.camera, &self.projection)?;
|
||||
self.tile_fetcher
|
||||
.launch_starting_hips_requests(hips, self.downloader.clone());
|
||||
|
||||
// Once its added, request the tiles in the view (unless the viewer is at depth 0)
|
||||
self.request_for_new_tiles = true;
|
||||
self.request_redraw = true;
|
||||
//self.grid.update(&self.camera, &self.projection);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -87,7 +87,6 @@ use math::projection::*;
|
||||
|
||||
use moclib::moc::RangeMOCIntoIterator;
|
||||
//use votable::votable::VOTableWrapper;
|
||||
use crate::tile_fetcher::HiPSLocalFiles;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::HtmlElement;
|
||||
|
||||
@@ -161,7 +160,11 @@ impl WebClient {
|
||||
/// * `shaders` - The list of shader objects containing the GLSL code source
|
||||
/// * `resources` - Image resource files
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(aladin_div: &HtmlElement, resources: JsValue) -> Result<WebClient, JsValue> {
|
||||
pub fn new(
|
||||
aladin_div: &HtmlElement,
|
||||
//_shaders: JsValue,
|
||||
resources: JsValue,
|
||||
) -> Result<WebClient, JsValue> {
|
||||
#[cfg(feature = "dbg")]
|
||||
panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||
|
||||
@@ -368,14 +371,10 @@ impl WebClient {
|
||||
/// of WebGL2 texture units on some architectures, the total number of surveys rendered is
|
||||
/// limited to 4.
|
||||
#[wasm_bindgen(js_name = addHiPS)]
|
||||
pub fn add_image_hips(
|
||||
&mut self,
|
||||
hips: JsValue,
|
||||
files: Option<HiPSLocalFiles>,
|
||||
) -> Result<(), JsValue> {
|
||||
pub fn add_image_hips(&mut self, hips: JsValue) -> Result<(), JsValue> {
|
||||
// Deserialize the survey objects that compose the survey
|
||||
let hips = serde_wasm_bindgen::from_value(hips)?;
|
||||
self.app.add_image_hips(hips, files)?;
|
||||
self.app.add_image_hips(hips)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1033,7 +1032,7 @@ impl WebClient {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = addFITSMOC)]
|
||||
#[wasm_bindgen(js_name = addFITSMoc)]
|
||||
pub fn add_fits_moc(&mut self, params: &al_api::moc::MOC, data: &[u8]) -> Result<(), JsValue> {
|
||||
//let bytes = js_sys::Uint8Array::new(array_buffer).to_vec();
|
||||
let moc = match fits::from_fits_ivoa_custom(Cursor::new(&data[..]), false)
|
||||
|
||||
@@ -662,7 +662,7 @@ impl HiPS {
|
||||
))
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@@ -679,8 +679,8 @@ impl HiPS {
|
||||
let uv_1 = TileUVW::new(cell, ending_texture, cfg);
|
||||
let start_time = ending_texture.start_time().as_millis();
|
||||
|
||||
let miss_0 = (false) as i32 as f32;
|
||||
let miss_1 = (false) as i32 as f32;
|
||||
let miss_0 = (starting_texture.is_missing()) as i32 as f32;
|
||||
let miss_1 = (ending_texture.is_missing()) as i32 as f32;
|
||||
|
||||
let num_subdivision = num_subdivision(cell, camera, projection);
|
||||
|
||||
@@ -817,7 +817,7 @@ impl HiPS {
|
||||
pub fn add_tile<I: Image + Debug>(
|
||||
&mut self,
|
||||
cell: &HEALPixCell,
|
||||
image: I,
|
||||
image: Option<I>,
|
||||
time_request: Time,
|
||||
) -> Result<(), JsValue> {
|
||||
self.textures.push(&cell, image, time_request)
|
||||
|
||||
@@ -10,7 +10,6 @@ pub mod text;
|
||||
pub mod utils;
|
||||
|
||||
use crate::renderable::image::Image;
|
||||
use crate::tile_fetcher::TileFetcherQueue;
|
||||
|
||||
use al_core::image::format::ChannelType;
|
||||
|
||||
@@ -317,7 +316,6 @@ impl Layers {
|
||||
layer: &str,
|
||||
camera: &mut CameraViewPort,
|
||||
proj: &ProjectionType,
|
||||
tile_fetcher: &mut TileFetcherQueue,
|
||||
) -> Result<usize, JsValue> {
|
||||
let err_layer_not_found = JsValue::from_str(&format!(
|
||||
"Layer {:?} not found, so cannot be removed.",
|
||||
@@ -353,9 +351,6 @@ impl Layers {
|
||||
// remove the frame
|
||||
camera.unregister_view_frame(hips_frame, proj);
|
||||
|
||||
// remove the local files access from the tile fetcher
|
||||
tile_fetcher.delete_hips_local_files(s.get_config().get_creator_did());
|
||||
|
||||
Ok(id_layer)
|
||||
} else if let Some(_) = self.images.remove(&id) {
|
||||
// A FITS image has been found and removed
|
||||
@@ -423,7 +418,6 @@ impl Layers {
|
||||
hips: HiPSCfg,
|
||||
camera: &mut CameraViewPort,
|
||||
proj: &ProjectionType,
|
||||
tile_fetcher: &mut TileFetcherQueue,
|
||||
) -> Result<&HiPS, JsValue> {
|
||||
let HiPSCfg {
|
||||
layer,
|
||||
@@ -437,7 +431,7 @@ impl Layers {
|
||||
let layer_already_found = self.layers.iter().any(|l| l == &layer);
|
||||
|
||||
let idx = if layer_already_found {
|
||||
let idx = self.remove_layer(&layer, camera, proj, tile_fetcher)?;
|
||||
let idx = self.remove_layer(&layer, camera, proj)?;
|
||||
idx
|
||||
} else {
|
||||
self.layers.len()
|
||||
@@ -498,7 +492,6 @@ impl Layers {
|
||||
image: ImageLayer,
|
||||
camera: &mut CameraViewPort,
|
||||
proj: &ProjectionType,
|
||||
tile_fetcher: &mut TileFetcherQueue,
|
||||
) -> Result<&[Image], JsValue> {
|
||||
let ImageLayer {
|
||||
layer,
|
||||
@@ -511,7 +504,7 @@ impl Layers {
|
||||
let layer_already_found = self.layers.iter().any(|s| s == &layer);
|
||||
|
||||
let idx = if layer_already_found {
|
||||
let idx = self.remove_layer(&layer, camera, proj, tile_fetcher)?;
|
||||
let idx = self.remove_layer(&layer, camera, proj)?;
|
||||
idx
|
||||
} else {
|
||||
self.layers.len()
|
||||
|
||||
@@ -27,7 +27,6 @@ impl<const N: usize> BitVector<N> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::BitVector;
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ impl ImageSurveyTextures {
|
||||
let mutex_locked = image.lock().unwrap_abort();
|
||||
let images = mutex_locked.as_ref().unwrap_abort();
|
||||
for (idx, image) in images.iter().enumerate() {
|
||||
self.push(&HEALPixCell(depth_tile, idx as u64), image, time_req)?;
|
||||
self.push(&HEALPixCell(depth_tile, idx as u64), Some(image), time_req)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ impl ImageSurveyTextures {
|
||||
pub fn push<I: Image + std::fmt::Debug>(
|
||||
&mut self,
|
||||
cell: &HEALPixCell,
|
||||
image: I,
|
||||
image: Option<I>,
|
||||
time_request: Time,
|
||||
) -> Result<(), JsValue> {
|
||||
if !self.contains_tile(cell) {
|
||||
@@ -381,7 +381,7 @@ impl ImageSurveyTextures {
|
||||
&mut self.base_textures[idx as usize]
|
||||
};
|
||||
|
||||
//let missing = image.is_none();
|
||||
let missing = image.is_none();
|
||||
send_to_gpu(
|
||||
cell,
|
||||
texture,
|
||||
@@ -393,7 +393,7 @@ impl ImageSurveyTextures {
|
||||
texture.append(
|
||||
cell, // The tile cell
|
||||
&self.config,
|
||||
//missing,
|
||||
missing,
|
||||
);
|
||||
|
||||
self.available_tiles_during_frame = true;
|
||||
@@ -629,7 +629,7 @@ impl ImageSurveyTextures {
|
||||
fn send_to_gpu<I: Image>(
|
||||
cell: &HEALPixCell,
|
||||
texture: &Texture,
|
||||
image: I,
|
||||
image: Option<I>,
|
||||
texture_array: &Texture2DArray,
|
||||
cfg: &mut HiPSConfig,
|
||||
) -> Result<(), JsValue> {
|
||||
@@ -663,9 +663,12 @@ fn send_to_gpu<I: Image>(
|
||||
idx_slice,
|
||||
);
|
||||
|
||||
image.tex_sub_image_3d(&texture_array, &offset)?;
|
||||
|
||||
Ok(())
|
||||
if let Some(image) = image {
|
||||
image.tex_sub_image_3d(&texture_array, &offset)
|
||||
} else {
|
||||
cfg.get_default_image()
|
||||
.tex_sub_image_3d(&texture_array, &offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl SendUniforms for ImageSurveyTextures {
|
||||
|
||||
@@ -31,7 +31,7 @@ pub struct Texture {
|
||||
num_tiles_written: usize,
|
||||
// Flag telling whether the texture is available
|
||||
// for drawing
|
||||
//missing: bool,
|
||||
missing: bool,
|
||||
}
|
||||
|
||||
use super::config::HiPSConfig;
|
||||
@@ -44,7 +44,7 @@ impl Texture {
|
||||
let full = false;
|
||||
let texture_cell = *texture_cell;
|
||||
let uniq = texture_cell.uniq();
|
||||
//let missing = true;
|
||||
let missing = true;
|
||||
let num_tiles_written = 0;
|
||||
Texture {
|
||||
texture_cell,
|
||||
@@ -55,19 +55,19 @@ impl Texture {
|
||||
start_time,
|
||||
full,
|
||||
num_tiles_written,
|
||||
//missing,
|
||||
missing,
|
||||
}
|
||||
}
|
||||
|
||||
// Panic if cell is not contained in the texture
|
||||
// Do nothing if the texture is full
|
||||
// Return true if the tile is newly added
|
||||
pub fn append(&mut self, cell: &HEALPixCell, cfg: &HiPSConfig /*, missing: bool */) {
|
||||
pub fn append(&mut self, cell: &HEALPixCell, cfg: &HiPSConfig, missing: bool) {
|
||||
let texture_cell = cell.get_texture_cell(cfg.delta_depth());
|
||||
debug_assert!(texture_cell == self.texture_cell);
|
||||
debug_assert!(!self.full);
|
||||
|
||||
//self.missing &= missing;
|
||||
self.missing &= missing;
|
||||
//self.start_time = Some(Time::now());
|
||||
//self.full = true;
|
||||
let num_tiles_per_texture = cfg.num_tiles_per_texture();
|
||||
@@ -127,9 +127,9 @@ impl Texture {
|
||||
self.idx
|
||||
}
|
||||
|
||||
/*pub fn is_missing(&self) -> bool {
|
||||
pub fn is_missing(&self) -> bool {
|
||||
self.missing
|
||||
}*/
|
||||
}
|
||||
|
||||
// Setter
|
||||
pub fn replace(&mut self, texture_cell: &HEALPixCell, time_request: Time) {
|
||||
@@ -143,7 +143,7 @@ impl Texture {
|
||||
self.start_time = None;
|
||||
self.time_request = time_request;
|
||||
self.tiles.clear();
|
||||
//self.missing = true;
|
||||
self.missing = true;
|
||||
self.num_tiles_written = 0;
|
||||
}
|
||||
|
||||
@@ -187,7 +187,9 @@ impl<'a> TextureUniforms<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
use al_core::shader::{SendUniforms, ShaderBound};
|
||||
use al_core::{
|
||||
shader::{SendUniforms, ShaderBound},
|
||||
};
|
||||
impl<'a> SendUniforms for TextureUniforms<'a> {
|
||||
fn attach_uniforms<'b>(&self, shader: &'b ShaderBound<'b>) -> &'b ShaderBound<'b> {
|
||||
shader
|
||||
@@ -198,8 +200,7 @@ impl<'a> SendUniforms for TextureUniforms<'a> {
|
||||
)
|
||||
.attach_uniform(
|
||||
&format!("{}{}", self.name, "empty"),
|
||||
//&((self.texture.full as u8) as f32),
|
||||
&0.0,
|
||||
&((self.texture.missing as u8) as f32),
|
||||
)
|
||||
.attach_uniform(
|
||||
&format!("{}{}", self.name, "start_time"),
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::time::{DeltaTime, Time};
|
||||
use crate::Abort;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
const MAX_NUM_TILE_FETCHING: usize = 8;
|
||||
@@ -16,98 +16,25 @@ pub struct TileFetcherQueue {
|
||||
base_tile_queries: Vec<query::Tile>,
|
||||
tiles_fetched_time: Time,
|
||||
num_tiles_fetched: usize,
|
||||
|
||||
hips_local_files: HashMap<CreatorDid, HiPSLocalFiles>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[wasm_bindgen]
|
||||
pub struct HiPSLocalFiles {
|
||||
tiles: Box<[Box<[HashMap<u64, web_sys::File>]>; 4]>,
|
||||
moc: web_sys::File,
|
||||
}
|
||||
|
||||
use crate::tile_fetcher::query::Tile;
|
||||
use crate::HEALPixCell;
|
||||
use al_api::hips::ImageExt;
|
||||
use al_core::image::format::ImageFormatType;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl HiPSLocalFiles {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(moc: web_sys::File) -> Self {
|
||||
let tiles_per_fmt = vec![HashMap::new(); 30].into_boxed_slice();
|
||||
|
||||
Self {
|
||||
tiles: Box::new([
|
||||
tiles_per_fmt.clone(),
|
||||
tiles_per_fmt.clone(),
|
||||
tiles_per_fmt.clone(),
|
||||
tiles_per_fmt,
|
||||
]),
|
||||
moc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, depth: u8, ipix: u64, ext: ImageExt, file: web_sys::File) {
|
||||
let mut tiles_per_fmt = match ext {
|
||||
ImageExt::Fits => &mut self.tiles[0],
|
||||
ImageExt::Jpeg => &mut self.tiles[1],
|
||||
ImageExt::Png => &mut self.tiles[2],
|
||||
ImageExt::Webp => &mut self.tiles[3],
|
||||
};
|
||||
|
||||
tiles_per_fmt[depth as usize].insert(ipix, file);
|
||||
}
|
||||
|
||||
fn get_tile(&self, cell: &HEALPixCell, ext: ImageExt) -> Option<&web_sys::File> {
|
||||
let d = cell.depth() as usize;
|
||||
let i = cell.idx();
|
||||
|
||||
let tiles_per_fmt = match ext {
|
||||
ImageExt::Fits => &self.tiles[0],
|
||||
ImageExt::Jpeg => &self.tiles[1],
|
||||
ImageExt::Png => &self.tiles[2],
|
||||
ImageExt::Webp => &self.tiles[3],
|
||||
};
|
||||
|
||||
return tiles_per_fmt[d].get(&i);
|
||||
}
|
||||
|
||||
fn get_moc(&self) -> &web_sys::File {
|
||||
&self.moc
|
||||
}
|
||||
}
|
||||
|
||||
use crate::renderable::CreatorDid;
|
||||
impl TileFetcherQueue {
|
||||
pub fn new() -> Self {
|
||||
let queries = VecDeque::new();
|
||||
let base_tile_queries = Vec::new();
|
||||
let tiles_fetched_time = Time::now();
|
||||
let num_tiles_fetched = 0;
|
||||
|
||||
Self {
|
||||
queries,
|
||||
base_tile_queries,
|
||||
tiles_fetched_time,
|
||||
num_tiles_fetched,
|
||||
hips_local_files: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_hips_local_files(&mut self, id: CreatorDid, local_files: HiPSLocalFiles) {
|
||||
self.hips_local_files.insert(id, local_files);
|
||||
}
|
||||
|
||||
pub fn delete_hips_local_files(&mut self, id: &str) {
|
||||
self.hips_local_files.remove(id);
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.queries.clear();
|
||||
//self.query_set.clear();
|
||||
}
|
||||
|
||||
pub fn append(&mut self, query: query::Tile) {
|
||||
@@ -145,43 +72,23 @@ impl TileFetcherQueue {
|
||||
self.num_tiles_fetched
|
||||
}
|
||||
|
||||
fn check_in_file_list(&self, mut query: Tile) -> Result<Tile, JsValue> {
|
||||
if let Some(local_hips) = self.hips_local_files.get(&query.hips_cdid) {
|
||||
if let Some(tile) =
|
||||
local_hips.get_tile(&query.cell, query.format.get_ext_file().clone())
|
||||
{
|
||||
if let Ok(url) = web_sys::Url::create_object_url_with_blob(tile.as_ref()) {
|
||||
// rewrite the url
|
||||
query.url = url;
|
||||
Ok(query)
|
||||
} else {
|
||||
Err(JsValue::from_str("could not create an url from the tile"))
|
||||
}
|
||||
} else {
|
||||
Ok(query)
|
||||
}
|
||||
} else {
|
||||
Ok(query)
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch(&mut self, downloader: Rc<RefCell<Downloader>>) {
|
||||
// Fetch the base tiles with higher priority
|
||||
while let Some(query) = self.base_tile_queries.pop() {
|
||||
if let Ok(query) = self.check_in_file_list(query) {
|
||||
downloader.borrow_mut().fetch(query);
|
||||
}
|
||||
//if downloader.fetch(query) {
|
||||
// The fetch has succeded
|
||||
//self.num_tiles_fetched += 1;
|
||||
//}
|
||||
downloader.borrow_mut().fetch(query);
|
||||
}
|
||||
|
||||
let mut num_fetched_tile = 0;
|
||||
while num_fetched_tile < MAX_NUM_TILE_FETCHING && !self.queries.is_empty() {
|
||||
let query = self.queries.pop_back().unwrap_abort();
|
||||
|
||||
if let Ok(query) = self.check_in_file_list(query) {
|
||||
if downloader.borrow_mut().fetch(query) {
|
||||
// The fetch has succeded
|
||||
num_fetched_tile += 1;
|
||||
}
|
||||
if downloader.borrow_mut().fetch(query) {
|
||||
// The fetch has succeded
|
||||
num_fetched_tile += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,21 +105,8 @@ impl TileFetcherQueue {
|
||||
// The allsky is not mandatory present in a HiPS service but it is better to first try to search for it
|
||||
//downloader.fetch(query::PixelMetadata::new(cfg));
|
||||
// Try to fetch the MOC
|
||||
let hips_cdid = cfg.get_creator_did();
|
||||
let moc_url = if let Some(local_hips) = self.hips_local_files.get(hips_cdid) {
|
||||
if let Ok(url) =
|
||||
web_sys::Url::create_object_url_with_blob(local_hips.get_moc().as_ref())
|
||||
{
|
||||
url
|
||||
} else {
|
||||
format!("{}/Moc.fits", cfg.get_root_url())
|
||||
}
|
||||
} else {
|
||||
format!("{}/Moc.fits", cfg.get_root_url())
|
||||
};
|
||||
|
||||
downloader.borrow_mut().fetch(query::Moc::new(
|
||||
moc_url,
|
||||
format!("{}/Moc.fits", cfg.get_root_url()),
|
||||
cfg.get_creator_did().to_string(),
|
||||
al_api::moc::MOC::default(),
|
||||
));
|
||||
@@ -230,23 +124,20 @@ impl TileFetcherQueue {
|
||||
let hips_fmt = cfg.get_format();
|
||||
let min_order = cfg.get_min_depth_texture();
|
||||
|
||||
for tile_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||
if let Ok(query) = self.check_in_file_list(query::Tile::new(
|
||||
tile_cell,
|
||||
hips_cdid.clone(),
|
||||
hips_url.clone(),
|
||||
hips_fmt,
|
||||
)) {
|
||||
let dl = downloader.clone();
|
||||
|
||||
crate::utils::set_timeout(
|
||||
move || {
|
||||
dl.borrow_mut().fetch(query);
|
||||
},
|
||||
2_000,
|
||||
);
|
||||
}
|
||||
}
|
||||
let dl = downloader.clone();
|
||||
crate::utils::set_timeout(
|
||||
move || {
|
||||
for tile_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||
dl.borrow_mut().fetch(query::Tile::new(
|
||||
tile_cell,
|
||||
hips_cdid.clone(),
|
||||
hips_url.clone(),
|
||||
hips_fmt,
|
||||
));
|
||||
}
|
||||
},
|
||||
2_000,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
57
src/js/A.js
57
src/js/A.js
@@ -51,7 +51,8 @@ import { Sesame } from "./Sesame.js";
|
||||
import init, * as module from './../core/pkg';
|
||||
|
||||
// Import aladin css inside the project
|
||||
import aladinCSS from './../css/aladin.css?inline';
|
||||
import './../css/aladin.css';
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
/////// Aladin Lite API ///////
|
||||
@@ -96,32 +97,17 @@ A.aladin = function (divSelector, options) {
|
||||
} else {
|
||||
divElement = divSelector;
|
||||
}
|
||||
|
||||
// Associate the CSS inside the div
|
||||
var cssStyleSheet = document.createElement('style')
|
||||
cssStyleSheet.classList.add("aladin-css");
|
||||
cssStyleSheet.innerHTML = aladinCSS;
|
||||
divElement.appendChild(cssStyleSheet)
|
||||
|
||||
return new Aladin(divElement, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a HiPS image object
|
||||
*
|
||||
* @function
|
||||
* @name A.HiPS
|
||||
* @name A.imageHiPS
|
||||
* @memberof A
|
||||
* @param {string} id - Can be:
|
||||
* <ul>
|
||||
* <li>An http url towards a HiPS.</li>
|
||||
* <li>A relative path to your HiPS</li>
|
||||
* <li>A special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* </ul>
|
||||
* @param {HiPSOptions} [options] - Options describing the survey
|
||||
* @returns {HiPS} - A HiPS image object
|
||||
* @deprecated
|
||||
* Old method name, use {@link A.HiPS} instead.
|
||||
*/
|
||||
A.HiPS = function (id, options) {
|
||||
A.imageHiPS = function (id, options) {
|
||||
let url = id;
|
||||
return Aladin.createImageSurvey(
|
||||
id,
|
||||
@@ -134,13 +120,17 @@ A.HiPS = function (id, options) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HiPS image object
|
||||
*
|
||||
* @function
|
||||
* @name A.imageHiPS
|
||||
* @name A.HiPS
|
||||
* @memberof A
|
||||
* @deprecated
|
||||
* Old method name, use {@link A.HiPS} instead.
|
||||
* @param {string} id - Can be either an `url` that refers to a HiPS.
|
||||
* Or it can be a "CDS ID" pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}.
|
||||
* @param {HiPSOptions} [options] - Options describing the survey
|
||||
* @returns {HiPS} - A HiPS image object
|
||||
*/
|
||||
A.imageHiPS = A.HiPS;
|
||||
A.HiPS = A.imageHiPS;
|
||||
|
||||
/**
|
||||
* Creates a celestial source object with the given coordinates.
|
||||
@@ -453,19 +443,17 @@ A.MOCFromURL = function (url, options, successCallback, errorCallback) {
|
||||
* @returns {MOC} Returns a new MOC object
|
||||
*
|
||||
* @example
|
||||
* var json = {
|
||||
* "3": [517],
|
||||
* "4": [2065,2066,2067,2112,2344,2346,2432],
|
||||
* "5": [8221,8257,8258,8259,8293,8304,8305,8307,8308,8452,8456,9346,9352,9354,9736],
|
||||
* "6": [32861,32862,32863,32881,32882,32883,32892,32893,33025,33026,33027,33157,33168,33169,33171,
|
||||
* var json = {"3":[517],
|
||||
* "4":[2065,2066,2067,2112,2344,2346,2432],
|
||||
* "5":[8221,8257,8258,8259,8293,8304,8305,8307,8308,8452,8456,9346,9352,9354,9736],
|
||||
* "6":[32861,32862,32863,32881,32882,32883,32892,32893,33025,33026,33027,33157,33168,33169,33171,
|
||||
* 33181,33224,33225,33227,33236,33240,33812,33816,33828,33832,37377,37378,37379,37382,37388,
|
||||
* 37390,37412,37414,37420,37422,37562,38928,38930,38936,38948,38952],
|
||||
* "7": [131423,131439,131443,131523,131556,131557,131580,131581,132099,132612,132613,132624,132625,132627,132637,
|
||||
* "7":[131423,131439,131443,131523,131556,131557,131580,131581,132099,132612,132613,132624,132625,132627,132637,
|
||||
* 132680,132681,132683,132709,132720,132721,132904,132905,132948,132952,132964,132968,133008,133009,133012,135252,135256,135268,135316,135320,135332,135336,148143,148152,148154,149507,149520
|
||||
* ,149522,149523,149652,149654,149660,149662,149684,149686,149692,149694,149695,150120,150122,150208,150210,150216,150218,150240,150242,150243,155748,155752,155796,155800,155812,155816]
|
||||
* };
|
||||
* ,149522,149523,149652,149654,149660,149662,149684,149686,149692,149694,149695,150120,150122,150208,150210,150216,150218,150240,150242,150243,155748,155752,155796,155800,155812,155816]};
|
||||
* var moc = A.MOCFromJSON(json, {opacity: 0.25, color: 'magenta', lineWidth: 3});
|
||||
* aladin.addMOC(moc);
|
||||
* aladin.addMOC(moc);
|
||||
*/
|
||||
A.MOCFromJSON = function (jsonMOC, options, successCallback, errorCallback) {
|
||||
var moc = new MOC(options);
|
||||
@@ -824,7 +812,6 @@ A.catalogFromSKAORucio = function (target, radiusDegrees, options, successCallba
|
||||
*
|
||||
* @example
|
||||
* const cat = A.catalogFromVizieR('I/311/hip2', 'M 45', 5, {onClick: 'showTable'});
|
||||
* const cat2 = A.catalogFromVizieR('I/311/hip2', '12 +9', 5, {onClick: 'showTable'});
|
||||
*/
|
||||
A.catalogFromVizieR = function (vizCatId, target, radius, options, successCallback, errorCallback) {
|
||||
options = options || {};
|
||||
@@ -992,7 +979,7 @@ A.box = function(options) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Utils object.
|
||||
* Returns utils object
|
||||
*
|
||||
* This contains utilitary methods such as HEALPix basic or projection methods.
|
||||
*
|
||||
|
||||
@@ -146,7 +146,6 @@ import { Polyline } from "./shapes/Polyline";
|
||||
* @property {boolean} [samp=false] - Whether to enable SAMP (Simple Application Messaging Protocol).
|
||||
* @property {boolean} [realFullscreen=false] - Whether to use real fullscreen mode.
|
||||
* @property {boolean} [pixelateCanvas=true] - Whether to pixelate the canvas.
|
||||
* @property {boolean} [manualSelection=false] - When set to true, no selection will be performed, only events will be generated.
|
||||
* @example
|
||||
* let aladin = A.aladin({
|
||||
target: 'galactic center',
|
||||
@@ -714,7 +713,6 @@ export let Aladin = (function () {
|
||||
samp: false,
|
||||
realFullscreen: false,
|
||||
pixelateCanvas: true,
|
||||
manualSelection: false
|
||||
};
|
||||
|
||||
// realFullscreen: AL div expands not only to the size of its parent, but takes the whole available screen estate
|
||||
@@ -1464,7 +1462,7 @@ export let Aladin = (function () {
|
||||
* @memberof Aladin
|
||||
*/
|
||||
Aladin.prototype.removeOverlays = function () {
|
||||
this.view.removeOverlays();
|
||||
this.view.removeLayers();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1473,10 +1471,10 @@ export let Aladin = (function () {
|
||||
* @memberof Aladin
|
||||
*/
|
||||
Aladin.prototype.removeLayers = Aladin.prototype.removeOverlays;
|
||||
/**
|
||||
* @typedef {MOC|Catalog|ProgressiveCat|GraphicOverlay} Overlay
|
||||
* @description Possible overlays
|
||||
*/
|
||||
/**
|
||||
* @typedef {MOC|Catalog|ProgressiveCat|GraphicOverlay} Overlay
|
||||
* @description Possible overlays
|
||||
*/
|
||||
/**
|
||||
* Remove an overlay by its layer name
|
||||
*
|
||||
@@ -1484,11 +1482,10 @@ export let Aladin = (function () {
|
||||
* @param {string|Overlay} overlay - The name of the overlay to remove or the overlay object itself
|
||||
*/
|
||||
Aladin.prototype.removeOverlay = function (overlay) {
|
||||
if(typeof overlay === 'string' || overlay instanceof String) {
|
||||
if(overlay instanceof String)
|
||||
this.view.removeOverlayByName(overlay);
|
||||
} else {
|
||||
else
|
||||
this.view.removeOverlay(overlay);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1499,16 +1496,17 @@ export let Aladin = (function () {
|
||||
Aladin.prototype.removeLayer = Aladin.prototype.removeOverlay;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Creates and return an image survey (HiPS) object
|
||||
* Please use {@link A.hiPS} instead for creating a new survey image
|
||||
*
|
||||
* @memberof Aladin
|
||||
* @param {string} id - Mandatory unique identifier for the survey.
|
||||
* @param {string} [name] - A convinient name for the survey, optional
|
||||
* @param {string|FileList|HiPSLocalFiles} url - Can be:
|
||||
* @param {string} url - Can be:
|
||||
* <ul>
|
||||
* <li>An http url towards a HiPS.</li>
|
||||
* <li>A relative path to your HiPS</li>
|
||||
* <li>A special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* <li>A dict storing a local HiPS files. This object contains a tile file: hips[order][ipix] = File and refers to the properties file like so: hips["properties"] = File. </li>
|
||||
* A javascript {@link FileList} pointing to the opened webkit directory is also accepted.
|
||||
* <li>1. An url that refers to a HiPS.</li>
|
||||
* <li>Or it can be a "CDS ID" that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* </ul>
|
||||
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
|
||||
* @param {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
|
||||
@@ -1534,18 +1532,19 @@ export let Aladin = (function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Creates and return an image survey (HiPS) object.
|
||||
* Please use {@link A.hiPS} instead for creating a new survey image
|
||||
*
|
||||
* @function createImageSurvey
|
||||
* @memberof Aladin
|
||||
* @static
|
||||
* @param {string} id - Mandatory unique identifier for the survey.
|
||||
* @param {string} [name] - A convinient name for the survey, optional
|
||||
* @param {string|FileList|HiPSLocalFiles} url - Can be:
|
||||
* @param {string} url - Can be:
|
||||
* <ul>
|
||||
* <li>An http url towards a HiPS.</li>
|
||||
* <li>A relative path to your HiPS</li>
|
||||
* <li>A special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* <li>A dict storing a local HiPS files. This object contains a tile file: hips[order][ipix] = File and refers to the properties file like so: hips["properties"] = File. </li>
|
||||
* A javascript {@link FileList} pointing to the opened webkit directory is also accepted.
|
||||
* <li>1. An url that refers to a HiPS.</li>
|
||||
* <li>Or it can be a "CDS ID" that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* </ul>
|
||||
* @param {string} [cooFrame] - Values accepted: 'equatorial', 'icrs', 'icrsd', 'j2000', 'gal', 'galactic'
|
||||
* @param {number} [maxOrder] - The maximum HEALPix order of the HiPS, i.e the HEALPix order of the most refined tile images of the HiPS.
|
||||
@@ -1589,7 +1588,7 @@ export let Aladin = (function () {
|
||||
* <ul>
|
||||
* <li>1. An url that refers to a HiPS</li>
|
||||
* <li>2. Or it can be a CDS identifier that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* <li>3. A {@link HiPS} HiPS object</li>
|
||||
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||
* <li>4. A {@link Image} Image object</li>
|
||||
* </ul>
|
||||
*/
|
||||
@@ -1655,11 +1654,11 @@ export let Aladin = (function () {
|
||||
* Please use {@link A.hiPS} instead for creating a new survey image
|
||||
*
|
||||
* @memberof Aladin
|
||||
* @static
|
||||
* @param {string} id - Can be:
|
||||
* <ul>
|
||||
* <li>An http url towards a HiPS.</li>
|
||||
* <li>A relative path to your HiPS</li>
|
||||
* <li>A special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* <li>1. An url that refers to a HiPS.</li>
|
||||
* <li>Or it can be a "CDS ID" that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* </ul>
|
||||
* @param {HiPSOptions} [options] - Options for rendering the image
|
||||
* @param {function} [success] - A success callback
|
||||
@@ -1668,8 +1667,7 @@ export let Aladin = (function () {
|
||||
*/
|
||||
Aladin.prototype.newImageSurvey = function (id, options) {
|
||||
// a wrapper on createImageSurvey that aggregates all params in an options object
|
||||
return this.createImageSurvey(
|
||||
id,
|
||||
return this.createImageSurvey(id,
|
||||
options && options.name,
|
||||
id,
|
||||
options && options.cooFrame,
|
||||
@@ -1750,29 +1748,11 @@ export let Aladin = (function () {
|
||||
return this.backgroundColor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an image layer/overlay from the instance
|
||||
*
|
||||
* @memberof Aladin
|
||||
* @param {string|Overlay} item - the overlay object or image layer name to remove
|
||||
*/
|
||||
Aladin.prototype.remove = function (item) {
|
||||
const layers = this.getStackLayers()
|
||||
let idxToDelete = layers.findIndex(l => l === item);
|
||||
if (idxToDelete >= 0) {
|
||||
this.view.removeImageLayer(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// must be an overlay
|
||||
this.view.removeOverlay(item)
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a specific layer
|
||||
*
|
||||
* @memberof Aladin
|
||||
* @param {string} layer - The name of the layer to remove or the HiPS/Image object
|
||||
* @param {string} layer - The name of the layer to remove
|
||||
*/
|
||||
Aladin.prototype.removeImageLayer = function (layer) {
|
||||
this.view.removeImageLayer(layer);
|
||||
@@ -1813,7 +1793,7 @@ export let Aladin = (function () {
|
||||
* <li>1. An url that refers to a HiPS.</li>
|
||||
* <li>2. Or it can be a CDS ID that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* <li>3. A {@link HiPS} HiPS object created from {@link A.HiPS}</li>
|
||||
* <li>4. A {@link Image} FITS/jpeg/png image</li>
|
||||
* <li>4. A {@link Image} FITS/jped/png image</li>
|
||||
* </ul>
|
||||
* @param {string} [layer="overlay"] - A layer name. By default 'overlay' is chosen and it is destined to be plot
|
||||
* on top the 'base' layer. If the layer is already present in the view, it will be replaced by the new HiPS/FITS image given here.
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
import { Aladin } from "./Aladin";
|
||||
import { Sesame } from "./Sesame";
|
||||
|
||||
/**
|
||||
* @namespace AladinUtils
|
||||
@@ -146,28 +145,6 @@ export let AladinUtils = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @namespace Sesame
|
||||
* @memberof AladinUtils
|
||||
* @description Namespace for Sesame related service.
|
||||
*/
|
||||
Sesame: {
|
||||
/**
|
||||
* Find RA, DEC for any target (object name or position) <br/>
|
||||
* if successful, callback is called with an object {ra: {@link number}, dec: {@link number}} <br/>
|
||||
* if not successful, errorCallback is called
|
||||
*
|
||||
* @function
|
||||
* @memberof AladinUtils.Sesame
|
||||
* @name resolveAstronomicalName
|
||||
*
|
||||
* @param {string} target - object name or position
|
||||
* @param {Function} callback - if successful, callback is called with an object {ra: {@link number}, dec: {@link number}}
|
||||
* @param {Function} errorCallback - if not successful, errorCallback is called with the error
|
||||
*/
|
||||
resolveAstronomicalName: Sesame.getTargetRADec
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
|
||||
@@ -47,7 +47,7 @@ import { Footprint } from "./Footprint.js";
|
||||
* @property {string} [name="catalog"] - The name of the catalog.
|
||||
* @property {string} [color] - The color associated with the catalog.
|
||||
* @property {number} [sourceSize=8] - The size of the sources in the catalog.
|
||||
* @property {string|Function|Image|HTMLCanvasElement|HTMLImageElement} [shape="square"] - The shape of the sources (can be, "square", "circle", "plus", "cross", "rhomb", "triangle").
|
||||
* @property {string|function|Image|HTMLCanvasElement} [shape="square"] - The shape of the sources (can be, "square", "circle", "plus", "cross", "rhomb", "triangle").
|
||||
* @property {number} [limit] - The maximum number of sources to display.
|
||||
* @property {string|Function} [onClick] - Whether the source data appears as a table row or a in popup. Can be 'showTable' string, 'showPopup' string or a custom user defined function that handles the click.
|
||||
* @property {boolean} [readOnly=false] - Whether the catalog is read-only.
|
||||
@@ -79,9 +79,7 @@ export let Catalog = (function () {
|
||||
* markerSize: 15,
|
||||
* shape: "circle",
|
||||
* limit: 1000,
|
||||
* onClick: (source) => {
|
||||
* // handle sources
|
||||
* },
|
||||
* onClick: (source) => { /* handle source click * },
|
||||
* readOnly: true,
|
||||
* raField: "ra",
|
||||
* decField: "dec",
|
||||
@@ -481,17 +479,7 @@ export let Catalog = (function () {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the shape of the sources
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {Object} [options] - shape options
|
||||
* @param {string} [options.color] - the color of the shape
|
||||
* @param {number} [options.sourceSize] - size of the shape
|
||||
* @param {string|Function|HTMLImageCanvas|HTMLImageElement} [options.shape="square"] - the type of the shape. Can be square, rhomb, plus, cross, triangle, circle.
|
||||
* A callback function can also be called that return an HTMLImageElement in function of the source object. A canvas or an image can also be given.
|
||||
*/
|
||||
// API
|
||||
Catalog.prototype.updateShape = function (options) {
|
||||
options = options || {};
|
||||
this.color = options.color || this.color || Color.getNextColor();
|
||||
@@ -536,13 +524,7 @@ export let Catalog = (function () {
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
/**
|
||||
* Add sources to the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {Source[]} sources - An array of sources or only one source to add
|
||||
*/
|
||||
// API
|
||||
Catalog.prototype.addSources = function (sources) {
|
||||
// make sure we have an array and not an individual source
|
||||
sources = [].concat(sources);
|
||||
@@ -577,6 +559,17 @@ export let Catalog = (function () {
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
/*Catalog.prototype.addFootprints = function(footprintsToAdd) {
|
||||
footprintsToAdd = [].concat(footprintsToAdd); // make sure we have an array and not an individual footprints
|
||||
this.footprints = this.footprints.concat(footprintsToAdd);
|
||||
|
||||
footprintsToAdd.forEach(f => {
|
||||
f.setCatalog(this);
|
||||
})
|
||||
|
||||
this.reportChange();
|
||||
};*/
|
||||
|
||||
Catalog.prototype.computeFootprints = function (sources) {
|
||||
let footprints = [];
|
||||
|
||||
@@ -626,14 +619,12 @@ export let Catalog = (function () {
|
||||
this.showFieldCallback[field] = callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create sources from a 2d array and add them to the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {String[]} columnNames - array with names of the columns
|
||||
* @param {String[][]|number[][]} array - 2D-array, each item being a 1d-array with the same number of items as columnNames
|
||||
*/
|
||||
// API
|
||||
//
|
||||
// create sources from a 2d array and add them to the catalog
|
||||
//
|
||||
// @param columnNames: array with names of the columns
|
||||
// @array: 2D-array, each item being a 1d-array with the same number of items as columnNames
|
||||
Catalog.prototype.addSourcesAsArray = function (columnNames, array) {
|
||||
var fields = [];
|
||||
for (var colIdx = 0; colIdx < columnNames.length; colIdx++) {
|
||||
@@ -675,13 +666,7 @@ export let Catalog = (function () {
|
||||
this.addSources(newSources);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all the sources
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @returns {Source[]} - an array of all the sources in the catalog object
|
||||
*/
|
||||
// return the current list of Source objects
|
||||
Catalog.prototype.getSources = function () {
|
||||
return this.sources;
|
||||
};
|
||||
@@ -690,11 +675,7 @@ export let Catalog = (function () {
|
||||
return this.footprints;
|
||||
};
|
||||
|
||||
/**
|
||||
* Select all the source catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*/
|
||||
// TODO : fonction générique traversant la liste des sources
|
||||
Catalog.prototype.selectAll = function () {
|
||||
if (!this.sources) {
|
||||
return;
|
||||
@@ -705,11 +686,6 @@ export let Catalog = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unselect all the source of the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*/
|
||||
Catalog.prototype.deselectAll = function () {
|
||||
if (!this.sources) {
|
||||
return;
|
||||
@@ -720,15 +696,7 @@ export let Catalog = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get one source by its index in the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {number} idx - the index of the source in the catalog sources
|
||||
*
|
||||
* @returns {Source} - the source at the index
|
||||
*/
|
||||
// return a source by index
|
||||
Catalog.prototype.getSource = function (idx) {
|
||||
if (idx < this.sources.length) {
|
||||
return this.sources[idx];
|
||||
@@ -746,86 +714,37 @@ export let Catalog = (function () {
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the color of the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {String} - the new color
|
||||
*/
|
||||
Catalog.prototype.setColor = function (color) {
|
||||
this.color = color;
|
||||
this.updateShape();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the color of selected sources
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {String} - the new color
|
||||
*/
|
||||
Catalog.prototype.setSelectionColor = function (color) {
|
||||
this.selectionColor = color;
|
||||
this.updateShape();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the color of hovered sources
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {String} - the new color
|
||||
*/
|
||||
Catalog.prototype.setHoverColor = function (color) {
|
||||
this.hoverColor = color;
|
||||
this.updateShape();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the size of the catalog sources
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {number} - the new size
|
||||
*/
|
||||
Catalog.prototype.setSourceSize = function (sourceSize) {
|
||||
// will be discarded in updateShape if the shape is an Image
|
||||
this.sourceSize = sourceSize;
|
||||
this.updateShape();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the color of the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {string|Function|HTMLImageCanvas|HTMLImageElement} [shape="square"] - the type of the shape. Can be square, rhomb, plus, cross, triangle, circle.
|
||||
* A callback function can also be called that return an HTMLImageElement in function of the source object. A canvas or an image can also be given.
|
||||
*/
|
||||
Catalog.prototype.setShape = function (shape) {
|
||||
this.shape = shape;
|
||||
this.updateShape();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the size of the catalog sources
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @returns {number} - the size of the sources
|
||||
*/
|
||||
Catalog.prototype.getSourceSize = function () {
|
||||
return this.sourceSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a specific source from the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*
|
||||
* @param {Source} - the source to remove
|
||||
*/
|
||||
// remove a source
|
||||
Catalog.prototype.remove = function (source) {
|
||||
var idx = this.sources.indexOf(source);
|
||||
if (idx < 0) {
|
||||
@@ -843,19 +762,12 @@ export let Catalog = (function () {
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear all the sources from the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*/
|
||||
Catalog.prototype.removeAll = Catalog.prototype.clear = function () {
|
||||
// TODO : RAZ de l'index
|
||||
this.sources = [];
|
||||
this.ra = [];
|
||||
this.dec = [];
|
||||
this.footprints = [];
|
||||
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
Catalog.prototype.draw = function (ctx, width, height) {
|
||||
@@ -1001,11 +913,6 @@ export let Catalog = (function () {
|
||||
this.view && this.view.requestRedraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*/
|
||||
Catalog.prototype.show = function () {
|
||||
if (this.isShowing) {
|
||||
return;
|
||||
@@ -1019,11 +926,6 @@ export let Catalog = (function () {
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the catalog
|
||||
*
|
||||
* @memberof Catalog
|
||||
*/
|
||||
Catalog.prototype.hide = function () {
|
||||
if (!this.isShowing) {
|
||||
return;
|
||||
|
||||
@@ -206,12 +206,6 @@ export let DefaultActionsForContextMenu = (function () {
|
||||
action(o) {
|
||||
a.select('rect', selectObjects)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Polygon',
|
||||
action(o) {
|
||||
a.select('poly', selectObjects)
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -57,9 +57,8 @@ export class CircleSelect extends FSM {
|
||||
let ctx = view.catalogCtx;
|
||||
|
||||
// draw the selection
|
||||
let colorValue = (typeof options.color === 'function') ? options.color(this.startCoo, this.coo) : options.color;
|
||||
ctx.fillStyle = colorValue;
|
||||
ctx.strokeStyle = colorValue;
|
||||
ctx.fillStyle = options.color + '7f';
|
||||
ctx.strokeStyle = options.color;
|
||||
ctx.lineWidth = options.lineWidth;
|
||||
|
||||
var r2 = (this.coo.x - this.startCoo.x) * (this.coo.x - this.startCoo.x) + (this.coo.y - this.startCoo.y) * (this.coo.y - this.startCoo.y);
|
||||
@@ -113,7 +112,7 @@ export class CircleSelect extends FSM {
|
||||
}
|
||||
|
||||
// execute selection callback only
|
||||
(typeof this.callback === 'function') && this.callback(s, Selector.getObjects(s, view));
|
||||
(typeof this.callback === 'function') && this.callback(s);
|
||||
|
||||
// TODO: remove these modes in the future
|
||||
view.aladin.showReticle(true)
|
||||
|
||||
@@ -22,7 +22,6 @@ import { ActionButton } from "../gui/Widgets/ActionButton";
|
||||
import { View } from "../View";
|
||||
import finishIconUrl from '../../../assets/icons/finish.svg';
|
||||
import { Utils } from "../Utils";
|
||||
import { Selector } from "../Selector";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
@@ -119,12 +118,11 @@ export class PolySelect extends FSM {
|
||||
|
||||
let draw = () => {
|
||||
let ctx = view.catalogCtx;
|
||||
|
||||
|
||||
// draw the selection
|
||||
ctx.save();
|
||||
let colorValue = (typeof options.color === 'function') ? options.color() : options.color;
|
||||
ctx.fillStyle = colorValue;
|
||||
ctx.strokeStyle = colorValue;
|
||||
ctx.fillStyle = options.color + '7f';
|
||||
ctx.strokeStyle = options.color;
|
||||
ctx.lineWidth = options.lineWidth;
|
||||
|
||||
ctx.beginPath();
|
||||
@@ -146,11 +144,6 @@ export class PolySelect extends FSM {
|
||||
|
||||
let finish = () => {
|
||||
// finish the selection
|
||||
const numCoo = this.coos.length;
|
||||
if (numCoo <= 1) {
|
||||
this.dispatch('off');
|
||||
return;
|
||||
}
|
||||
let xMin = this.coos[0].x
|
||||
let yMin = this.coos[0].y
|
||||
let xMax = this.coos[0].x
|
||||
@@ -170,32 +163,17 @@ export class PolySelect extends FSM {
|
||||
let s = {
|
||||
vertices: this.coos,
|
||||
label: 'polygon',
|
||||
contains(s) {
|
||||
let x = s.x;
|
||||
let y = s.y;
|
||||
|
||||
let inside = false;
|
||||
for (let i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
|
||||
let xi = this.vertices[i].x, yi = this.vertices[i].y;
|
||||
let xj = this.vertices[j].x, yj = this.vertices[j].y;
|
||||
|
||||
let intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||
if (intersect) inside = !inside;
|
||||
}
|
||||
return inside;
|
||||
},
|
||||
bbox() {
|
||||
return {x, y, w, h}
|
||||
}
|
||||
};
|
||||
(typeof this.callback === 'function') && this.callback(s, Selector.getObjects(s, view));
|
||||
(typeof this.callback === 'function') && this.callback(s);
|
||||
|
||||
// execute general callback
|
||||
if (view.aladin.callbacksByEventName) {
|
||||
var callback = view.aladin.callbacksByEventName['objectsSelected'] || view.aladin.callbacksByEventName['select'];
|
||||
if (typeof callback === "function") {
|
||||
let objList = Selector.getObjects(s, view);
|
||||
callback(objList);
|
||||
console.warn('polygon selection is not fully implemented, PolySelect.contains is needed for finding sources inside a polygon')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +202,7 @@ export class PolySelect extends FSM {
|
||||
mousedown
|
||||
},
|
||||
mousedown: {
|
||||
//mouseout,
|
||||
mousemove,
|
||||
draw,
|
||||
},
|
||||
@@ -267,7 +246,6 @@ export class PolySelect extends FSM {
|
||||
//mouseout,
|
||||
mousemove,
|
||||
draw,
|
||||
finish,
|
||||
},
|
||||
mouseout: {
|
||||
start,
|
||||
|
||||
@@ -58,10 +58,8 @@ export class RectSelect extends FSM {
|
||||
let ctx = view.catalogCtx;
|
||||
|
||||
// draw the selection
|
||||
let colorValue = (typeof options.color === 'function') ? options.color(this.startCoo, this.coo) : options.color;
|
||||
|
||||
ctx.fillStyle = colorValue;
|
||||
ctx.strokeStyle = colorValue;
|
||||
ctx.fillStyle = options.color + '7f';
|
||||
ctx.strokeStyle = options.color;
|
||||
ctx.lineWidth = options.lineWidth;
|
||||
|
||||
var w = this.coo.x - this.startCoo.x;
|
||||
@@ -101,7 +99,7 @@ export class RectSelect extends FSM {
|
||||
}
|
||||
};
|
||||
|
||||
(typeof this.callback === 'function') && this.callback(s, Selector.getObjects(s, view));
|
||||
(typeof this.callback === 'function') && this.callback(s);
|
||||
|
||||
// TODO: remove these modes in the future
|
||||
view.aladin.showReticle(true)
|
||||
|
||||
132
src/js/HiPS.js
132
src/js/HiPS.js
@@ -28,7 +28,7 @@
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
import { ColorCfg } from "./ColorCfg.js";
|
||||
import { HiPSProperties } from "./HiPSProperties.js";
|
||||
import { Aladin } from "./Aladin.js";
|
||||
|
||||
let PropertyParser = {};
|
||||
// Utilitary functions for parsing the properties and giving default values
|
||||
/// Mandatory tileSize property
|
||||
@@ -153,24 +153,6 @@ PropertyParser.isPlanetaryBody = function (properties) {
|
||||
* @property {number} [brightness=0.0] - The brightness value for the color configuration.
|
||||
* @property {number} [contrast=0.0] - The contrast value for the color configuration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileList
|
||||
*
|
||||
* JS {@link https://developer.mozilla.org/fr/docs/Web/API/FileList| FileList} API type
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} HiPSLocalFiles
|
||||
*
|
||||
* @property {File} properties - The local properties file of the HiPS
|
||||
*
|
||||
* @description
|
||||
* Tiles are accessed like so: HIPSLocalFiles[norder][ipix] = {@link File};<br/>
|
||||
* The properties file is accessed with: HIPSLocalFiles["properties"]
|
||||
*/
|
||||
|
||||
|
||||
export let HiPS = (function () {
|
||||
/**
|
||||
* The object describing an image survey
|
||||
@@ -179,14 +161,10 @@ export let HiPS = (function () {
|
||||
* @constructs HiPS
|
||||
*
|
||||
* @param {string} id - Mandatory unique identifier for the layer. Can be an arbitrary name
|
||||
* @param {string|FileList|HiPSLocalFiles} url - Can be:
|
||||
* <ul>
|
||||
* <li>An http url towards a HiPS.</li>
|
||||
* <li>A relative path to your HiPS</li>
|
||||
* <li>A special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}</li>
|
||||
* <li>A dict storing a local HiPS files. This object contains a tile file: hips[order][ipix] = File and refers to the properties file like so: hips["properties"] = File. </li>
|
||||
* A javascript {@link FileList} pointing to the opened webkit directory is also accepted.
|
||||
* </ul>
|
||||
* @param {string} location - Can be:
|
||||
* - an http url <br/>
|
||||
* - a relative path to your HiPS <br/>
|
||||
* - a special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}
|
||||
* @param {HiPSOptions} [options] - The option for the survey
|
||||
*
|
||||
* @description Giving a CDS ID will do a query to the MOCServer first to retrieve metadata. Then it will also check for the presence of faster HiPS nodes to choose a faster url to query to tiles from.
|
||||
@@ -200,41 +178,6 @@ export let HiPS = (function () {
|
||||
this.name = (options && options.name) || undefined;
|
||||
this.startUrl = options.startUrl;
|
||||
|
||||
if (location instanceof FileList) {
|
||||
let localFiles = {};
|
||||
for (var file of location) {
|
||||
let path = file.webkitRelativePath;
|
||||
if (path.includes("Norder") && path.includes("Npix")) {
|
||||
const order = +path.substring(path.indexOf("Norder") + 6).split("/")[0];
|
||||
if (!localFiles[order]) {
|
||||
localFiles[order] = {}
|
||||
}
|
||||
|
||||
let tile = path.substring(path.indexOf("Npix") + 4).split(".");
|
||||
const ipix = +tile[0];
|
||||
const fmt = tile[1];
|
||||
|
||||
if (!localFiles[order][ipix]) {
|
||||
localFiles[order][ipix] = {}
|
||||
}
|
||||
|
||||
localFiles[order][ipix][fmt] = file;
|
||||
}
|
||||
|
||||
if (path.includes("properties")) {
|
||||
localFiles['properties'] = file;
|
||||
}
|
||||
|
||||
if (path.includes("Moc")) {
|
||||
localFiles['moc'] = file;
|
||||
}
|
||||
}
|
||||
|
||||
this.localFiles = localFiles;
|
||||
} else if (location instanceof Object) {
|
||||
this.localFiles = location;
|
||||
}
|
||||
|
||||
this.url = location;
|
||||
this.maxOrder = options.maxOrder;
|
||||
this.minOrder = options.minOrder || 0;
|
||||
@@ -459,30 +402,11 @@ export let HiPS = (function () {
|
||||
}
|
||||
this.view = view;
|
||||
|
||||
if (this.localFiles) {
|
||||
// Fetch the properties file
|
||||
self.query = (async () => {
|
||||
// look for the properties file
|
||||
await HiPSProperties.fetchFromFile(self.localFiles["properties"])
|
||||
.then((p) => {
|
||||
self._parseProperties(p);
|
||||
|
||||
self.url = "local";
|
||||
|
||||
delete self.localFiles["properties"]
|
||||
})
|
||||
|
||||
return self;
|
||||
})();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let isIncompleteOptions = true;
|
||||
|
||||
// This is very dirty but it allows me to differentiate the location from whether it is an ID or a plain url
|
||||
// This is very dirty but it allows me to differentiate the location from
|
||||
// whether an ID or a plain url
|
||||
let isID = this.url.includes("P/") || this.url.includes("C/")
|
||||
|
||||
|
||||
if (this.imgFormat === "fits") {
|
||||
// a fits is given
|
||||
isIncompleteOptions = !(
|
||||
@@ -504,6 +428,7 @@ export let HiPS = (function () {
|
||||
}
|
||||
|
||||
self.query = (async () => {
|
||||
|
||||
if (isIncompleteOptions) {
|
||||
// ID typed url
|
||||
if (self.startUrl && isID) {
|
||||
@@ -534,6 +459,8 @@ export let HiPS = (function () {
|
||||
},
|
||||
1000
|
||||
);
|
||||
|
||||
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
@@ -872,7 +799,7 @@ export let HiPS = (function () {
|
||||
this.layer = layer;
|
||||
let self = this;
|
||||
|
||||
const config = {
|
||||
this.view.wasm.addHiPS({
|
||||
layer,
|
||||
properties: {
|
||||
creatorDid: self.creatorDid,
|
||||
@@ -894,39 +821,8 @@ export let HiPS = (function () {
|
||||
...this.colorCfg.get(),
|
||||
longitudeReversed: this.longitudeReversed,
|
||||
imgFormat: this.imgFormat,
|
||||
}
|
||||
};
|
||||
|
||||
let localFiles;
|
||||
if (this.localFiles) {
|
||||
localFiles = new Aladin.wasmLibs.core.HiPSLocalFiles(this.localFiles["moc"]);
|
||||
|
||||
let fmt;
|
||||
for (var order in this.localFiles) {
|
||||
if (order === "moc")
|
||||
continue;
|
||||
|
||||
for (var ipix in this.localFiles[order]) {
|
||||
for (var f in this.localFiles[order][ipix]) {
|
||||
if (f === "png") {
|
||||
fmt = Aladin.wasmLibs.core.ImageExt.Png;
|
||||
} else if (f === "fits") {
|
||||
fmt = Aladin.wasmLibs.core.ImageExt.Fits;
|
||||
} else {
|
||||
fmt = Aladin.wasmLibs.core.ImageExt.Jpeg;
|
||||
}
|
||||
|
||||
const tileFile = this.localFiles[order][+ipix][f];
|
||||
localFiles.insert(+order, BigInt(+ipix), fmt, tileFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.view.wasm.addHiPS(
|
||||
config,
|
||||
localFiles
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return Promise.resolve(this)
|
||||
.then((hips) => {
|
||||
|
||||
@@ -70,8 +70,6 @@ HiPSProperties.fetchFromID = async function(ID) {
|
||||
}
|
||||
|
||||
HiPSProperties.fetchFromUrl = async function(urlOrId) {
|
||||
let url;
|
||||
|
||||
try {
|
||||
urlOrId = new URL(urlOrId);
|
||||
} catch (e) {
|
||||
@@ -87,7 +85,7 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
|
||||
// Fetch the properties of the survey
|
||||
const HiPSServiceUrl = urlOrId.toString();
|
||||
|
||||
url = HiPSServiceUrl;
|
||||
let url = HiPSServiceUrl;
|
||||
// Use the url for retrieving the HiPS properties
|
||||
// remove final slash
|
||||
if (url.slice(-1) === '/') {
|
||||
@@ -100,7 +98,6 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
|
||||
// fix for HTTPS support --> will work for all HiPS served by CDS
|
||||
url = Utils.fixURLForHTTPS(url)
|
||||
|
||||
|
||||
let init = {};
|
||||
if (Utils.requestCORSIfNotSameOrigin(url)) {
|
||||
init = { mode: 'cors' };
|
||||
@@ -124,9 +121,7 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
|
||||
if (!metadata.hips_frame || !metadata.hips_order) {
|
||||
reject('Bad properties: do not contain the mandatory frame or order info')
|
||||
} else {
|
||||
if (!("hips_service_url" in metadata)) {
|
||||
metadata.hips_service_url = HiPSServiceUrl;
|
||||
}
|
||||
metadata.hips_service_url = HiPSServiceUrl;
|
||||
resolve(metadata);
|
||||
}
|
||||
} else {
|
||||
@@ -138,27 +133,6 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) {
|
||||
return result;
|
||||
}
|
||||
|
||||
HiPSProperties.fetchFromFile = function(file) {
|
||||
let url = URL.createObjectURL(file);
|
||||
return fetch(url)
|
||||
.then((response) => response.text())
|
||||
.then(
|
||||
(response) => new Promise((resolve, reject) => {
|
||||
// We get the property here
|
||||
let metadata = HiPSDefinition.parseHiPSProperties(response);
|
||||
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
// 1. Ensure there is exactly one survey matching
|
||||
if (metadata && Object.keys(metadata).length > 0) {
|
||||
resolve(metadata)
|
||||
} else {
|
||||
reject('No surveys matching at this url: ' + rootURL);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
HiPSProperties.getFasterMirrorUrl = function (metadata) {
|
||||
const pingHiPSServiceUrl = async (baseUrl) => {
|
||||
baseUrl = Utils.fixURLForHTTPS(baseUrl);
|
||||
|
||||
@@ -31,36 +31,6 @@ import { Utils } from "./Utils";
|
||||
import { AVM } from "./libs/avm.js";
|
||||
import { HiPS } from "./HiPS.js";
|
||||
|
||||
/**
|
||||
* @typedef {Object} WCS
|
||||
*
|
||||
* {@link https://ui.adsabs.harvard.edu/abs/2002A%26A...395.1077C/abstract|FITS (Paper II)}, Calabretta, M. R., and Greisen, E. W., Astronomy & Astrophysics, 395, 1077-1122, 2002
|
||||
*
|
||||
* @property {number} [NAXIS]
|
||||
* @property {string} CTYPE1
|
||||
* @property {string} [CTYPE2]
|
||||
* @property {number} [LONPOLE]
|
||||
* @property {number} [LATPOLE]
|
||||
* @property {number} [CRVAL1]
|
||||
* @property {number} [CRVAL2]
|
||||
* @property {number} [CRPIX1]
|
||||
* @property {number} [CRPIX2]
|
||||
* @property {string} [CUNIT1] - e.g. 'deg'
|
||||
* @property {string} [CUNIT2] - e.g. 'deg'
|
||||
* @property {number} [CD1_1]
|
||||
* @property {number} [CD1_2]
|
||||
* @property {number} [CD2_1]
|
||||
* @property {number} [CD2_2]
|
||||
* @property {number} [PC1_1]
|
||||
* @property {number} [PC1_2]
|
||||
* @property {number} [PC2_1]
|
||||
* @property {number} [PC2_2]
|
||||
* @property {number} [CDELT1]
|
||||
* @property {number} [CDELT2]
|
||||
* @property {number} [NAXIS1]
|
||||
* @property {number} [NAXIS2]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ImageOptions
|
||||
*
|
||||
@@ -78,7 +48,7 @@ import { HiPS } from "./HiPS.js";
|
||||
* @property {number} [saturation=0.0] - The saturation value for the color configuration.
|
||||
* @property {number} [brightness=0.0] - The brightness value for the color configuration.
|
||||
* @property {number} [contrast=0.0] - The contrast value for the color configuration.
|
||||
* @property {WCS} [wcs] - an object describing the WCS of the image. In case of a fits image
|
||||
* @property {Object} [wcs] - an object describing the WCS of the image. In case of a fits image
|
||||
* this property will be ignored as the WCS taken will be the one present in the fits file.
|
||||
* @property {string} [imgFormat] - Optional image format. Giving it will prevent the auto extension determination algorithm to be triggered. Possible values are 'jpeg', 'png' or 'fits'. tiff files are not supported. You can convert your tiff files to jpg ones by using the fantastic image magick suite.
|
||||
*
|
||||
|
||||
@@ -134,7 +134,7 @@ export let MOC = (function() {
|
||||
if (data instanceof ArrayBuffer) {
|
||||
// from an url
|
||||
const buf = data;
|
||||
self.view.wasm.addFITSMOC(self.mocParams, new Uint8Array(buf));
|
||||
self.view.wasm.addFITSMoc(self.mocParams, new Uint8Array(buf));
|
||||
} else if(data.ra && data.dec && data.radius) {
|
||||
// circle
|
||||
const c = data;
|
||||
|
||||
@@ -94,7 +94,7 @@ export class Selector {
|
||||
|
||||
var objList = [];
|
||||
var cat, sources, s;
|
||||
var overlayItems, f;
|
||||
var footprints, f;
|
||||
var objListPerCatalog = [];
|
||||
if (view.catalogs) {
|
||||
for (var k = 0; k < view.catalogs.length; k++) {
|
||||
@@ -114,11 +114,11 @@ export class Selector {
|
||||
}
|
||||
}
|
||||
// footprints
|
||||
overlayItems = cat.getFootprints();
|
||||
if (overlayItems) {
|
||||
footprints = cat.getFootprints();
|
||||
if (footprints) {
|
||||
const {x, y, w, h} = selection.bbox();
|
||||
for (var l = 0; l < overlayItems.length; l++) {
|
||||
f = overlayItems[l];
|
||||
for (var l = 0; l < footprints.length; l++) {
|
||||
f = footprints[l];
|
||||
if (f.intersectsBBox(x, y, w, h, view)) {
|
||||
objListPerCatalog.push(f);
|
||||
}
|
||||
@@ -132,27 +132,6 @@ export class Selector {
|
||||
}
|
||||
}
|
||||
|
||||
if (view.overlays) {
|
||||
const {x, y, w, h} = selection.bbox();
|
||||
for (var k = 0; k < view.overlays.length; k++) {
|
||||
let overlay = view.overlays[k];
|
||||
if (!overlay.isShowing) {
|
||||
continue;
|
||||
}
|
||||
var overlayItems = overlay.overlayItems;
|
||||
for (var l = 0; l < overlayItems.length; l++) {
|
||||
let o = overlayItems[l];
|
||||
if (!o.isShowing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (o.intersectsBBox && o.intersectsBBox(x, y, w, h, view)) {
|
||||
objList.push([o]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return objList;
|
||||
}
|
||||
}
|
||||
@@ -62,18 +62,16 @@ export let Sesame = (function() {
|
||||
// ask resolution by Sesame
|
||||
else {
|
||||
Sesame.resolve(target,
|
||||
function(data) { // success callback
|
||||
callback({
|
||||
ra: data.coo.jradeg,
|
||||
dec: data.coo.jdedeg
|
||||
});
|
||||
},
|
||||
function(data) { // success callback
|
||||
callback({ra: data.Target.Resolver.jradeg,
|
||||
dec: data.Target.Resolver.jdedeg});
|
||||
},
|
||||
|
||||
function(data) { // error callback
|
||||
if (errorCallback) {
|
||||
errorCallback(data);
|
||||
}
|
||||
}
|
||||
function(data) { // error callback
|
||||
if (errorCallback) {
|
||||
errorCallback();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -126,7 +126,7 @@ export let View = (function () {
|
||||
this.aladinDiv.ondragover = Utils.dragOverHandler;
|
||||
|
||||
this.throttledPositionChanged = Utils.throttle(
|
||||
(dragging) => {
|
||||
() => {
|
||||
var posChangedFn = this.aladin.callbacksByEventName && this.aladin.callbacksByEventName['positionChanged'];
|
||||
if (typeof posChangedFn === 'function') {
|
||||
var pos = this.aladin.pix2world(this.width / 2, this.height / 2, 'icrs');
|
||||
@@ -135,7 +135,7 @@ export let View = (function () {
|
||||
posChangedFn({
|
||||
ra: pos[0],
|
||||
dec: pos[1],
|
||||
dragging: dragging
|
||||
dragging: true
|
||||
});
|
||||
} catch(e) {
|
||||
console.error(e)
|
||||
@@ -205,8 +205,7 @@ export let View = (function () {
|
||||
const cooFrame = CooFrameEnum.fromString(this.options.cooFrame, CooFrameEnum.J2000);
|
||||
this.changeFrame(cooFrame);
|
||||
|
||||
this.selector = new Selector(this, this.options.selector);
|
||||
this.manualSelection = (this.options && this.options.manualSelection) || false;
|
||||
this.selector = new Selector(this);
|
||||
|
||||
// current reference image survey displayed
|
||||
this.imageLayers = new Map();
|
||||
@@ -576,7 +575,7 @@ export let View = (function () {
|
||||
const xymouse = Utils.relMouseCoords(e);
|
||||
|
||||
// deselect all the selected sources with Select panel
|
||||
view.unselectObjects();
|
||||
view.unselectObjects()
|
||||
|
||||
try {
|
||||
const [lon, lat] = view.aladin.pix2world(xymouse.x, xymouse.y, 'icrs');
|
||||
@@ -619,7 +618,7 @@ export let View = (function () {
|
||||
var handleSelect = function(xy, tolerance) {
|
||||
tolerance = tolerance || 5;
|
||||
var objs = view.closestObjects(xy.x, xy.y, tolerance);
|
||||
|
||||
// Deselect objects if any
|
||||
view.unselectObjects();
|
||||
|
||||
if (objs) {
|
||||
@@ -641,7 +640,7 @@ export let View = (function () {
|
||||
(typeof objClickedFunction === 'function') && objClickedFunction(o, xy);
|
||||
|
||||
if (o.isFootprint()) {
|
||||
if (typeof footprintClickedFunction === 'function') {
|
||||
if (typeof footprintClickedFunction === 'function' && (!view.lastClickedObject || !view.lastClickedObject.includes(o))) {
|
||||
footprintClickedFunction(o, xy);
|
||||
}
|
||||
}
|
||||
@@ -651,7 +650,6 @@ export let View = (function () {
|
||||
objs = Array.from(Object.values(objsByCats));
|
||||
view.selectObjects(objs);
|
||||
view.lastClickedObject = objs;
|
||||
|
||||
} else {
|
||||
// If there is a past clicked object
|
||||
if (view.lastClickedObject) {
|
||||
@@ -843,9 +841,6 @@ export let View = (function () {
|
||||
|
||||
if (wasDragging) {
|
||||
view.realDragging = false;
|
||||
|
||||
// call the positionChanged once more with a dragging = false
|
||||
view.throttledPositionChanged(false);
|
||||
}
|
||||
} // end of "if (view.dragging) ... "
|
||||
|
||||
@@ -1014,6 +1009,11 @@ export let View = (function () {
|
||||
view.updateObjectsLookup();
|
||||
}
|
||||
|
||||
/*if (!view.dragging || Utils.hasTouchScreen()) {
|
||||
// update location box
|
||||
view.updateLocation({mouseX: xymouse.x, mouseY: xymouse.y});
|
||||
}*/
|
||||
|
||||
if (!view.dragging && !view.moving && view.mode === View.PAN) {
|
||||
// call listener of 'mouseMove' event
|
||||
var onMouseMoveFunction = view.aladin.callbacksByEventName['mouseMove'];
|
||||
@@ -1127,7 +1127,7 @@ export let View = (function () {
|
||||
ALEvent.POSITION_CHANGED.dispatchedTo(view.aladin.aladinDiv, view.viewCenter);
|
||||
|
||||
// Apply position changed callback after the move
|
||||
view.throttledPositionChanged(true);
|
||||
view.throttledPositionChanged();
|
||||
}
|
||||
}); //// endof mousemove ////
|
||||
|
||||
@@ -1150,6 +1150,7 @@ export let View = (function () {
|
||||
view.zoom.stopAnimation();
|
||||
}, 100);
|
||||
|
||||
|
||||
const xymouse = Utils.relMouseCoords(e);
|
||||
view.xy = xymouse
|
||||
ALEvent.CANVAS_EVENT.dispatchedTo(view.aladinDiv, {
|
||||
@@ -1286,32 +1287,40 @@ export let View = (function () {
|
||||
/**
|
||||
* redraw the whole view
|
||||
*/
|
||||
View.prototype.redraw = function (timestamp) {
|
||||
View.prototype.redraw = function () {
|
||||
// request another frame
|
||||
|
||||
// Elapsed time since last loop
|
||||
const now = performance.now();
|
||||
const elapsedTime = now - timestamp;
|
||||
const elapsedTime = now - this.then;
|
||||
this.dt = elapsedTime;
|
||||
// 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)
|
||||
//if (this.dt > 10)
|
||||
// console.log(this.dt)
|
||||
// Drawing code
|
||||
//try {
|
||||
this.moving = this.wasm.update(elapsedTime);
|
||||
|
||||
// inertia run throttled position
|
||||
if (this.moving && this.aladin.callbacksByEventName && this.aladin.callbacksByEventName['positionChanged'] && this.wasm.isInerting()) {
|
||||
// run the trottled position
|
||||
this.throttledPositionChanged();
|
||||
}
|
||||
|
||||
this.moving = this.wasm.update(elapsedTime);
|
||||
|
||||
// inertia run throttled position
|
||||
if (this.moving && this.aladin.callbacksByEventName && this.aladin.callbacksByEventName['positionChanged'] && this.wasm.isInerting()) {
|
||||
// run the trottled position
|
||||
this.throttledPositionChanged(false);
|
||||
}
|
||||
////// 2. Draw catalogues////////
|
||||
const isViewRendering = this.wasm.isRendering();
|
||||
if (isViewRendering || this.needRedraw) {
|
||||
this.drawAllOverlays();
|
||||
}
|
||||
this.needRedraw = false;
|
||||
|
||||
|
||||
////// 2. Draw catalogues////////
|
||||
const isViewRendering = this.wasm.isRendering();
|
||||
if (isViewRendering || this.needRedraw) {
|
||||
this.drawAllOverlays();
|
||||
}
|
||||
this.needRedraw = false;
|
||||
|
||||
//this.then = now % View.FPS_INTERVAL;
|
||||
requestAnimFrame(this.redrawClbk);
|
||||
this.then = now;
|
||||
//this.then = now % View.FPS_INTERVAL;
|
||||
requestAnimFrame(this.redrawClbk);
|
||||
//}
|
||||
};
|
||||
|
||||
View.prototype.drawAllOverlays = function () {
|
||||
@@ -1432,10 +1441,6 @@ export let View = (function () {
|
||||
};
|
||||
|
||||
View.prototype.unselectObjects = function() {
|
||||
if (this.manualSelection) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.aladin.measurementTable.hide();
|
||||
|
||||
if (this.selection) {
|
||||
@@ -1455,13 +1460,9 @@ export let View = (function () {
|
||||
}
|
||||
|
||||
View.prototype.selectObjects = function(selection) {
|
||||
if (this.manualSelection) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unselect the previous selection
|
||||
this.unselectObjects();
|
||||
|
||||
|
||||
if (Array.isArray(selection)) {
|
||||
this.selection = selection;
|
||||
} else {
|
||||
@@ -2019,7 +2020,7 @@ export let View = (function () {
|
||||
var self = this;
|
||||
setTimeout(function () { self.refreshProgressiveCats(); }, 1000);
|
||||
// Apply position changed callback after the move
|
||||
self.throttledPositionChanged(false);
|
||||
self.throttledPositionChanged();
|
||||
|
||||
// hide the popup if it is open
|
||||
this.aladin.hidePopup();
|
||||
@@ -2046,7 +2047,7 @@ export let View = (function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
View.prototype.removeOverlays = function () {
|
||||
View.prototype.removeLayers = function () {
|
||||
this.catalogs = [];
|
||||
this.overlays = [];
|
||||
this.mocs = [];
|
||||
@@ -2062,11 +2063,6 @@ export let View = (function () {
|
||||
|
||||
View.prototype.removeOverlay = function (overlay) {
|
||||
let indexToDelete = this.allOverlayLayers.indexOf(overlay);
|
||||
if (indexToDelete === -1) {
|
||||
// overlay not found
|
||||
return;
|
||||
}
|
||||
|
||||
this.allOverlayLayers.splice(indexToDelete, 1);
|
||||
|
||||
if (overlay.type == 'catalog' || overlay.type == 'progressivecat') {
|
||||
@@ -2095,12 +2091,12 @@ export let View = (function () {
|
||||
};
|
||||
|
||||
View.prototype.removeOverlayByName = function (overlayName) {
|
||||
let overlay = this.allOverlayLayers.find(o => o.name === overlayName);
|
||||
if (!overlay) {
|
||||
console.error(`Overlay "${overlayName}" not found.`);
|
||||
let layer = this.allOverlayLayers.find(l => l.name === overlayName);
|
||||
if (!layer) {
|
||||
console.error(`Layer with name "${overlayName}" not found.`);
|
||||
return;
|
||||
}
|
||||
this.removeOverlay(overlay);
|
||||
this.removeOverlay(layer);
|
||||
};
|
||||
|
||||
View.prototype.add = function(overlay) {
|
||||
|
||||
@@ -580,8 +580,7 @@ export class OverlayStackBox extends Box {
|
||||
// Center the view around the new fits object
|
||||
self.aladin.gotoRaDec(ra, dec);
|
||||
self.aladin.setFoV(fov * 1.1);
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
//self.aladin.selectLayer(image.layer);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -591,31 +590,6 @@ export class OverlayStackBox extends Box {
|
||||
);
|
||||
},
|
||||
}),
|
||||
ContextMenu.webkitDir({
|
||||
label: "Load local HiPS",
|
||||
action(files) {
|
||||
let id = files[0].webkitRelativePath.split("/")[0];
|
||||
let name = id;
|
||||
|
||||
let hips = self.aladin.createImageSurvey(
|
||||
id,
|
||||
name,
|
||||
files,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
errorCallback: (e) => {
|
||||
aladin.addStatusBarMessage({
|
||||
duration: 2000,
|
||||
type: 'info',
|
||||
message: 'Could not add the local HiPS',
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
self.aladin.addNewImageLayer(hips);
|
||||
},
|
||||
}),
|
||||
],
|
||||
tooltip: {
|
||||
content: "Add a HiPS or an FITS image",
|
||||
@@ -794,7 +768,7 @@ export class OverlayStackBox extends Box {
|
||||
);
|
||||
layout = layout.concat(this._createSurveysList());
|
||||
|
||||
return Layout.vertical({ layout });
|
||||
return Layout.vertical({ layout, classList: ["content"] });
|
||||
}
|
||||
|
||||
_createOverlaysList() {
|
||||
|
||||
@@ -407,36 +407,4 @@ export class ContextMenu extends DOMElement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static webkitDir(itemOptions) {
|
||||
return {
|
||||
...itemOptions,
|
||||
label: {
|
||||
icon: {
|
||||
monochrome: true,
|
||||
tooltip: {content: 'Load a local file from your computer.<br \>Accept ' + itemOptions.accept + ' files'},
|
||||
url: uploadIconUrl,
|
||||
cssStyle: {
|
||||
cursor: 'help',
|
||||
}
|
||||
},
|
||||
content: itemOptions.label
|
||||
},
|
||||
action(e) {
|
||||
let webkitDirLoader = document.createElement('input');
|
||||
webkitDirLoader.type = 'file';
|
||||
webkitDirLoader.webkitdirectory = true;
|
||||
webkitDirLoader.multiple = true;
|
||||
|
||||
// Case: The user is loading a FITS file
|
||||
webkitDirLoader.addEventListener("change", (e) => {
|
||||
if (itemOptions.action) {
|
||||
itemOptions.action(e.target.files)
|
||||
}
|
||||
});
|
||||
|
||||
webkitDirLoader.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,8 +288,8 @@ export let Circle = (function() {
|
||||
// From StackOverflow: https://stackoverflow.com/questions/401847/circle-rectangle-collision-detection-intersection
|
||||
Circle.prototype.intersectsBBox = function(x, y, w, h) {
|
||||
const circleDistance = {
|
||||
x: Math.abs(this.center.x - x),
|
||||
y: Math.abs(this.center.y - y)
|
||||
x: abs(this.center.x - x),
|
||||
y: abs(this.center.y - y)
|
||||
};
|
||||
|
||||
if (circleDistance.x > (w/2 + this.radius)) { return false; }
|
||||
|
||||
@@ -464,51 +464,8 @@ export let Polyline = (function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline.prototype.intersectsBBox = function(x, y, w, h, view) {
|
||||
for (let i = 0; i < this.raDecArray.length - 1; i++) {
|
||||
let p1 = this.raDecArray[i];
|
||||
let p2 = this.raDecArray[i + 1];
|
||||
|
||||
let xy1 = view.aladin.world2pix(p1[0], p1[1]);
|
||||
let xy2 = view.aladin.world2pix(p2[0], p2[1]);
|
||||
|
||||
if (!xy1 || !xy2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
xy1 = {x: xy1[0], y: xy1[1]};
|
||||
xy2 = {x: xy2[0], y: xy2[1]};
|
||||
|
||||
// Check if line segment intersects with the bounding box
|
||||
if (this.lineIntersectsBox(xy1, xy2, x, y, w, h)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline.prototype.lineIntersectsBox = function(p1, p2, x, y, w, h) {
|
||||
// Check if line segment is completely outside the box
|
||||
if ((p1.x < x && p2.x < x) ||
|
||||
(p1.y < y && p2.y < y) ||
|
||||
(p1.x > x + w && p2.x > x + w) ||
|
||||
(p1.y > y + h && p2.y > y + h)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let m = (p2.y - p1.y) / (p2.x - p1.x); // Slope of the line
|
||||
let c = p1.y - m * p1.x; // y-intercept of the line
|
||||
|
||||
// Check if line intersects with the sides of the box
|
||||
if ((p1.y >= y && p1.y <= y + h) ||
|
||||
(p2.y >= y && p2.y <= y + h) ||
|
||||
(m * x + c >= y && m * x + c <= y + h) ||
|
||||
(m * (x + w) + c >= y && m * (x + w) + c <= y + h)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
Polyline.prototype.intersectsBBox = function(x, y, w, h) {
|
||||
// todo
|
||||
};
|
||||
|
||||
// static methods
|
||||
|
||||
@@ -10,7 +10,7 @@ import wasmPack from 'vite-plugin-wasm-pack';
|
||||
// To include and minify glsl into the bundle
|
||||
import glsl from 'vite-plugin-glsl';
|
||||
// To include css into the bundle
|
||||
//import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
|
||||
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
@@ -38,6 +38,7 @@ export default defineConfig({
|
||||
glsl({
|
||||
compress: true,
|
||||
}),
|
||||
cssInjectedByJsPlugin(),
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
|
||||
Reference in New Issue
Block a user