mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-26 04:42:40 -08:00
Compare commits
39 Commits
features/l
...
fill-polyg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a54ef4510a | ||
|
|
7947817694 | ||
|
|
79ecda33ca | ||
|
|
e622207145 | ||
|
|
43a8bf0e6e | ||
|
|
01aff09511 | ||
|
|
7a52a9f962 | ||
|
|
3bda0fcd75 | ||
|
|
d6e753ee85 | ||
|
|
98b0d0dff6 | ||
|
|
5364eaf124 | ||
|
|
c35c20d241 | ||
|
|
be619b3e8c | ||
|
|
62633d01bc | ||
|
|
bc1096fce3 | ||
|
|
7d5696228d | ||
|
|
08699a9bd5 | ||
|
|
fc6a09e373 | ||
|
|
a8a86a2952 | ||
|
|
cc958bfa2d | ||
|
|
6c4ddce6b0 | ||
|
|
c1b2bd24b9 | ||
|
|
46573a23da | ||
|
|
121f4345bc | ||
|
|
0665f2b65f | ||
|
|
a58fb1dd8a | ||
|
|
466472a1a7 | ||
|
|
540f4e33be | ||
|
|
0b92b6d1db | ||
|
|
06dcc126f9 | ||
|
|
04e552b7c3 | ||
|
|
1bee9c8b77 | ||
|
|
c77f2aeda8 | ||
|
|
57c1b8423d | ||
|
|
ebf2d06f31 | ||
|
|
5d0ec40612 | ||
|
|
82b2eb0423 | ||
|
|
2dc6f17c7d | ||
|
|
402e270015 |
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -32,4 +32,6 @@ jobs:
|
||||
run: |
|
||||
npm run build
|
||||
- name: "Run some tests"
|
||||
run: npm test
|
||||
run: |
|
||||
npm run test:build
|
||||
npm run test:unit
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,6 +8,6 @@ package-lock.json
|
||||
src/core/target/
|
||||
src/core/Cargo.lock
|
||||
|
||||
aladin-lite-3.1.0.tgz
|
||||
aladin-lite*.tgz
|
||||
|
||||
.vscode
|
||||
.vscode
|
||||
|
||||
@@ -6,7 +6,7 @@ Aladin Lite is a Web application which enables HiPS visualization from the brows
|
||||
|
||||
See [A&A 578, A114 (2015)](https://arxiv.org/abs/1505.02291) and [IVOA HiPS Recommendation](http://ivoa.net/documents/HiPS/index.html) for more details about the HiPS standard.
|
||||
|
||||
Aladin Lite is built to be easily embeddable in any web page. It powers astronomical portals like [ESASky](https://almascience.eso.org/asax/), [ESO Science Archive portal](http://archive.eso.org/scienceportal/) and [ALMA Portal](https://almascience.eso.org/asax/).
|
||||
Aladin Lite is built to be easily embeddable in any web page. It powers astronomical portals like [ESASky](https://sky.esa.int/), [ESO Science Archive portal](http://archive.eso.org/scienceportal/) and [ALMA Portal](https://almascience.eso.org/asax/).
|
||||
|
||||
More details on [Aladin Lite documentation page](http://aladin.u-strasbg.fr/AladinLite/doc/).
|
||||
|
||||
|
||||
@@ -6,11 +6,12 @@ ssh $USER_ALADIN@aladin 'sg hips -c "mkdir -p /home/matthieu.baumann/al-tmp && r
|
||||
# For compatibility with the docs, rename the UMD file into aladin.js
|
||||
scp dist/aladin.umd.cjs $USER_ALADIN@aladin:~/al-tmp/aladin.js
|
||||
# Copy the tgz
|
||||
cp aladin-l*.tgz aladin-lite.tgz
|
||||
mv aladin-l*.tgz aladin-lite.tgz
|
||||
scp aladin-lite.tgz $USER_ALADIN@aladin:~/al-tmp
|
||||
|
||||
ssh $USER_ALADIN@aladin "sg hips -c 'rm -rf /home/thomas.boch/AladinLite/www/api/v3/$DATEUPLOAD &&
|
||||
mkdir -p /home/thomas.boch/AladinLite/www/api/v3/$DATEUPLOAD &&
|
||||
cp /home/matthieu.baumann/al-tmp/* /home/thomas.boch/AladinLite/www/api/v3/$DATEUPLOAD &&
|
||||
rm -rf /home/thomas.boch/AladinLite/www/api/v3/latest &&
|
||||
ln -s /home/thomas.boch/AladinLite/www/api/v3/$DATEUPLOAD /home/thomas.boch/AladinLite/www/api/v3/latest'"
|
||||
ln -s /home/thomas.boch/AladinLite/www/api/v3/$DATEUPLOAD /home/thomas.boch/AladinLite/www/api/v3/latest &&
|
||||
ln -s /home/thomas.boch/AladinLite/www/api/v3/latest/aladin-lite.tgz /home/thomas.boch/AladinLite/www/api/v3/latest/AladinLiteAssets.tar.gz'"
|
||||
11709
examples/al-all-sky-polygons-projection-HPX.html
Normal file
11709
examples/al-all-sky-polygons-projection-HPX.html
Normal file
File diff suppressed because it is too large
Load Diff
11709
examples/al-all-sky-polygons-projection-MOL.html
Normal file
11709
examples/al-all-sky-polygons-projection-MOL.html
Normal file
File diff suppressed because it is too large
Load Diff
34
examples/al-big-circle.html
Normal file
34
examples/al-big-circle.html
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="aladin-lite-div" style="width: 500px; height: 400px"></div>
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
// Start up Aladin Lite
|
||||
aladin = A.aladin('#aladin-lite-div', {survey: "CDS/P/DSS2/color", target: 'M 1', fov: 0.2, showContextMenu: true, fullScreen: true});
|
||||
var overlay = A.graphicOverlay({color: '#ee2345', lineWidth: 3});
|
||||
aladin.addOverlay(overlay);
|
||||
overlay.add(A.circle(83.66067, 22.03081, 40.0, {color: 'cyan'})); // radius in degrees
|
||||
|
||||
aladin.on("footprintClicked", (footprint) => {
|
||||
console.log("footprint clicked catched", footprint)
|
||||
})
|
||||
aladin.on("objectClicked", (object) => {
|
||||
console.log("object clicked catched", object)
|
||||
})
|
||||
aladin.on("footprintHovered", (footprint) => {
|
||||
console.log("footprint hovered catched", footprint)
|
||||
})
|
||||
aladin.on("objectHoveredStop", (object) => {
|
||||
console.log("Object hovered stopped", object)
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
31
examples/al-cat-read-only.html
Normal file
31
examples/al-cat-read-only.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<!--<link rel="stylesheet" href="./layers.css" />-->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
|
||||
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {survey: 'P/DSS2/red', target: 'M50', fov: 0.7});
|
||||
|
||||
var cat1 = A.catalog({readOnly: true});
|
||||
aladin.addCatalog(cat1);
|
||||
cat1.addSources(A.source(105.69239256, -8.45235969));
|
||||
cat1.addSources(A.source(105.70779763, -8.31350997));
|
||||
cat1.addSources(A.source(105.74242906, -8.34776709));
|
||||
|
||||
var cat2 = A.catalog({readOnly: false});
|
||||
aladin.addCatalog(cat2);
|
||||
cat2.addSources(A.source(105.79239256, -8.45235969));
|
||||
cat2.addSources(A.source(105.90779763, -8.31350997));
|
||||
cat2.addSources(A.source(105.54242906, -8.34776709));
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -14,7 +14,7 @@
|
||||
<!--link rel="stylesheet" href="css/grids-responsive-min.css"-->
|
||||
<link rel="stylesheet" href="https://unpkg.com/purecss@2.0.3/build/buttons.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/purecss@2.0.3/build/buttons-core.css">
|
||||
|
||||
|
||||
<!--meta name="viewport" content="initial-scale=1.0, user-scalable=no"-->
|
||||
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
@@ -81,15 +81,15 @@
|
||||
<div id="coo_epoca">
|
||||
<a class="pure-button nav-button nav-goto" href="#">De Epoca</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="coo_legende">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Légende</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="coo_orion">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Orion</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="coo_magellan">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Magellan</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
@@ -97,7 +97,7 @@
|
||||
<div id="coo_halley">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Halley</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css"> .aladin-reticleColor { color: rgb(178, 50, 178); font-weight:bold;} </style>
|
||||
@@ -106,27 +106,27 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.aladin-zoomControl {
|
||||
top: 10% !important;
|
||||
left: unset !important;
|
||||
right: 4px !important;
|
||||
}
|
||||
|
||||
|
||||
.aladin-zoomControl a {
|
||||
font-size: 24px !important;
|
||||
padding: 22px !important;
|
||||
}
|
||||
|
||||
|
||||
#aladin{
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
|
||||
#explain {
|
||||
padding: 4px;
|
||||
top: 30%;
|
||||
@@ -134,51 +134,51 @@
|
||||
font-size: 11pt;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
|
||||
#explain tbody tr:nth-child(even) {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
|
||||
#explain tbody tr:nth-child(odd) {
|
||||
background-color: #ccdaeb;
|
||||
}
|
||||
|
||||
|
||||
#layersControlLeft {
|
||||
padding: 10px;
|
||||
right: unset;
|
||||
left: 4px;
|
||||
top: 20vh;
|
||||
}
|
||||
|
||||
|
||||
#layersCL2 {
|
||||
padding: 10px;
|
||||
right: unset;
|
||||
left: 4px;
|
||||
top: 90vh;
|
||||
}
|
||||
|
||||
|
||||
#layersControlRight {
|
||||
padding: 4px;
|
||||
left: unset;
|
||||
right: 4px;
|
||||
top: 25vh;
|
||||
}
|
||||
|
||||
|
||||
#layersControlLeft, #layersControlRight, #layersCL2 input {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
|
||||
.img-hips {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
|
||||
#opacity-slider {
|
||||
-webkit-appearance: none !important; /* Override default CSS styles */
|
||||
width: 220px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
|
||||
#opacity-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none !important; /* Override default look */
|
||||
appearance: none;
|
||||
@@ -187,18 +187,18 @@
|
||||
background: #4CAF50; /* Green background */
|
||||
cursor: pointer; /* Cursor on hover */
|
||||
}
|
||||
|
||||
|
||||
#opacity-slider::-moz-range-thumb {
|
||||
width: 25px; /* Set a specific slider handle width */
|
||||
height: 25px; /* Slider handle height */
|
||||
background: #4CAF50; /* Green background */
|
||||
cursor: pointer; /* Cursor on hover */
|
||||
}
|
||||
|
||||
|
||||
.aladin-box {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
|
||||
#calibCircle {
|
||||
position: fixed;
|
||||
border: 8px solid red;
|
||||
@@ -210,16 +210,16 @@
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
.pure-table {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
|
||||
.catcoro {
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.coro-star {
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -227,6 +227,8 @@
|
||||
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
import {Utils} from '../src/js/Utils';
|
||||
|
||||
A.init.then(() => {
|
||||
var hipsDir="http://alasky.u-strasbg.fr/CDS_P_Coronelli";
|
||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||
@@ -358,7 +360,7 @@
|
||||
});
|
||||
|
||||
// listen to click on objects
|
||||
aladin.on('objectClicked', function(source) {
|
||||
aladin.on('objectClicked', function(source, xyMouseCoords) {
|
||||
var html = '<table class="pure-table">';
|
||||
|
||||
if (curSelectedSource != null) {
|
||||
@@ -495,7 +497,7 @@
|
||||
deleteOverlayTimeout = undefined;
|
||||
}
|
||||
isDrawing = true;
|
||||
points.push([drawOverlayCanvas.relMouseCoords(e)]);
|
||||
points.push([Utils.relMouseCoords(drawOverlayCanvas.imageCanvas, e)]);
|
||||
});
|
||||
|
||||
|
||||
@@ -504,10 +506,10 @@
|
||||
e.preventDefault();
|
||||
|
||||
drawOverlayCtx.clearRect(0, 0, drawOverlayCtx.canvas.width, drawOverlayCtx.canvas.height);
|
||||
points[points.length-1].push(drawOverlayCanvas.relMouseCoords(e));
|
||||
points[points.length-1].push(Utils.relMouseCoords(drawOverlayCanvas.imageCanvas, e));
|
||||
|
||||
drawOverlayCtx.beginPath();
|
||||
|
||||
|
||||
for (var k=0; k<points.length; k++) {
|
||||
drawOverlayCtx.moveTo(points[k][0].x, points[k][0].y);
|
||||
for (var i = 1; i < points[k].length; i++) {
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
var msg;
|
||||
|
||||
// define function triggered when a source is hovered
|
||||
aladin.on('objectHovered', function(object) {
|
||||
aladin.on('objectHovered', function(object, xyMouseCoords) {
|
||||
if (object) {
|
||||
msg = 'You hovered object ' + object.data.name + ' located at ' + object.ra + ', ' + object.dec;
|
||||
msg = 'You hovered object ' + object.data.name + ' located at ' + object.ra + ', ' + object.dec + '; mouse coords - x: '
|
||||
+ xyMouseCoords.x + ', y: ' + xyMouseCoords.y;
|
||||
}
|
||||
else {
|
||||
msg = 'No object hovered';
|
||||
@@ -27,20 +28,22 @@
|
||||
$('#infoDiv').html(msg);
|
||||
});
|
||||
|
||||
aladin.on('objectHoveredStop', function(object) {
|
||||
aladin.on('objectHoveredStop', function(object, xyMouseCoords) {
|
||||
if (object) {
|
||||
msg = 'You stopped hove object ' + object.data.name + ' located at ' + object.ra + ', ' + object.dec;
|
||||
msg = 'You stopped hove object ' + object.data.name + ' located at ' + object.ra + ', ' + object.dec + '; mouse coords - x: '
|
||||
+ xyMouseCoords.x + ', y: ' + xyMouseCoords.y;
|
||||
}
|
||||
$('#infoDiv').html(msg);
|
||||
});
|
||||
|
||||
// define function triggered when an object is clicked
|
||||
var objClicked;
|
||||
aladin.on('objectClicked', function(object) {
|
||||
aladin.on('objectClicked', function(object, xyMouseCoords) {
|
||||
if (object) {
|
||||
objClicked = object;
|
||||
object.select();
|
||||
msg = 'You clicked object ' + object.data.name + ' located at ' + object.ra + ', ' + object.dec;
|
||||
object.select();
|
||||
msg = 'You clicked object ' + object.data.name + ' located at ' + object.ra + ', ' + object.dec + '; mouse coords - x: '
|
||||
+ xyMouseCoords.x + ', y: ' + xyMouseCoords.y;
|
||||
}
|
||||
else {
|
||||
objClicked.deselect();
|
||||
@@ -51,4 +54,4 @@
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
26
examples/al-fill-polygon.html
Normal file
26
examples/al-fill-polygon.html
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="aladin-lite-div" style="width: 500px; height: 400px"></div>
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
// Start up Aladin Lite
|
||||
aladin = A.aladin('#aladin-lite-div', {fov: 122, showContextMenu: true, fullScreen: true});
|
||||
var overlay = A.graphicOverlay({color: '#ee2345', lineWidth: 3});
|
||||
|
||||
aladin.addOverlay(overlay);
|
||||
overlay.addFootprints([A.polygon(
|
||||
[[264.375,-35.68533471265207], [258.75,-30.000000000000018], [264.375,-24.624318352164085], [270,-30.000000000000018]],
|
||||
{color: '#808080', fillColor: '#808080', opacity: .4, lineWidth: 1, fill: true})]);
|
||||
|
||||
aladin.gotoRaDec(264.375,-24.624318352164085);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -21,17 +21,17 @@
|
||||
]);
|
||||
overlay.add(A.circle(83.66067, 22.03081, 0.04, {color: 'cyan'})); // radius in degrees
|
||||
|
||||
aladin.on("footprintClicked", (footprint) => {
|
||||
console.log("footprint clicked catched", footprint)
|
||||
aladin.on("footprintClicked", (footprint, xyMouseCoords) => {
|
||||
console.log("footprint clicked catched: ", footprint, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
|
||||
})
|
||||
aladin.on("objectClicked", (object) => {
|
||||
console.log("object clicked catched", object)
|
||||
aladin.on("objectClicked", (object, xyMouseCoords) => {
|
||||
console.log("object clicked catched: ", object, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
|
||||
})
|
||||
aladin.on("footprintHovered", (footprint) => {
|
||||
console.log("footprint hovered catched", footprint)
|
||||
aladin.on("footprintHovered", (footprint, xyMouseCoords) => {
|
||||
console.log("footprint hovered catched: ", footprint, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
|
||||
})
|
||||
aladin.on("objectHoveredStop", (object) => {
|
||||
console.log("Object hovered stopped", object)
|
||||
aladin.on("objectHoveredStop", (object, xyMouseCoords) => {
|
||||
console.log("Object hovered stopped: ", object, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
|
||||
})
|
||||
|
||||
const cat = A.catalogFromVizieR('B/assocdata/obscore', 'M 1', 100, {onClick: 'showTable', limit: 1000});
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
});
|
||||
|
||||
// listen to click on objects
|
||||
aladin.on('objectClicked', function (source) {
|
||||
aladin.on('objectClicked', function (source, xyMouseCoords) {
|
||||
var html = '<table class="pure-table">';
|
||||
|
||||
if (curSelectedSource != null) {
|
||||
@@ -142,4 +142,4 @@
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
16
package.json
16
package.json
@@ -2,7 +2,7 @@
|
||||
"homepage": "https://aladin.u-strasbg.fr/",
|
||||
"name": "aladin-lite",
|
||||
"type": "module",
|
||||
"version": "3.1.0",
|
||||
"version": "3.2.0",
|
||||
"description": "An astronomical HiPS visualizer in the browser",
|
||||
"author": "Thomas Boch and Matthieu Baumann",
|
||||
"license": "GPL-3",
|
||||
@@ -33,22 +33,26 @@
|
||||
],
|
||||
"scripts": {
|
||||
"wasm": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2",
|
||||
"predeploy": "npm run build && npm pack",
|
||||
"deploy": "./deploy-dbg.sh",
|
||||
"predeploy": "npm run build && rm -rf aladin-lite.tgz && npm pack",
|
||||
"deploy": "./deploy.sh",
|
||||
"build": "npm run wasm && vite build && cp examples/index.html dist/index.html",
|
||||
"dev": "npm run build && vite",
|
||||
"serve": "npm run dev",
|
||||
"preview": "vite preview",
|
||||
"test": "cd src/core && cargo test --release --features webgl2"
|
||||
"test:build": "cd src/core && cargo test --release --features webgl2",
|
||||
"test:unit": "vitest run"
|
||||
},
|
||||
"devDependencies": {
|
||||
"npm": "^8.19.2",
|
||||
"happy-dom": "^8.9.0",
|
||||
"npm": "^9.8.1",
|
||||
"typescript": "^5.0.4",
|
||||
"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.3.1",
|
||||
"vite-plugin-wasm": "^3.2.2",
|
||||
"vite-plugin-wasm-pack": "^0.1.12"
|
||||
"vite-plugin-wasm-pack": "^0.1.12",
|
||||
"vitest": "^0.32.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"autocompleter": "^6.1.3",
|
||||
|
||||
@@ -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.1.1"
|
||||
version = "3.2.0"
|
||||
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::{
|
||||
tile_fetcher::TileFetcherQueue,
|
||||
time::DeltaTime,
|
||||
};
|
||||
use al_core::{info, inforec, log};
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
@@ -601,7 +602,6 @@ impl App {
|
||||
|
||||
let is_tile_root = tile.cell().depth() == delta_depth;
|
||||
let _depth = tile.cell().depth();
|
||||
//al_core::info!("is root tile", depth, is_tile_root);
|
||||
// do not perform tex_sub costly GPU calls while the camera is zooming
|
||||
if is_tile_root || included_or_near_coverage {
|
||||
let is_missing = tile.missing();
|
||||
@@ -1258,6 +1258,7 @@ impl App {
|
||||
|
||||
pub(crate) fn resize(&mut self, width: f32, height: f32) {
|
||||
self.camera.set_screen_size(width, height, &self.projection);
|
||||
|
||||
self.camera
|
||||
.set_aperture(self.camera.get_aperture(), &self.projection);
|
||||
// resize the view fbo
|
||||
|
||||
@@ -10,7 +10,7 @@ use super::{fov::FieldOfView, view_hpx_cells::ViewHpxCells};
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
use crate::healpix::coverage::HEALPixCoverage;
|
||||
use crate::math::{projection::coo_space::XYZWModel, projection::domain::sdf::ProjDef};
|
||||
|
||||
use al_core::{info, inforec, log};
|
||||
|
||||
use cgmath::{Matrix4, Vector2};
|
||||
pub struct CameraViewPort {
|
||||
@@ -265,14 +265,14 @@ impl CameraViewPort {
|
||||
.unwrap_abort();
|
||||
|
||||
// grid canvas
|
||||
let document = web_sys::window().unwrap_abort().document().unwrap_abort();
|
||||
/*let document = web_sys::window().unwrap_abort().document().unwrap_abort();
|
||||
let grid_canvas = document
|
||||
// Inside it, retrieve the canvas
|
||||
.get_elements_by_class_name("aladin-gridCanvas")
|
||||
.get_with_index(0)
|
||||
.unwrap_abort()
|
||||
.dyn_into::<web_sys::HtmlCanvasElement>()
|
||||
.unwrap_abort();
|
||||
.unwrap_abort();*/
|
||||
|
||||
canvas
|
||||
.style()
|
||||
@@ -282,19 +282,19 @@ impl CameraViewPort {
|
||||
.style()
|
||||
.set_property("height", &format!("{}px", height))
|
||||
.unwrap_abort();
|
||||
grid_canvas
|
||||
/*grid_canvas
|
||||
.style()
|
||||
.set_property("width", &format!("{}px", width))
|
||||
.unwrap_abort();
|
||||
grid_canvas
|
||||
.style()
|
||||
.set_property("height", &format!("{}px", height))
|
||||
.unwrap_abort();
|
||||
.unwrap_abort();*/
|
||||
|
||||
canvas.set_width(self.width as u32);
|
||||
canvas.set_height(self.height as u32);
|
||||
grid_canvas.set_width(self.width as u32);
|
||||
grid_canvas.set_height(self.height as u32);
|
||||
//grid_canvas.set_width(self.width as u32);
|
||||
//grid_canvas.set_height(self.height as u32);
|
||||
|
||||
// Once the canvas size is changed, we have to set the viewport as well
|
||||
self.gl
|
||||
@@ -306,7 +306,6 @@ impl CameraViewPort {
|
||||
self.height = (height as f32) * self.dpi;
|
||||
|
||||
self.aspect = width / height;
|
||||
|
||||
// Compute the new clip zoom factor
|
||||
self.compute_ndc_to_clip_factor(projection);
|
||||
|
||||
@@ -316,11 +315,13 @@ impl CameraViewPort {
|
||||
&self.w2m,
|
||||
projection,
|
||||
);
|
||||
|
||||
let proj_area = projection.get_area();
|
||||
self.is_allsky = !proj_area.is_in(&math::projection::ndc_to_clip_space(
|
||||
&Vector2::new(-1.0, -1.0),
|
||||
self,
|
||||
));
|
||||
|
||||
// Update the size of the canvas
|
||||
self.set_canvas_size(width, height);
|
||||
// Once it is done, recompute the scissor
|
||||
@@ -404,6 +405,7 @@ impl CameraViewPort {
|
||||
|
||||
self.fov
|
||||
.set_aperture(&self.ndc_to_clip, self.clip_zoom_factor, &self.w2m, proj);
|
||||
|
||||
let proj_area = proj.get_area();
|
||||
self.is_allsky = !proj_area.is_in(&math::projection::ndc_to_clip_space(
|
||||
&Vector2::new(-1.0, -1.0),
|
||||
|
||||
@@ -14,8 +14,6 @@ use crate::renderable::Renderer;
|
||||
use crate::ProjectionType;
|
||||
use al_api::color::ColorRGBA;
|
||||
|
||||
|
||||
|
||||
use al_api::grid::GridCfg;
|
||||
|
||||
use crate::grid::label::Label;
|
||||
@@ -231,7 +229,7 @@ impl ProjetedGrid {
|
||||
rot,
|
||||
} in labels
|
||||
{
|
||||
let position = position.cast::<f32>().unwrap_abort() * dpi;
|
||||
let position = position.cast::<f32>().unwrap_abort();
|
||||
self.text_renderer
|
||||
.add_label(&content, &position, cgmath::Rad(*rot as f32))?;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
use web_sys::CanvasRenderingContext2d;
|
||||
use super::Renderer;
|
||||
use web_sys::CanvasRenderingContext2d;
|
||||
|
||||
pub struct TextRenderManager {
|
||||
// The text canvas
|
||||
canvas: HtmlCanvasElement,
|
||||
ctx: CanvasRenderingContext2d,
|
||||
color: JsValue,
|
||||
font_size: u32,
|
||||
font_size: u32,
|
||||
}
|
||||
|
||||
use cgmath::{Rad, Vector2};
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
use crate::camera::CameraViewPort;
|
||||
use al_api::color::{ColorRGBA, ColorRGB};
|
||||
use web_sys::{HtmlCanvasElement};
|
||||
|
||||
use al_api::color::{ColorRGB, ColorRGBA};
|
||||
use web_sys::HtmlCanvasElement;
|
||||
|
||||
use crate::Abort;
|
||||
use wasm_bindgen::JsCast;
|
||||
@@ -34,10 +33,11 @@ impl TextRenderManager {
|
||||
.get_context("2d")
|
||||
.unwrap_abort()
|
||||
.unwrap_abort()
|
||||
.dyn_into::<web_sys::CanvasRenderingContext2d>().unwrap_abort();
|
||||
|
||||
.dyn_into::<web_sys::CanvasRenderingContext2d>()
|
||||
.unwrap_abort();
|
||||
|
||||
let color = JsValue::from_str("#00ff00");
|
||||
let font_size = 30;
|
||||
let font_size = 15;
|
||||
Ok(Self {
|
||||
font_size,
|
||||
color,
|
||||
@@ -47,7 +47,11 @@ impl TextRenderManager {
|
||||
}
|
||||
|
||||
pub fn set_color(&mut self, color: &ColorRGB) {
|
||||
let hex = al_api::color::Color::rgbToHex((color.r * 255.0) as u8, (color.g * 255.0) as u8, (color.b * 255.0) as u8);
|
||||
let hex = al_api::color::Color::rgbToHex(
|
||||
(color.r * 255.0) as u8,
|
||||
(color.g * 255.0) as u8,
|
||||
(color.b * 255.0) as u8,
|
||||
);
|
||||
self.color = JsValue::from_str(&hex);
|
||||
}
|
||||
|
||||
@@ -60,9 +64,10 @@ impl TextRenderManager {
|
||||
text: &str,
|
||||
screen_pos: &Vector2<f32>,
|
||||
angle: A,
|
||||
) -> Result<(), JsValue>{
|
||||
) -> Result<(), JsValue> {
|
||||
self.ctx.save();
|
||||
self.ctx.translate(screen_pos.x as f64, screen_pos.y as f64)?;
|
||||
self.ctx
|
||||
.translate(screen_pos.x as f64, screen_pos.y as f64)?;
|
||||
|
||||
let rot: Rad<f32> = angle.into();
|
||||
self.ctx.rotate(rot.0 as f64)?;
|
||||
@@ -71,31 +76,44 @@ impl TextRenderManager {
|
||||
self.ctx.fill_text(text, 0.0, 0.0)?;
|
||||
|
||||
self.ctx.restore();
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, _camera: &CameraViewPort, _color: &ColorRGBA, _scale: f32) -> Result<(), JsValue> {
|
||||
pub fn draw(
|
||||
&mut self,
|
||||
_camera: &CameraViewPort,
|
||||
_color: &ColorRGBA,
|
||||
_scale: f32,
|
||||
) -> Result<(), JsValue> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear_text_canvas(&mut self) {
|
||||
self.ctx.clear_rect(0_f64, 0_f64, self.canvas.width() as f64, self.canvas.height() as f64);
|
||||
self.ctx.clear_rect(
|
||||
0_f64,
|
||||
0_f64,
|
||||
self.canvas.width() as f64,
|
||||
self.canvas.height() as f64,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for TextRenderManager {
|
||||
fn begin(&mut self) {
|
||||
self.ctx = self.canvas
|
||||
self.ctx = self
|
||||
.canvas
|
||||
.get_context("2d")
|
||||
.unwrap_abort()
|
||||
.unwrap_abort()
|
||||
.dyn_into::<web_sys::CanvasRenderingContext2d>().unwrap_abort();
|
||||
.dyn_into::<web_sys::CanvasRenderingContext2d>()
|
||||
.unwrap_abort();
|
||||
|
||||
self.clear_text_canvas();
|
||||
|
||||
// reset the font and color
|
||||
self.ctx.set_font(&format!("{}px verdana, sans-serif", self.font_size));
|
||||
self.ctx
|
||||
.set_font(&format!("{}px verdana, sans-serif", self.font_size));
|
||||
self.ctx.set_fill_style(&self.color);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { View } from "./View.js";
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { Overlay } from "./Overlay.js";
|
||||
import { Logger } from "./Logger.js";
|
||||
import { ProgressiveCat } from "./ProgressiveCat.js";
|
||||
@@ -580,10 +580,10 @@ export let Aladin = (function () {
|
||||
}
|
||||
|
||||
// Delay the fixLayoutDimensions layout for firefox
|
||||
setTimeout(function () {
|
||||
/*setTimeout(function () {
|
||||
self.view.fixLayoutDimensions();
|
||||
}, 1000);
|
||||
|
||||
*/
|
||||
// force call to zoomChanged callback
|
||||
var fovChangedFn = self.callbacksByEventName['zoomChanged'];
|
||||
(typeof fovChangedFn === 'function') && fovChangedFn(self.view.fov);
|
||||
@@ -594,34 +594,34 @@ export let Aladin = (function () {
|
||||
|
||||
Aladin.prototype.getOptionsFromQueryString = function () {
|
||||
var options = {};
|
||||
var requestedTarget = $.urlParam('target');
|
||||
var requestedTarget = Utils.urlParam('target');
|
||||
if (requestedTarget) {
|
||||
options.target = requestedTarget;
|
||||
}
|
||||
var requestedFrame = $.urlParam('frame');
|
||||
var requestedFrame = Utils.urlParam('frame');
|
||||
if (requestedFrame && CooFrameEnum[requestedFrame]) {
|
||||
options.frame = requestedFrame;
|
||||
}
|
||||
var requestedSurveyId = $.urlParam('survey');
|
||||
var requestedSurveyId = Utils.urlParam('survey');
|
||||
if (requestedSurveyId && ImageSurvey.getSurveyInfoFromId(requestedSurveyId)) {
|
||||
options.survey = requestedSurveyId;
|
||||
}
|
||||
var requestedZoom = $.urlParam('zoom');
|
||||
var requestedZoom = Utils.urlParam('zoom');
|
||||
if (requestedZoom && requestedZoom > 0 && requestedZoom < 180) {
|
||||
options.zoom = requestedZoom;
|
||||
}
|
||||
|
||||
var requestedShowreticle = $.urlParam('showReticle');
|
||||
var requestedShowreticle = Utils.urlParam('showReticle');
|
||||
if (requestedShowreticle) {
|
||||
options.showReticle = requestedShowreticle.toLowerCase() == 'true';
|
||||
}
|
||||
|
||||
var requestedCooFrame = $.urlParam('cooFrame');
|
||||
var requestedCooFrame = Utils.urlParam('cooFrame');
|
||||
if (requestedCooFrame) {
|
||||
options.cooFrame = requestedCooFrame;
|
||||
}
|
||||
|
||||
var requestedFullscreen = $.urlParam('fullScreen');
|
||||
var requestedFullscreen = Utils.urlParam('fullScreen');
|
||||
if (requestedFullscreen !== undefined) {
|
||||
options.fullScreen = requestedFullscreen;
|
||||
}
|
||||
@@ -1786,4 +1786,4 @@ Aladin.prototype.displayJPG = Aladin.prototype.displayPNG = function (url, optio
|
||||
Aladin.prototype.setReduceDeformations = function (reduce) {
|
||||
this.reduceDeformations = reduce;
|
||||
this.view.requestRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,16 @@
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
*
|
||||
* File Catalog
|
||||
*
|
||||
*
|
||||
* Author: Thomas Boch[CDS]
|
||||
*
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Source } from "./Source.js"
|
||||
import { Color } from "./Color.js"
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { Coo } from "./libs/astro/coo.js";
|
||||
import { VOTable } from "./vo/VOTable.js";
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
@@ -57,6 +57,7 @@ export let Catalog = (function() {
|
||||
this.shape = options.shape || "square";
|
||||
this.maxNbSources = options.limit || undefined;
|
||||
this.onClick = options.onClick || undefined;
|
||||
this.readOnly = options.readOnly || false;
|
||||
|
||||
this.raField = options.raField || undefined; // ID or name of the field holding RA
|
||||
this.decField = options.decField || undefined; // ID or name of the field holding dec
|
||||
@@ -82,10 +83,10 @@ export let Catalog = (function() {
|
||||
this.displayLabel = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.selectionColor = '#00ff00';
|
||||
|
||||
// create this.cacheCanvas
|
||||
|
||||
// create this.cacheCanvas
|
||||
// cacheCanvas permet de ne créer le path de la source qu'une fois, et de le réutiliser (cf. http://simonsarris.com/blog/427-increasing-performance-by-caching-paths-on-canvas)
|
||||
this.updateShape(options);
|
||||
|
||||
@@ -104,7 +105,7 @@ export let Catalog = (function() {
|
||||
|
||||
this.isShowing = true;
|
||||
};
|
||||
|
||||
|
||||
Catalog.createShape = function(shapeName, color, sourceSize) {
|
||||
if (shapeName instanceof Image || shapeName instanceof HTMLCanvasElement) { // in this case, the shape is already created
|
||||
return shapeName;
|
||||
@@ -119,7 +120,7 @@ export let Catalog = (function() {
|
||||
ctx.moveTo(sourceSize/2., 0);
|
||||
ctx.lineTo(sourceSize/2., sourceSize);
|
||||
ctx.stroke();
|
||||
|
||||
|
||||
ctx.moveTo(0, sourceSize/2.);
|
||||
ctx.lineTo(sourceSize, sourceSize/2.);
|
||||
ctx.stroke();
|
||||
@@ -128,7 +129,7 @@ export let Catalog = (function() {
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(sourceSize-1, sourceSize-1);
|
||||
ctx.stroke();
|
||||
|
||||
|
||||
ctx.moveTo(sourceSize-1, 0);
|
||||
ctx.lineTo(0, sourceSize-1);
|
||||
ctx.stroke();
|
||||
@@ -160,10 +161,10 @@ export let Catalog = (function() {
|
||||
ctx.lineTo(1, 1);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
|
||||
return c;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// find RA, Dec fields among the given fields
|
||||
//
|
||||
@@ -182,7 +183,7 @@ export let Catalog = (function() {
|
||||
if (Utils.isInt(raField) && raField<fields.length) { // raField can be given as an index
|
||||
raFieldIdx = raField;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( (field.ID && field.ID===raField) || (field.name && field.name===raField)) {
|
||||
raFieldIdx = l;
|
||||
break;
|
||||
@@ -195,7 +196,7 @@ export let Catalog = (function() {
|
||||
if (Utils.isInt(decField) && decField<fields.length) { // decField can be given as an index
|
||||
decFieldIdx = decField;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( (field.ID && field.ID===decField) || (field.name && field.name===decField)) {
|
||||
decFieldIdx = l;
|
||||
break;
|
||||
@@ -218,7 +219,7 @@ export let Catalog = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( ! decFieldIdx) {
|
||||
if (field.ucd) {
|
||||
var ucd = $.trim(field.ucd.toLowerCase());
|
||||
@@ -236,7 +237,7 @@ export let Catalog = (function() {
|
||||
var field = fields[l];
|
||||
var name = field.name || field.ID || '';
|
||||
name = name.toLowerCase();
|
||||
|
||||
|
||||
if ( ! raFieldIdx) {
|
||||
if (name.indexOf('ra')==0 || name.indexOf('_ra')==0 || name.indexOf('ra(icrs)')==0 || name.indexOf('_ra')==0 || name.indexOf('alpha')==0) {
|
||||
raFieldIdx = l;
|
||||
@@ -250,7 +251,7 @@ export let Catalog = (function() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,8 +263,8 @@ export let Catalog = (function() {
|
||||
|
||||
return [raFieldIdx, decFieldIdx];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Catalog.parseFields = function(fields, raField, decField) {
|
||||
// This votable is not an obscore one
|
||||
let [raFieldIdx, decFieldIdx] = findRADecFields(fields, raField, decField);
|
||||
@@ -379,13 +380,13 @@ export let Catalog = (function() {
|
||||
|
||||
this.selectSize = this.sourceSize + 2;
|
||||
|
||||
this.cacheCanvas = Catalog.createShape(this.shape, this.color, this.sourceSize);
|
||||
this.cacheCanvas = Catalog.createShape(this.shape, this.color, this.sourceSize);
|
||||
this.cacheSelectCanvas = Catalog.createShape(this.shape, this.selectionColor, this.selectSize);
|
||||
this.cacheHoverCanvas = Catalog.createShape(this.shape, this.hoverColor, this.sourceSize);
|
||||
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
|
||||
// API
|
||||
Catalog.prototype.addSources = function(sources) {
|
||||
// make sure we have an array and not an individual source
|
||||
@@ -507,7 +508,7 @@ export let Catalog = (function() {
|
||||
if (! this.sources) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (var k=0; k<this.sources.length; k++) {
|
||||
this.sources[k].select();
|
||||
}
|
||||
@@ -702,7 +703,7 @@ export let Catalog = (function() {
|
||||
Catalog.prototype.reportChange = function() {
|
||||
this.view && this.view.requestRedraw();
|
||||
};
|
||||
|
||||
|
||||
Catalog.prototype.show = function() {
|
||||
if (this.isShowing) {
|
||||
return;
|
||||
@@ -715,7 +716,7 @@ export let Catalog = (function() {
|
||||
|
||||
this.reportChange();
|
||||
};
|
||||
|
||||
|
||||
Catalog.prototype.hide = function() {
|
||||
if (! this.isShowing) {
|
||||
return;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { AladinUtils } from "./AladinUtils.js";
|
||||
import { Overlay } from "./Overlay.js";
|
||||
|
||||
@@ -163,31 +163,48 @@ export let Circle = (function() {
|
||||
x: centerXyview[0],
|
||||
y: centerXyview[1],
|
||||
};
|
||||
// compute value of radius in pixels in current projection
|
||||
var ra = this.centerRaDec[0];
|
||||
var dec = this.centerRaDec[1] + (ra>0 ? - this.radiusDegrees : this.radiusDegrees);
|
||||
|
||||
// First check, the point in the circle is defined
|
||||
let circlePtXyView = AladinUtils.radecToViewXy(ra, dec, view);
|
||||
if (!circlePtXyView) {
|
||||
// the circle border goes out of the projection
|
||||
// we do not draw it
|
||||
return;
|
||||
let hidden = true;
|
||||
|
||||
var ra, dec, vertOnCircle, dx, dy;
|
||||
if (view.fov > 90) {
|
||||
this.radius = Number.POSITIVE_INFINITY;
|
||||
|
||||
// Project 4 points lying on the circle and take the minimal dist with the center as radius
|
||||
[[-1, 0], [1, 0], [0, -1], [0, 1]].forEach(([cardDirRa, cardDirDec]) => {
|
||||
ra = this.centerRaDec[0] + cardDirRa * this.radiusDegrees;
|
||||
dec = this.centerRaDec[1] + cardDirDec * this.radiusDegrees;
|
||||
|
||||
vertOnCircle = AladinUtils.radecToViewXy(ra, dec, view);
|
||||
|
||||
if (vertOnCircle) {
|
||||
dx = vertOnCircle[0] - this.center.x;
|
||||
dy = vertOnCircle[1] - this.center.y;
|
||||
|
||||
this.radius = Math.min(Math.sqrt(dx*dx + dy*dy), this.radius);
|
||||
|
||||
hidden = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ra = this.centerRaDec[0] + this.radiusDegrees;
|
||||
dec = this.centerRaDec[1];
|
||||
|
||||
vertOnCircle = AladinUtils.radecToViewXy(ra, dec, view);
|
||||
|
||||
if (vertOnCircle) {
|
||||
dx = vertOnCircle[0] - this.center.x;
|
||||
dy = vertOnCircle[1] - this.center.y;
|
||||
|
||||
this.radius = Math.sqrt(dx*dx + dy*dy);
|
||||
hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Second check, the radius is not too big in the clipping space
|
||||
let [x1c, y1c] = AladinUtils.viewXyToClipXy(this.center.x, this.center.y, view);
|
||||
let [x2c, y2c] = AladinUtils.viewXyToClipXy(circlePtXyView[0], circlePtXyView[1], view);
|
||||
|
||||
let mag2 = (x1c - x2c)*(x1c - x2c) + (y1c - y2c)*(y1c - y2c);
|
||||
if (mag2 > 0.2) {
|
||||
if (hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Then we can draw
|
||||
var dx = circlePtXyView[0] - this.center.x;
|
||||
var dy = circlePtXyView[1] - this.center.y;
|
||||
this.radius = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
var baseColor = this.color;
|
||||
if (! baseColor && this.overlay) {
|
||||
|
||||
1
src/js/Constants.ts
Normal file
1
src/js/Constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const JSONP_PROXY = "https://alaskybis.cds.unistra.fr/cgi/JSONProxy";
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { AladinUtils } from "./AladinUtils.js";
|
||||
import { Overlay } from "./Overlay.js";
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { AladinUtils } from './AladinUtils.js';
|
||||
import { Utils } from './Utils.js';
|
||||
import { Utils } from './Utils';
|
||||
|
||||
export let Footprint= (function() {
|
||||
// constructor
|
||||
@@ -46,13 +46,15 @@ export let Footprint= (function() {
|
||||
this.shapes = shapes;
|
||||
|
||||
this.isShowing = true;
|
||||
|
||||
this.overlay = null;
|
||||
};
|
||||
|
||||
Footprint.prototype.setCatalog = function(catalog) {
|
||||
if (this.source) {
|
||||
this.source.setCatalog(catalog);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Footprint.prototype.show = function() {
|
||||
if (this.isShowing) {
|
||||
@@ -91,7 +93,7 @@ export let Footprint= (function() {
|
||||
Footprint.prototype.setSelectionColor = function(color) {
|
||||
this.shapes.forEach((shape) => shape.setSelectionColor(color))
|
||||
};
|
||||
|
||||
|
||||
Footprint.prototype.isFootprint = function() {
|
||||
return true;
|
||||
}
|
||||
@@ -125,6 +127,10 @@ export let Footprint= (function() {
|
||||
return this.source && this.source.catalog;
|
||||
};
|
||||
|
||||
Footprint.prototype.setOverlay = function(overlay) {
|
||||
this.overlay = overlay;
|
||||
};
|
||||
|
||||
Footprint.prototype.intersectsBBox = function(x, y, w, h, view) {
|
||||
if(this.source) {
|
||||
let s = this.source;
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
|
||||
import { SimbadPointer } from "./SimbadPointer.js";
|
||||
import { PlanetaryFeaturesPointer } from "./PlanetaryFeaturesPointer.js";
|
||||
import { Utils } from './Utils';
|
||||
|
||||
// allow to call either Simbad or Planetary features Pointers
|
||||
export let GenericPointer = (function (view, e) {
|
||||
const xymouse = view.imageCanvas.relMouseCoords(e);
|
||||
const xymouse = Utils.relMouseCoords(view.imageCanvas, e);
|
||||
let radec = view.wasm.screenToWorld(xymouse.x, xymouse.y);
|
||||
if (radec) {
|
||||
// sky case
|
||||
@@ -29,4 +30,4 @@ export let GenericPointer = (function (view, e) {
|
||||
console.log("The location you clicked on is out of the view.");
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import $ from 'jquery';
|
||||
|
||||
export let HiPSDefinition = (function() {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* Authors: Thomas Boch & Matthieu Baumann [CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { HiPSDefinition } from "./HiPSDefinition.js";
|
||||
import { MocServer } from "./MocServer.js";
|
||||
|
||||
@@ -202,4 +202,4 @@ HiPSProperties.getFasterMirrorUrl = function (metadata) {
|
||||
}
|
||||
})
|
||||
.then((url) => Utils.fixURLForHTTPS(url));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
import { ColorCfg } from "./ColorCfg.js";
|
||||
import { ImageLayer } from "./ImageLayer.js";
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
|
||||
export let ImageFITS = (function () {
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* Authors: Thomas Boch & Matthieu Baumann [CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
import { CooFrameEnum } from "./CooFrameEnum.js"
|
||||
import { ColorCfg } from "./ColorCfg.js";
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { Aladin } from "./Aladin.js";
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { Color } from "./Color.js";
|
||||
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
|
||||
export let MOC = (function() {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils } from './Utils.js';
|
||||
import { Utils } from './Utils';
|
||||
import A from "./A.js";
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
* Author: Thomas Boch [CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { AladinUtils } from "./AladinUtils.js";
|
||||
|
||||
export let PlanetaryFeaturesPointer = (function() {
|
||||
|
||||
@@ -35,17 +35,54 @@
|
||||
|
||||
import { AladinUtils } from './AladinUtils.js';
|
||||
import { Line } from './Line.js';
|
||||
import { Utils } from './Utils.js';
|
||||
import { Utils } from './Utils';
|
||||
import { Overlay } from "./Overlay.js";
|
||||
import { ProjectionEnum, projectionNames } from "./ProjectionEnum.js";
|
||||
|
||||
|
||||
export let Polyline= (function() {
|
||||
function _calculateMag2ForNoSinProjections(line, view) {
|
||||
// check if the line is too big (in the clip space) to be drawn
|
||||
const [x1, y1] = AladinUtils.viewXyToClipXy(line.x1, line.y1, view);
|
||||
const [x2, y2] = AladinUtils.viewXyToClipXy(line.x2, line.y2, view);
|
||||
|
||||
const mag2 = (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2);
|
||||
return mag2;
|
||||
}
|
||||
|
||||
function _isAcrossCollignonZoneForHpxProjection(line, view) {
|
||||
const [x1, y1] = AladinUtils.viewXyToClipXy(line.x1, line.y1, view);
|
||||
const [x2, y2] = AladinUtils.viewXyToClipXy(line.x2, line.y2, view);
|
||||
|
||||
// x, y, between -1 and 1
|
||||
let triIdxCollignionZone = function(x, y) {
|
||||
let xZone = Math.floor((x * 0.5 + 0.5) * 4.0);
|
||||
return xZone + 4 * (y > 0.0);
|
||||
};
|
||||
|
||||
let isInCollignionZone = function(x, y) {
|
||||
return Math.abs(y) > 0.5;
|
||||
};
|
||||
|
||||
if (isInCollignionZone(x1, y1) && isInCollignionZone(x2, y2)) {
|
||||
if (triIdxCollignionZone(x1, y1) === triIdxCollignionZone(x2, y2)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// constructor
|
||||
let Polyline = function(radecArray, options) {
|
||||
options = options || {};
|
||||
this.color = options['color'] || undefined;
|
||||
this.lineWidth = options["lineWidth"] || 2;
|
||||
this.fill = options['fill'] || false;
|
||||
this.fillColor = options['fillColor'] || undefined;
|
||||
this.opacity = options['opacity'] || undefined;
|
||||
this.lineWidth = options["lineWidth"] || undefined;
|
||||
|
||||
if (options["closed"]) {
|
||||
this.closed = options["closed"];
|
||||
@@ -138,7 +175,7 @@ export let Polyline= (function() {
|
||||
this.overlay.reportChange();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Polyline.prototype.isFootprint = function() {
|
||||
// The polyline is a footprint if it describes a polygon (i.e. a closed polyline)
|
||||
return this.closed;
|
||||
@@ -163,6 +200,10 @@ export let Polyline= (function() {
|
||||
baseColor = '#ff0000';
|
||||
}
|
||||
|
||||
if (!this.lineWidth) {
|
||||
this.lineWidth = this.overlay.lineWidth || 2;
|
||||
}
|
||||
|
||||
if (this.isSelected) {
|
||||
if(this.selectionColor) {
|
||||
ctx.strokeStyle = this.selectionColor;
|
||||
@@ -204,69 +245,116 @@ export let Polyline= (function() {
|
||||
}
|
||||
|
||||
let drawLine;
|
||||
|
||||
let fillPoly;
|
||||
|
||||
if (view.projection === ProjectionEnum.SIN) {
|
||||
drawLine = (v0, v1) => {
|
||||
const line = new Line(v0.x, v0.y, v1.x, v1.y);
|
||||
|
||||
|
||||
if (line.isInsideView(view.width, view.height)) {
|
||||
line.draw(ctx);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
|
||||
if (this.closed && this.fill) {
|
||||
fillPoly = (v0, v1, index) => {
|
||||
const line = new Line(v0.x, v0.y, v1.x, v1.y);
|
||||
if (index === 0) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(line.x1, line.y1);
|
||||
} else {
|
||||
ctx.lineTo(line.x1, line.y1);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
} else if (view.projection === ProjectionEnum.HPX) {
|
||||
drawLine = (v0, v1) => {
|
||||
const line = new Line(v0.x, v0.y, v1.x, v1.y);
|
||||
|
||||
|
||||
if (_isAcrossCollignonZoneForHpxProjection(line, view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.isInsideView(view.width, view.height)) {
|
||||
// check if the line is too big (in the clip space) to be drawn
|
||||
const [x1, y1] = AladinUtils.viewXyToClipXy(line.x1, line.y1, view);
|
||||
const [x2, y2] = AladinUtils.viewXyToClipXy(line.x2, line.y2, view);
|
||||
|
||||
const mag2 = (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2);
|
||||
|
||||
const mag2 = _calculateMag2ForNoSinProjections(line, view);
|
||||
|
||||
if (mag2 < 0.1) {
|
||||
line.draw(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 3. Check whether the polygon do not cross the view
|
||||
let nSegment = this.closed ? len : len - 1;
|
||||
/*
|
||||
let v0 = this.closed ? len - 1 : 0;
|
||||
let v1 = this.closed ? 0 : 1;
|
||||
let v2 = this.closed ? 1 : 2;
|
||||
if (this.closed && this.fill) {
|
||||
fillPoly = (v0, v1, index) => {
|
||||
const line = new Line(v0.x, v0.y, v1.x, v1.y);
|
||||
|
||||
let drawPolygon = true;
|
||||
for (var k = 0; k < nSegment; k++) {
|
||||
let ccwTriOrder = ccwOrder(xyView[v0], xyView[v1], xyView[v2])
|
||||
if (_isAcrossCollignonZoneForHpxProjection(line, view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ccwGoodOrder != ccwTriOrder) {
|
||||
// if it cross the view, we end up here
|
||||
drawPolygon = false;
|
||||
const mag2 = _calculateMag2ForNoSinProjections(line, view);
|
||||
|
||||
return;
|
||||
if (mag2 < 0.1) {
|
||||
if (index === 0) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(line.x1, line.y1);
|
||||
} else {
|
||||
ctx.lineTo(line.x1, line.y1);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
drawLine = (v0, v1) => {
|
||||
const line = new Line(v0.x, v0.y, v1.x, v1.y);
|
||||
|
||||
v0 = v1;
|
||||
v1 = v2;
|
||||
v2 = (v2 + 1) % len;
|
||||
if (line.isInsideView(view.width, view.height)) {
|
||||
const mag2 = _calculateMag2ForNoSinProjections(line, view);
|
||||
|
||||
if (mag2 < 0.1) {
|
||||
line.draw(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (this.closed && this.fill) {
|
||||
fillPoly = (v0, v1, index) => {
|
||||
const line = new Line(v0.x, v0.y, v1.x, v1.y);
|
||||
|
||||
const mag2 = _calculateMag2ForNoSinProjections(line, view);
|
||||
|
||||
if (mag2 < 0.1) {
|
||||
if (index === 0) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(line.x1, line.y1);
|
||||
} else {
|
||||
ctx.lineTo(line.x1, line.y1);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!drawPolygon) {
|
||||
return;
|
||||
}*/
|
||||
|
||||
// 4. Finally, draw all the polygon, segment by segment
|
||||
let nSegment = this.closed ? len : len - 1;
|
||||
|
||||
let v0 = this.closed ? len - 1 : 0;
|
||||
let v1 = this.closed ? 0 : 1;
|
||||
|
||||
ctx.lineWidth = this.lineWidth;
|
||||
ctx.beginPath();
|
||||
|
||||
|
||||
for (var k = 0; k < nSegment; k++) {
|
||||
drawLine(xyView[v0], xyView[v1])
|
||||
drawLine(xyView[v0], xyView[v1]);
|
||||
|
||||
v0 = v1;
|
||||
v1 = v1 + 1;
|
||||
@@ -275,6 +363,28 @@ export let Polyline= (function() {
|
||||
if (!noStroke) {
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
if (this.fill && this.closed) {
|
||||
v0 = len - 1;
|
||||
v1 = 0;
|
||||
|
||||
let index = 0;
|
||||
for (var k = 0; k < nSegment; k++) {
|
||||
if (fillPoly(xyView[v0], xyView[v1], index)) {
|
||||
index++;
|
||||
}
|
||||
|
||||
v0 = v1;
|
||||
v1 = v1 + 1;
|
||||
}
|
||||
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.fillColor;
|
||||
ctx.globalAlpha = this.opacity;
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Polyline.prototype.isInStroke = function(ctx, view, x, y) {
|
||||
@@ -303,7 +413,7 @@ export let Polyline= (function() {
|
||||
if(this.closed) {
|
||||
const line = new Line(pointXY[lastPointIdx].x, pointXY[lastPointIdx].y, pointXY[0].x, pointXY[0].y); // new segment
|
||||
line.draw(ctx, true);
|
||||
|
||||
|
||||
if (ctx.isPointInStroke(x, y)) { // x,y is on line?
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import { Catalog } from "./Catalog.js";
|
||||
import { Source } from "./Source.js";
|
||||
import { Color } from "./Color.js";
|
||||
import { Coo } from "./libs/astro/coo.js";
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { CooFrameEnum } from "./CooFrameEnum.js";
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
import { Coo } from "./libs/astro/coo.js";
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { AladinUtils } from "./AladinUtils.js";
|
||||
|
||||
export let SimbadPointer = (function() {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
import { Coo } from './libs/astro/coo.js';
|
||||
import { Utils } from './Utils.js';
|
||||
import { Utils } from './Utils';
|
||||
export let URLBuilder = (function() {
|
||||
|
||||
let URLBuilder = {
|
||||
|
||||
428
src/js/Utils.js
428
src/js/Utils.js
@@ -1,428 +0,0 @@
|
||||
// Copyright 2013 - UDS/CNRS
|
||||
// The Aladin Lite program is distributed under the terms
|
||||
// of the GNU General Public License version 3.
|
||||
//
|
||||
// This file is part of Aladin Lite.
|
||||
//
|
||||
// Aladin Lite is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Aladin Lite is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// The GNU General Public License is available in COPYING file
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File Utils
|
||||
*
|
||||
* Author: Thomas Boch[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Aladin } from "./Aladin.js";
|
||||
import $ from 'jquery';
|
||||
|
||||
export let Utils = {};
|
||||
|
||||
// list of URL domains that can be safely switched from HTTP to HTTPS
|
||||
Utils.HTTPS_WHITELIST = ['alasky.u-strasbg.fr', 'alaskybis.u-strasbg.fr', 'alasky.unistra.fr', 'alaskybis.unistra.fr',
|
||||
'alasky.cds.unistra.fr', 'alaskybis.cds.unistra.fr', 'hips.astron.nl', 'jvo.nao.ac.jp',
|
||||
'archive.cefca.es', 'cade.irap.omp.eu', 'skies.esac.esa.int'];
|
||||
|
||||
Utils.cssScale = undefined;
|
||||
// adding relMouseCoords to HTMLCanvasElement prototype (see http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-element )
|
||||
function relMouseCoords(event) {
|
||||
if (event.offsetX) {
|
||||
return {x: event.offsetX, y: event.offsetY};
|
||||
}
|
||||
else {
|
||||
if (!Utils.cssScale) {
|
||||
var st = window.getComputedStyle(document.body, null);
|
||||
var tr = st.getPropertyValue("-webkit-transform") ||
|
||||
st.getPropertyValue("-moz-transform") ||
|
||||
st.getPropertyValue("-ms-transform") ||
|
||||
st.getPropertyValue("-o-transform") ||
|
||||
st.getPropertyValue("transform");
|
||||
var matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/;
|
||||
var matches = tr.match(matrixRegex);
|
||||
if (matches) {
|
||||
Utils.cssScale = parseFloat(matches[1]);
|
||||
}
|
||||
else {
|
||||
Utils.cssScale = 1;
|
||||
}
|
||||
}
|
||||
var e = event;
|
||||
var canvas = e.target;
|
||||
// http://www.jacklmoore.com/notes/mouse-position/
|
||||
var target = e.target || e.srcElement;
|
||||
var style = target.currentStyle || window.getComputedStyle(target, null);
|
||||
var borderLeftWidth = parseInt(style['borderLeftWidth'], 10);
|
||||
var borderTopWidth = parseInt(style['borderTopWidth'], 10);
|
||||
var rect = target.getBoundingClientRect();
|
||||
|
||||
var clientX = e.clientX;
|
||||
var clientY = e.clientY;
|
||||
if (e.originalEvent.changedTouches) {
|
||||
clientX = e.originalEvent.changedTouches[0].clientX;
|
||||
clientY = e.originalEvent.changedTouches[0].clientY;
|
||||
}
|
||||
|
||||
var offsetX = clientX - borderLeftWidth - rect.left;
|
||||
var offsetY = clientY - borderTopWidth - rect.top
|
||||
|
||||
return {x: parseInt(offsetX/Utils.cssScale), y: parseInt(offsetY/Utils.cssScale)};
|
||||
}
|
||||
}
|
||||
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
|
||||
|
||||
|
||||
|
||||
//Function.prototype.bind polyfill from
|
||||
//https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function (obj) {
|
||||
// closest thing possible to the ECMAScript 5 internal IsCallable function
|
||||
if (typeof this !== 'function') {
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var slice = [].slice,
|
||||
args = slice.call(arguments, 1),
|
||||
self = this,
|
||||
nop = function () { },
|
||||
bound = function () {
|
||||
return self.apply(this instanceof nop ? this : (obj || {}),
|
||||
args.concat(slice.call(arguments)));
|
||||
};
|
||||
|
||||
bound.prototype = this.prototype;
|
||||
|
||||
return bound;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//$ = $ || jQuery;
|
||||
|
||||
/* source : http://stackoverflow.com/a/8764051 */
|
||||
$.urlParam = function(name, queryString){
|
||||
if (queryString===undefined) {
|
||||
queryString = location.search;
|
||||
}
|
||||
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(queryString)||[,""])[1].replace(/\+/g, '%20'))||null;
|
||||
};
|
||||
|
||||
/* source: http://stackoverflow.com/a/1830844 */
|
||||
Utils.isNumber = function(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
};
|
||||
|
||||
Utils.isInt = function(n) {
|
||||
return Utils.isNumber(n) && Math.floor(n)==n;
|
||||
};
|
||||
|
||||
/* a debounce function, used to prevent multiple calls to the same function if less than delay milliseconds have passed */
|
||||
Utils.debounce = function(fn, delay) {
|
||||
var timer = null;
|
||||
return function () {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function () {
|
||||
fn.apply(context, args);
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
/* return a throttled function, to rate limit the number of calls (by default, one call every 250 milliseconds) */
|
||||
Utils.throttle = function(fn, threshhold, scope) {
|
||||
threshhold || (threshhold = 250);
|
||||
var last,
|
||||
deferTimer;
|
||||
return function () {
|
||||
var context = scope || this;
|
||||
|
||||
var now = +new Date,
|
||||
args = arguments;
|
||||
if (last && now < last + threshhold) {
|
||||
// hold on to it
|
||||
clearTimeout(deferTimer);
|
||||
deferTimer = setTimeout(function () {
|
||||
last = now;
|
||||
fn.apply(context, args);
|
||||
}, threshhold);
|
||||
} else {
|
||||
last = now;
|
||||
fn.apply(context, args);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* A LRU cache, inspired by https://gist.github.com/devinus/409353#file-gistfile1-js */
|
||||
// TODO : utiliser le LRU cache pour les tuiles images
|
||||
Utils.LRUCache = function (maxsize) {
|
||||
this._keys = [];
|
||||
this._items = {};
|
||||
this._expires = {};
|
||||
this._size = 0;
|
||||
this._maxsize = maxsize || 1024;
|
||||
};
|
||||
|
||||
Utils.LRUCache.prototype = {
|
||||
set: function (key, value) {
|
||||
var keys = this._keys,
|
||||
items = this._items,
|
||||
expires = this._expires,
|
||||
size = this._size,
|
||||
maxsize = this._maxsize;
|
||||
|
||||
if (size >= maxsize) { // remove oldest element when no more room
|
||||
keys.sort(function (a, b) {
|
||||
if (expires[a] > expires[b]) return -1;
|
||||
if (expires[a] < expires[b]) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
size--;
|
||||
}
|
||||
|
||||
keys[size] = key;
|
||||
items[key] = value;
|
||||
expires[key] = Date.now();
|
||||
size++;
|
||||
|
||||
this._keys = keys;
|
||||
this._items = items;
|
||||
this._expires = expires;
|
||||
this._size = size;
|
||||
},
|
||||
|
||||
get: function (key) {
|
||||
var item = this._items[key];
|
||||
if (item) { this._expires[key] = Date.now(); }
|
||||
return item;
|
||||
},
|
||||
|
||||
keys: function() {
|
||||
return this._keys;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////:
|
||||
|
||||
/**
|
||||
Fetch an url with the method GET, given a list of potential mirrors
|
||||
An optional object can be given with the following keywords accepted:
|
||||
* data: an object storing the params associated to the URL
|
||||
* contentType: specify the content type returned from the url (no verification is done, it is not mandatory to put it)
|
||||
* timeout: A maximum request time. If exceeded, the request is aborted and the next url will be fetched
|
||||
This method assumes the URL are CORS-compatible, no proxy will be used
|
||||
|
||||
A promise is returned. When all the urls fail, a rejected Promise is returned so that it can be catched afterwards
|
||||
*/
|
||||
Utils.loadFromMirrors = function(urls, options) {
|
||||
const contentType = options && options.contentType || "application/json";
|
||||
const data = options && options.data || undefined;
|
||||
const timeout = options && options.timeout || 5000;
|
||||
|
||||
// Base case, when all urls have been fetched and failed
|
||||
if (urls.length === 0) {
|
||||
return Promise.reject("None of the urls given can be fetched!");
|
||||
}
|
||||
|
||||
// A controller that can abort the query when a timeout is reached
|
||||
const controller = new AbortController();
|
||||
|
||||
// Launch a timemout that will interrupt the fetch if it has not yet succeded:
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
const init = {
|
||||
// *GET, POST, PUT, DELETE, etc.
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": contentType
|
||||
},
|
||||
// no-cors, *cors, same-origin
|
||||
mode: 'cors',
|
||||
// *default, no-cache, reload, force-cache, only-if-cached
|
||||
cache: 'default',
|
||||
// manual, *follow, error
|
||||
redirect: 'follow',
|
||||
// Abort the request when a timeout exceeded
|
||||
signal: controller.signal,
|
||||
};
|
||||
|
||||
const url = urls[0] + '?' + new URLSearchParams(data);
|
||||
return fetch(url, init)
|
||||
.then((response) => {
|
||||
// completed request before timeout fired
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (!response.ok) {
|
||||
return Promise.reject("Url: ", urls[0], " cannot be reached in some way.");
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
// The request aborted because it was to slow, fetch the next url given recursively
|
||||
return Utils.loadFromMirrors(urls.slice(1), options);
|
||||
});
|
||||
}
|
||||
|
||||
// return the jquery ajax object configured with the requested parameters
|
||||
// by default, we use the proxy (safer, as we don't know if the remote server supports CORS)
|
||||
Utils.getAjaxObject = function(url, method, dataType, useProxy) {
|
||||
if (useProxy!==false) {
|
||||
useProxy = true;
|
||||
}
|
||||
|
||||
if (useProxy===true) {
|
||||
var urlToRequest = Aladin.JSONP_PROXY + '?url=' + encodeURIComponent(url);
|
||||
}
|
||||
else {
|
||||
urlToRequest = url;
|
||||
}
|
||||
method = method || 'GET';
|
||||
dataType = dataType || null;
|
||||
|
||||
return $.ajax({
|
||||
url: urlToRequest,
|
||||
method: method,
|
||||
dataType: dataType
|
||||
});
|
||||
};
|
||||
|
||||
// return true if script is executed in a HTTPS context
|
||||
// return false otherwise
|
||||
Utils.isFileContext = function() {
|
||||
return ( window.location.protocol === 'file:' );
|
||||
};
|
||||
|
||||
Utils.isHttpsContext = function() {
|
||||
return ( window.location.protocol === 'https:' );
|
||||
};
|
||||
|
||||
Utils.isHttpContext = function() {
|
||||
return ( window.location.protocol === 'http:' );
|
||||
};
|
||||
|
||||
Utils.fixURLForHTTPS = function(url) {
|
||||
const switchToHttps = Utils.HTTPS_WHITELIST.some(element => {
|
||||
return url.includes(element);
|
||||
});
|
||||
|
||||
if (switchToHttps) {
|
||||
return url.replace('http://', 'https://');
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
// generate an absolute URL from a relative URL
|
||||
// example: getAbsoluteURL('foo/bar/toto') return http://cds.unistra.fr/AL/foo/bar/toto if executed from page http://cds.unistra.fr/AL/
|
||||
Utils.getAbsoluteURL = function(url) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
|
||||
return a.href;
|
||||
};
|
||||
|
||||
// generate a valid v4 UUID
|
||||
Utils.uuidv4 = function() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @description Deep clone a class instance.
|
||||
* @param {object} instance The class instance you want to clone.
|
||||
* @returns {object} A new cloned instance.
|
||||
*/
|
||||
Utils.clone = function(instance) {
|
||||
return Object.assign(
|
||||
Object.create(
|
||||
// Set the prototype of the new object to the prototype of the instance.
|
||||
// Used to allow new object behave like class instance.
|
||||
Object.getPrototypeOf(instance),
|
||||
),
|
||||
// Prevent shallow copies of nested structures like arrays, etc
|
||||
JSON.parse(JSON.stringify(instance)),
|
||||
);
|
||||
}
|
||||
|
||||
Utils.getDroppedFilesHandler = function(ev) {
|
||||
// Prevent default behavior (Prevent file from being opened)
|
||||
ev.preventDefault();
|
||||
|
||||
let items;
|
||||
if (ev.dataTransfer.items) {
|
||||
// Use DataTransferItemList interface to access the file(s)
|
||||
items = [...ev.dataTransfer.items];
|
||||
} else {
|
||||
// Use DataTransfer interface to access the file(s)
|
||||
items = [...ev.dataTransfer.files];
|
||||
}
|
||||
|
||||
const files = items.filter((item) => {
|
||||
// If dropped items aren't files, reject them
|
||||
return item.kind === 'file';
|
||||
})
|
||||
.map((item) => item.getAsFile());
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
Utils.dragOverHandler = function(ev) {
|
||||
// Prevent default behavior (Prevent file from being opened)
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
Utils.requestCORSIfNotSameOrigin = function(url) {
|
||||
return (new URL(url, window.location.href)).origin !== window.location.origin;
|
||||
}
|
||||
|
||||
// Check the protocol, for http ones, use a CORS compatible proxy
|
||||
Utils.handleCORSNotSameOrigin = function(url) {
|
||||
if (Utils.requestCORSIfNotSameOrigin(url)) {
|
||||
// http(s) protocols and not in localhost
|
||||
let proxiedUrl = new URL(Aladin.JSONP_PROXY);
|
||||
proxiedUrl.searchParams.append("url", url);
|
||||
|
||||
url = proxiedUrl;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
Utils.deepCopy = function(orig) {
|
||||
return Object.assign(Object.create(Object.getPrototypeOf(orig)), orig);
|
||||
}
|
||||
|
||||
Utils.download = function(url, name = undefined) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
if (name) {
|
||||
a.download = name;
|
||||
}
|
||||
a.click()
|
||||
}
|
||||
413
src/js/Utils.ts
Normal file
413
src/js/Utils.ts
Normal file
@@ -0,0 +1,413 @@
|
||||
// Copyright 2013 - UDS/CNRS
|
||||
// The Aladin Lite program is distributed under the terms
|
||||
// of the GNU General Public License version 3.
|
||||
//
|
||||
// This file is part of Aladin Lite.
|
||||
//
|
||||
// Aladin Lite is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Aladin Lite is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// The GNU General Public License is available in COPYING file
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File Utils
|
||||
*
|
||||
* Author: Thomas Boch[CDS]
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import {JSONP_PROXY} from "@/js/Constants";
|
||||
|
||||
export let Utils: any = {}
|
||||
|
||||
// list of URL domains that can be safely switched from HTTP to HTTPS
|
||||
Utils.HTTPS_WHITELIST = ['alasky.u-strasbg.fr', 'alaskybis.u-strasbg.fr', 'alasky.unistra.fr', 'alaskybis.unistra.fr',
|
||||
'alasky.cds.unistra.fr', 'alaskybis.cds.unistra.fr', 'hips.astron.nl', 'jvo.nao.ac.jp',
|
||||
'archive.cefca.es', 'cade.irap.omp.eu', 'skies.esac.esa.int']
|
||||
|
||||
Utils.cssScale = undefined
|
||||
|
||||
Utils.relMouseCoords = function (canvas: HTMLCanvasElement, event: MouseEvent) {
|
||||
if (event.offsetX) {
|
||||
return {x: event.offsetX, y: event.offsetY}
|
||||
} else {
|
||||
if (!Utils.cssScale) {
|
||||
var st = window.getComputedStyle(document.body, null)
|
||||
var tr = st.getPropertyValue('-webkit-transform') ||
|
||||
st.getPropertyValue('-moz-transform') ||
|
||||
st.getPropertyValue('-ms-transform') ||
|
||||
st.getPropertyValue('-o-transform') ||
|
||||
st.getPropertyValue('transform')
|
||||
var matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/
|
||||
var matches = tr.match(matrixRegex)
|
||||
if (matches) {
|
||||
Utils.cssScale = parseFloat(matches[1])
|
||||
} else {
|
||||
Utils.cssScale = 1
|
||||
}
|
||||
}
|
||||
var e = event
|
||||
// http://www.jacklmoore.com/notes/mouse-position/
|
||||
var target = e.target || e.srcElement
|
||||
var style = target.currentStyle || window.getComputedStyle(target, null)
|
||||
var borderLeftWidth = parseInt(style['borderLeftWidth'], 10)
|
||||
var borderTopWidth = parseInt(style['borderTopWidth'], 10)
|
||||
var rect = target.getBoundingClientRect()
|
||||
|
||||
var clientX = e.clientX
|
||||
var clientY = e.clientY
|
||||
if (e.originalEvent.changedTouches) {
|
||||
clientX = e.originalEvent.changedTouches[0].clientX
|
||||
clientY = e.originalEvent.changedTouches[0].clientY
|
||||
}
|
||||
|
||||
var offsetX = clientX - borderLeftWidth - rect.left
|
||||
var offsetY = clientY - borderTopWidth - rect.top
|
||||
|
||||
return {x: Math.round(offsetX / Utils.cssScale), y: Math.round(offsetY / Utils.cssScale)}
|
||||
}
|
||||
}
|
||||
|
||||
//Function.prototype.bind polyfill from
|
||||
//https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function (obj) {
|
||||
// closest thing possible to the ECMAScript 5 internal IsCallable function
|
||||
if (typeof this !== 'function') {
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable')
|
||||
}
|
||||
|
||||
var slice = [].slice,
|
||||
args = slice.call(arguments, 1),
|
||||
self = this,
|
||||
nop = function () {
|
||||
},
|
||||
bound = function () {
|
||||
return self.apply(this instanceof nop ? this : (obj || {}),
|
||||
args.concat(slice.call(arguments)))
|
||||
}
|
||||
|
||||
bound.prototype = this.prototype
|
||||
|
||||
return bound
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* source : http://stackoverflow.com/a/8764051 */
|
||||
Utils.urlParam = function (name: string, queryString: string | undefined) {
|
||||
if (queryString === undefined) {
|
||||
queryString = location.search
|
||||
}
|
||||
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(queryString) || [, ''])[1].replace(/\+/g, '%20')) || null
|
||||
}
|
||||
|
||||
/* source: http://stackoverflow.com/a/1830844 */
|
||||
Utils.isNumber = function (n: string | number) {
|
||||
return !isNaN(parseFloat(n as string)) && isFinite(n as number)
|
||||
}
|
||||
|
||||
Utils.isInt = function (n: string | number) {
|
||||
return Utils.isNumber(n) && Math.floor(n as number) === n
|
||||
}
|
||||
|
||||
/* a debounce function, used to prevent multiple calls to the same function if less than delay milliseconds have passed */
|
||||
Utils.debounce = function (fn, delay) {
|
||||
var timer = null
|
||||
return function () {
|
||||
var context = this, args = arguments
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(function () {
|
||||
fn.apply(context, args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/* return a throttled function, to rate limit the number of calls (by default, one call every 250 milliseconds) */
|
||||
Utils.throttle = function (fn, threshhold, scope) {
|
||||
threshhold || (threshhold = 250)
|
||||
var last,
|
||||
deferTimer
|
||||
return function () {
|
||||
var context = scope || this
|
||||
|
||||
var now = +new Date,
|
||||
args = arguments
|
||||
if (last && now < last + threshhold) {
|
||||
// hold on to it
|
||||
clearTimeout(deferTimer)
|
||||
deferTimer = setTimeout(function () {
|
||||
last = now
|
||||
fn.apply(context, args)
|
||||
}, threshhold)
|
||||
} else {
|
||||
last = now
|
||||
fn.apply(context, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* A LRU cache, inspired by https://gist.github.com/devinus/409353#file-gistfile1-js */
|
||||
// TODO : utiliser le LRU cache pour les tuiles images
|
||||
Utils.LRUCache = function (maxsize) {
|
||||
this._keys = []
|
||||
this._items = {}
|
||||
this._expires = {}
|
||||
this._size = 0
|
||||
this._maxsize = maxsize || 1024
|
||||
}
|
||||
|
||||
Utils.LRUCache.prototype = {
|
||||
set: function (key, value) {
|
||||
var keys = this._keys,
|
||||
items = this._items,
|
||||
expires = this._expires,
|
||||
size = this._size,
|
||||
maxsize = this._maxsize
|
||||
|
||||
if (size >= maxsize) { // remove oldest element when no more room
|
||||
keys.sort(function (a, b) {
|
||||
if (expires[a] > expires[b]) return -1
|
||||
if (expires[a] < expires[b]) return 1
|
||||
return 0
|
||||
})
|
||||
|
||||
size--
|
||||
}
|
||||
|
||||
keys[size] = key
|
||||
items[key] = value
|
||||
expires[key] = Date.now()
|
||||
size++
|
||||
|
||||
this._keys = keys
|
||||
this._items = items
|
||||
this._expires = expires
|
||||
this._size = size
|
||||
},
|
||||
|
||||
get: function (key) {
|
||||
var item = this._items[key]
|
||||
if (item) {
|
||||
this._expires[key] = Date.now()
|
||||
}
|
||||
return item
|
||||
},
|
||||
|
||||
keys: function () {
|
||||
return this._keys
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////:
|
||||
|
||||
/**
|
||||
Fetch an url with the method GET, given a list of potential mirrors
|
||||
An optional object can be given with the following keywords accepted:
|
||||
* data: an object storing the params associated to the URL
|
||||
* contentType: specify the content type returned from the url (no verification is done, it is not mandatory to put it)
|
||||
* timeout: A maximum request time. If exceeded, the request is aborted and the next url will be fetched
|
||||
This method assumes the URL are CORS-compatible, no proxy will be used
|
||||
|
||||
A promise is returned. When all the urls fail, a rejected Promise is returned so that it can be catched afterwards
|
||||
*/
|
||||
Utils.loadFromMirrors = function (urls, options) {
|
||||
const contentType = options && options.contentType || 'application/json'
|
||||
const data = options && options.data || undefined
|
||||
const timeout = options && options.timeout || 5000
|
||||
|
||||
// Base case, when all urls have been fetched and failed
|
||||
if (urls.length === 0) {
|
||||
return Promise.reject('None of the urls given can be fetched!')
|
||||
}
|
||||
|
||||
// A controller that can abort the query when a timeout is reached
|
||||
const controller = new AbortController()
|
||||
|
||||
// Launch a timemout that will interrupt the fetch if it has not yet succeded:
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
||||
const init = {
|
||||
// *GET, POST, PUT, DELETE, etc.
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': contentType
|
||||
},
|
||||
// no-cors, *cors, same-origin
|
||||
mode: 'cors',
|
||||
// *default, no-cache, reload, force-cache, only-if-cached
|
||||
cache: 'default',
|
||||
// manual, *follow, error
|
||||
redirect: 'follow',
|
||||
// Abort the request when a timeout exceeded
|
||||
signal: controller.signal,
|
||||
}
|
||||
|
||||
const url = urls[0] + '?' + new URLSearchParams(data)
|
||||
return fetch(url, init)
|
||||
.then((response) => {
|
||||
// completed request before timeout fired
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (!response.ok) {
|
||||
return Promise.reject('Url: ', urls[0], ' cannot be reached in some way.')
|
||||
} else {
|
||||
return response
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
// The request aborted because it was to slow, fetch the next url given recursively
|
||||
return Utils.loadFromMirrors(urls.slice(1), options)
|
||||
})
|
||||
}
|
||||
|
||||
// return the jquery ajax object configured with the requested parameters
|
||||
// by default, we use the proxy (safer, as we don't know if the remote server supports CORS)
|
||||
Utils.getAjaxObject = function (url, method, dataType, useProxy) {
|
||||
if (useProxy !== false) {
|
||||
useProxy = true
|
||||
}
|
||||
|
||||
if (useProxy === true) {
|
||||
var urlToRequest = JSONP_PROXY + '?url=' + encodeURIComponent(url)
|
||||
} else {
|
||||
urlToRequest = url
|
||||
}
|
||||
method = method || 'GET'
|
||||
dataType = dataType || null
|
||||
|
||||
return $.ajax({
|
||||
url: urlToRequest,
|
||||
method: method,
|
||||
dataType: dataType
|
||||
})
|
||||
}
|
||||
|
||||
// return true if script is executed in a HTTPS context
|
||||
// return false otherwise
|
||||
Utils.isFileContext = function () {
|
||||
return (window.location.protocol === 'file:')
|
||||
}
|
||||
|
||||
Utils.isHttpsContext = function () {
|
||||
return (window.location.protocol === 'https:')
|
||||
}
|
||||
|
||||
Utils.isHttpContext = function () {
|
||||
return (window.location.protocol === 'http:')
|
||||
}
|
||||
|
||||
Utils.fixURLForHTTPS = function (url) {
|
||||
const switchToHttps = Utils.HTTPS_WHITELIST.some(element => {
|
||||
return url.includes(element)
|
||||
})
|
||||
|
||||
if (switchToHttps) {
|
||||
return url.replace('http://', 'https://')
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
// generate an absolute URL from a relative URL
|
||||
// example: getAbsoluteURL('foo/bar/toto') return http://cds.unistra.fr/AL/foo/bar/toto if executed from page http://cds.unistra.fr/AL/
|
||||
Utils.getAbsoluteURL = function (url) {
|
||||
var a = document.createElement('a')
|
||||
a.href = url
|
||||
|
||||
return a.href
|
||||
}
|
||||
|
||||
// generate a valid v4 UUID
|
||||
Utils.uuidv4 = function () {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8)
|
||||
return v.toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @description Deep clone a class instance.
|
||||
* @param {object} instance The class instance you want to clone.
|
||||
* @returns {object} A new cloned instance.
|
||||
*/
|
||||
Utils.clone = function (instance) {
|
||||
return Object.assign(
|
||||
Object.create(
|
||||
// Set the prototype of the new object to the prototype of the instance.
|
||||
// Used to allow new object behave like class instance.
|
||||
Object.getPrototypeOf(instance),
|
||||
),
|
||||
// Prevent shallow copies of nested structures like arrays, etc
|
||||
JSON.parse(JSON.stringify(instance)),
|
||||
)
|
||||
}
|
||||
|
||||
Utils.getDroppedFilesHandler = function (ev) {
|
||||
// Prevent default behavior (Prevent file from being opened)
|
||||
ev.preventDefault()
|
||||
|
||||
let items
|
||||
if (ev.dataTransfer.items) {
|
||||
// Use DataTransferItemList interface to access the file(s)
|
||||
items = [...ev.dataTransfer.items]
|
||||
} else {
|
||||
// Use DataTransfer interface to access the file(s)
|
||||
items = [...ev.dataTransfer.files]
|
||||
}
|
||||
|
||||
const files = items.filter((item) => {
|
||||
// If dropped items aren't files, reject them
|
||||
return item.kind === 'file'
|
||||
})
|
||||
.map((item) => item.getAsFile())
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
Utils.dragOverHandler = function (ev) {
|
||||
// Prevent default behavior (Prevent file from being opened)
|
||||
ev.preventDefault()
|
||||
}
|
||||
|
||||
Utils.requestCORSIfNotSameOrigin = function (url) {
|
||||
return (new URL(url, window.location.href)).origin !== window.location.origin
|
||||
}
|
||||
|
||||
// Check the protocol, for http ones, use a CORS compatible proxy
|
||||
Utils.handleCORSNotSameOrigin = function (url) {
|
||||
if (Utils.requestCORSIfNotSameOrigin(url)) {
|
||||
// http(s) protocols and not in localhost
|
||||
let proxiedUrl = new URL(JSONP_PROXY)
|
||||
proxiedUrl.searchParams.append('url', url)
|
||||
|
||||
url = proxiedUrl
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
Utils.deepCopy = function (orig) {
|
||||
return Object.assign(Object.create(Object.getPrototypeOf(orig)), orig)
|
||||
}
|
||||
|
||||
Utils.download = function(url, name = undefined) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
if (name) {
|
||||
a.download = name;
|
||||
}
|
||||
a.click()
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import A from "./A.js";
|
||||
import { Popup } from "./Popup.js";
|
||||
import { HealpixGrid } from "./HealpixGrid.js";
|
||||
import { ProjectionEnum } from "./ProjectionEnum.js";
|
||||
import { Utils } from "./Utils.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { GenericPointer } from "./GenericPointer.js";
|
||||
import { Stats } from "./libs/Stats.js";
|
||||
import { Circle } from "./Circle.js";
|
||||
@@ -256,7 +256,7 @@ export let View = (function () {
|
||||
if (fov !== this.oldFov) {
|
||||
const fovChangedFn = this.aladin.callbacksByEventName['zoomChanged'];
|
||||
(typeof fovChangedFn === 'function') && fovChangedFn(fov);
|
||||
|
||||
|
||||
// finally, save fov value
|
||||
this.oldFov = fov;
|
||||
}
|
||||
@@ -348,9 +348,9 @@ export let View = (function () {
|
||||
this.catalogCtx.canvas.width = this.width;
|
||||
this.catalogCtx.canvas.height = this.height;
|
||||
|
||||
/*this.gridCtx = this.gridCanvas.getContext("2d");
|
||||
this.gridCtx = this.gridCanvas.getContext("2d");
|
||||
this.gridCtx.canvas.width = this.width;
|
||||
this.gridCtx.canvas.height = this.height;*/
|
||||
this.gridCtx.canvas.height = this.height;
|
||||
|
||||
pixelateCanvasContext(this.imageCtx, this.aladin.options.pixelateCanvas);
|
||||
|
||||
@@ -461,7 +461,7 @@ export let View = (function () {
|
||||
|
||||
// various listeners
|
||||
let onDblClick = function (e) {
|
||||
var xymouse = view.imageCanvas.relMouseCoords(e);
|
||||
const xymouse = Utils.relMouseCoords(view.imageCanvas, e);
|
||||
|
||||
// deselect all the selected sources with Select panel
|
||||
view.deselectObjects()
|
||||
@@ -485,7 +485,7 @@ export let View = (function () {
|
||||
// do something here...
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
|
||||
|
||||
let cutMinInit = null
|
||||
let cutMaxInit = null;
|
||||
@@ -494,7 +494,7 @@ export let View = (function () {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var xymouse = view.imageCanvas.relMouseCoords(e);
|
||||
const xymouse = Utils.relMouseCoords(view.imageCanvas, e);
|
||||
|
||||
if (e.which === 3 || e.button === 2) {
|
||||
view.rightClick = true;
|
||||
@@ -618,7 +618,7 @@ export let View = (function () {
|
||||
let tables = selectedObjects.map((objList) => {
|
||||
// Get the catalog containing that list of objects
|
||||
let catalog = objList[0].getCatalog();
|
||||
|
||||
|
||||
let rows = objList.map((o) => {
|
||||
if (o instanceof Footprint) {
|
||||
return o.source;
|
||||
@@ -660,7 +660,7 @@ export let View = (function () {
|
||||
|
||||
view.mustClearCatalog = true;
|
||||
view.dragx = view.dragy = null;
|
||||
const xymouse = view.imageCanvas.relMouseCoords(e);
|
||||
const xymouse = Utils.relMouseCoords(view.imageCanvas, e);
|
||||
|
||||
if (e.type === "mouseout" || e.type === "touchend" || e.type === "touchcancel") {
|
||||
view.updateLocation(xymouse.x, xymouse.y, true);
|
||||
@@ -708,13 +708,13 @@ export let View = (function () {
|
||||
}
|
||||
|
||||
var objClickedFunction = view.aladin.callbacksByEventName['objectClicked'];
|
||||
(typeof objClickedFunction === 'function') && objClickedFunction(o);
|
||||
(typeof objClickedFunction === 'function') && objClickedFunction(o, xymouse);
|
||||
|
||||
|
||||
if (o.isFootprint()) {
|
||||
var footprintClickedFunction = view.aladin.callbacksByEventName['footprintClicked'];
|
||||
if (typeof footprintClickedFunction === 'function' && o != view.lastClickedObject) {
|
||||
var ret = footprintClickedFunction(o);
|
||||
var ret = footprintClickedFunction(o, xymouse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,7 +728,7 @@ export let View = (function () {
|
||||
if (view.lastClickedObject) {
|
||||
view.aladin.measurementTable.hide();
|
||||
view.popup.hide();
|
||||
|
||||
|
||||
// Deselect the last clicked object
|
||||
if (view.lastClickedObject instanceof Ellipse || view.lastClickedObject instanceof Circle || view.lastClickedObject instanceof Polyline) {
|
||||
view.lastClickedObject.deselect();
|
||||
@@ -736,9 +736,9 @@ export let View = (function () {
|
||||
// Case where lastClickedObject is a Source
|
||||
view.lastClickedObject.actionOtherObjectClicked();
|
||||
}
|
||||
|
||||
|
||||
var objClickedFunction = view.aladin.callbacksByEventName['objectClicked'];
|
||||
(typeof objClickedFunction === 'function') && objClickedFunction(null);
|
||||
(typeof objClickedFunction === 'function') && objClickedFunction(null, xymouse);
|
||||
|
||||
view.lastClickedObject = null;
|
||||
}
|
||||
@@ -766,11 +766,11 @@ export let View = (function () {
|
||||
var lastMouseMovePos = null;
|
||||
$(view.catalogCanvas).bind("mousemove touchmove", function (e) {
|
||||
e.preventDefault();
|
||||
var xymouse = view.imageCanvas.relMouseCoords(e);
|
||||
const xymouse = Utils.relMouseCoords(view.imageCanvas, e);
|
||||
|
||||
if (view.rightClick) {
|
||||
var onRightClickMoveFunction = view.aladin.callbacksByEventName['rightClickMove'];
|
||||
if (typeof onRightClickMoveFunction === 'function') {
|
||||
if (typeof onRightClickMoveFunction === 'function') {
|
||||
onRightClickMoveFunction(xymouse.x, xymouse.y);
|
||||
|
||||
// do not process further
|
||||
@@ -786,12 +786,12 @@ export let View = (function () {
|
||||
};
|
||||
const cx = (xymouse.x - cs.x) / view.catalogCanvas.clientWidth;
|
||||
const cy = -(xymouse.y - cs.y) / view.catalogCanvas.clientHeight;
|
||||
|
||||
|
||||
const offset = (cutMaxInit - cutMinInit) * cx;
|
||||
|
||||
|
||||
const lr = offset + (1.0 - 2.0 * cy) * cutMinInit;
|
||||
const rr = offset + (1.0 + 2.0 * cy) * cutMaxInit;
|
||||
|
||||
|
||||
if (lr <= rr) {
|
||||
selectedLayer.setCuts(lr, rr)
|
||||
}
|
||||
@@ -867,12 +867,12 @@ export let View = (function () {
|
||||
|
||||
view.setCursor('pointer');
|
||||
if (typeof objHoveredFunction === 'function' && o != lastHoveredObject) {
|
||||
var ret = objHoveredFunction(o);
|
||||
var ret = objHoveredFunction(o, xymouse);
|
||||
}
|
||||
|
||||
if (o.isFootprint()) {
|
||||
if (typeof footprintHoveredFunction === 'function' && o != lastHoveredObject) {
|
||||
var ret = footprintHoveredFunction(o);
|
||||
var ret = footprintHoveredFunction(o, xymouse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,10 +885,10 @@ export let View = (function () {
|
||||
if (lastHoveredObject.isFootprint()) {
|
||||
view.requestRedraw();
|
||||
}
|
||||
|
||||
|
||||
if (typeof objHoveredStopFunction === 'function') {
|
||||
// call callback function to notify we left the hovered object
|
||||
var ret = objHoveredStopFunction(lastHoveredObject);
|
||||
var ret = objHoveredStopFunction(lastHoveredObject, xymouse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1959,7 +1959,7 @@ export let View = (function () {
|
||||
sources = cat.getSources();
|
||||
for (var l = 0; l < sources.length; l++) {
|
||||
s = sources[l];
|
||||
if (!s.isShowing || !s.x || !s.y) {
|
||||
if (!s.isShowing || !s.x || !s.y || cat.readOnly) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1984,7 +1984,7 @@ export let View = (function () {
|
||||
}
|
||||
|
||||
let closest = null;
|
||||
|
||||
|
||||
footprints.forEach((footprint) => {
|
||||
// Hidden footprints are not considered
|
||||
if (footprint.isShowing && footprint.isInStroke(ctx, this, x, y)) {
|
||||
@@ -2022,7 +2022,7 @@ export let View = (function () {
|
||||
if (this.catalogs) {
|
||||
for (var k = 0; k < this.catalogs.length; k++) {
|
||||
let catalog = this.catalogs[k];
|
||||
|
||||
|
||||
let closest = this.closestFootprints(catalog.footprints, ctx, x, y);
|
||||
if (closest) {
|
||||
ctx.lineWidth = pastLineWidth;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//
|
||||
|
||||
import { MocServer } from "../MocServer.js";
|
||||
import { Utils } from "../Utils.js";
|
||||
import { Utils } from "../Utils";
|
||||
import autocomplete from 'autocompleter';
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
import { Coo } from "../libs/astro/coo.js";
|
||||
import { CooFrameEnum } from "../CooFrameEnum.js";
|
||||
import { Coo } from '../libs/astro/coo.js';
|
||||
import { CooFrameEnum } from '../CooFrameEnum.js';
|
||||
import { Utils } from '../Utils';
|
||||
|
||||
export class ContextMenu {
|
||||
|
||||
@@ -42,11 +43,11 @@ export class ContextMenu {
|
||||
|
||||
_hideMenu(e) {
|
||||
//if (e === true || !this.contextMenuUl.contains(e.target)) {
|
||||
this.contextMenuUl.remove();
|
||||
document.removeEventListener('click', this._hideMenu);
|
||||
window.removeEventListener('resize', this._hideOnResize);
|
||||
this.contextMenuUl.remove();
|
||||
document.removeEventListener('click', this._hideMenu);
|
||||
window.removeEventListener('resize', this._hideOnResize);
|
||||
|
||||
this.isShowing = false;
|
||||
this.isShowing = false;
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -57,31 +58,27 @@ export class ContextMenu {
|
||||
_attachOption(target, opt, xymouse) {
|
||||
const item = document.createElement('li');
|
||||
item.className = 'aladin-context-menu-item';
|
||||
if (opt.label=='Copy position') {
|
||||
if (opt.label == 'Copy position') {
|
||||
try {
|
||||
const pos = this.aladin.pix2world(xymouse.x, xymouse.y);
|
||||
const coo = new Coo(pos[0], pos[1], 6);
|
||||
let posStr;
|
||||
if (this.aladin.view.cooFrame == CooFrameEnum.J2000) {
|
||||
posStr = coo.format('s/');
|
||||
}
|
||||
else if (this.aladin.view.cooFrame == CooFrameEnum.J2000d) {
|
||||
} else if (this.aladin.view.cooFrame == CooFrameEnum.J2000d) {
|
||||
posStr = coo.format('d/');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
posStr = coo.format('d/');
|
||||
}
|
||||
item.innerHTML = '<span>' + posStr + '</span>';
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
item.innerHTML = '<span></span>';
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
item.innerHTML = '<span>' + opt.label + '</span>';
|
||||
}
|
||||
|
||||
if (opt.subMenu && opt.subMenu.length>0) {
|
||||
if (opt.subMenu && opt.subMenu.length > 0) {
|
||||
item.innerHTML += '<span style="position: absolute; right: 4px;">▶</span>';
|
||||
}
|
||||
|
||||
@@ -89,10 +86,9 @@ export class ContextMenu {
|
||||
item.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
if (!opt.subMenu || opt.subMenu.length === 0) {
|
||||
if (opt.label=='Copy position') {
|
||||
if (opt.label == 'Copy position') {
|
||||
opt.action(e);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
opt.action(this.event);
|
||||
}
|
||||
self._hideMenu(true);
|
||||
@@ -105,19 +101,17 @@ export class ContextMenu {
|
||||
const subMenu = document.createElement('ul');
|
||||
subMenu.className = 'aladin-context-sub-menu';
|
||||
item.appendChild(subMenu);
|
||||
opt.subMenu.forEach(subOpt => this._attachOption(subMenu, subOpt))
|
||||
opt.subMenu.forEach(subOpt => this._attachOption(subMenu, subOpt));
|
||||
}
|
||||
}
|
||||
|
||||
_showMenu(e) {
|
||||
|
||||
|
||||
this.contextMenuUl.className = 'aladin-context-menu';
|
||||
this.contextMenuUl.innerHTML = '';
|
||||
|
||||
const xymouse = this.aladin.view.imageCanvas.relMouseCoords(e);
|
||||
const xymouse = Utils.relMouseCoords(this.aladin.view.imageCanvas, e);
|
||||
|
||||
this.menuOptions.forEach(opt => this._attachOption(this.contextMenuUl, opt, xymouse))
|
||||
this.menuOptions.forEach(opt => this._attachOption(this.contextMenuUl, opt, xymouse));
|
||||
document.body.appendChild(this.contextMenuUl);
|
||||
|
||||
const { innerWidth, innerHeight } = window;
|
||||
@@ -154,7 +148,6 @@ export class ContextMenu {
|
||||
}
|
||||
|
||||
|
||||
|
||||
attachTo(el, options) {
|
||||
this.contextMenuUl = document.createElement('ul');
|
||||
this.menuOptions = options;
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
// Coordinates grid plot
|
||||
let labelCoordinatesGridCb = $('<div class="aladin-label">Coo grid options</div>');
|
||||
let cooGridOptions = $('<div class="layer-options"><table><tbody><tr><td>Color</td><td><input type="color" value="#00ff00"></td></tr><tr><td>Opacity</td><td><input class="aladin-input opacity" value="0.5" type="range" min="0.0" max="1.0" step="0.05"></td></tr><tr><td>Thickness</td><td><input class="aladin-input thickness" value="3.0" type="range" min="0.5" max="10.0" step="0.01"></td></tr><tr><td>Label size</td><td><input class="aladin-input label-size" type="range" value="30" min="10" max="60" step="0.01"></td></tr></table></div>');
|
||||
let cooGridOptions = $('<div class="layer-options"><table><tbody><tr><td>Color</td><td><input type="color" value="#00ff00"></td></tr><tr><td>Opacity</td><td><input class="aladin-input opacity" value="0.5" type="range" min="0.0" max="1.0" step="0.05"></td></tr><tr><td>Thickness</td><td><input class="aladin-input thickness" value="3.0" type="range" min="0.5" max="10.0" step="0.01"></td></tr><tr><td>Label size</td><td><input class="aladin-input label-size" type="range" value="15" min="5" max="30" step="0.01"></td></tr></table></div>');
|
||||
layerBox.append(labelCoordinatesGridCb).append(cooGridOptions);
|
||||
|
||||
let gridColorInput = cooGridOptions.find('input[type="color"]');
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import A from "../A.js";
|
||||
import { MocServer } from "../MocServer.js";
|
||||
import { Utils } from "../Utils.js";
|
||||
import { Utils } from "../Utils";
|
||||
import autocomplete from 'autocompleter';
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { VOTable } from "./VOTable.js";
|
||||
import { Utils } from './../Utils.js';
|
||||
import { Utils } from './../Utils';
|
||||
|
||||
export let Datalink = (function() {
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
*****************************************************************************/
|
||||
import { VOTable } from "./VOTable.js";
|
||||
import { Datalink } from "./Datalink.js";
|
||||
import { Utils } from '../Utils.js';
|
||||
import { Utils } from '../Utils';
|
||||
|
||||
export let ObsCore = (function() {
|
||||
|
||||
@@ -241,4 +241,3 @@
|
||||
|
||||
return ObsCore;
|
||||
})();
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
import { ALEvent } from "../events/ALEvent.js";
|
||||
import { Catalog } from "../Catalog.js";
|
||||
import { ObsCore } from "./ObsCore.js";
|
||||
import { Utils } from "./../Utils.js";
|
||||
import { Utils } from "./../Utils";
|
||||
|
||||
export let VOTable = (function() {
|
||||
|
||||
|
||||
13
tests/unit/Utils.spec.js
Normal file
13
tests/unit/Utils.spec.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import {Utils} from '@/js/Utils.ts';
|
||||
|
||||
describe('Utils.ts', () => {
|
||||
beforeEach(() => {
|
||||
delete window.location;
|
||||
window.location = {href: {}, search: ''};
|
||||
});
|
||||
|
||||
it('correctly parse a location parameter', () => {
|
||||
window.location.search = '?survey=DSS';
|
||||
expect(Utils.urlParam('survey')).toEqual('DSS');
|
||||
});
|
||||
});
|
||||
45
tsconfig.json
Normal file
45
tsconfig.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
],
|
||||
"types": [
|
||||
"node",
|
||||
"vite/client",
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
],
|
||||
"typeRoots": [
|
||||
"node_modules/@types",
|
||||
"src/types"
|
||||
],
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
],
|
||||
"#/*": [
|
||||
"./tests/unit/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"tests/unit/**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
import { resolve } from 'path'
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
// plugins
|
||||
/// <reference types="vitest" />
|
||||
import * as path from 'path'
|
||||
import {resolve} from 'path'
|
||||
import {defineConfig} from 'vite';
|
||||
// For wasm inclusion
|
||||
import wasm from "vite-plugin-wasm";
|
||||
import topLevelAwait from "vite-plugin-top-level-await";
|
||||
// For wasm genrated by wasm-pack
|
||||
// For wasm generated by wasm-pack
|
||||
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'
|
||||
|
||||
@@ -41,7 +39,24 @@ export default defineConfig({
|
||||
}),
|
||||
cssInjectedByJsPlugin(),
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
{find: '@', replacement: path.resolve(__dirname, '/src')},
|
||||
{find: '#', replacement: path.resolve(__dirname, '/tests/unit')},
|
||||
{find: '$', replacement: path.resolve(__dirname, '/tests/e2e')}
|
||||
],
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'happy-dom',
|
||||
include: [
|
||||
'tests/unit/**/*.{test,spec}.{js,ts}'
|
||||
],
|
||||
deps: {
|
||||
inline: ['core/pkg'],
|
||||
},
|
||||
},
|
||||
server: {
|
||||
open: '/examples/index.html',
|
||||
},
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user