Compare commits

...

25 Commits

Author SHA1 Message Date
Matthieu Baumann
bc1096fce3 Aladin lite: v3.2.0
Features:
- The use of vite as a project manager
- Enhance the MOC rendering perf and add possibility to draw the perimeter
- Many fixes such as the footprints rendering for all sky projections
- A line rasterizer enabling the thickness' grid line changes
2023-08-13 14:10:44 +02:00
Matthieu Baumann
7d5696228d remove engines in package json 2023-08-12 19:14:44 +02:00
Matthieu Baumann
08699a9bd5 Merge branch 'develop' into develop 2023-08-12 19:00:28 +02:00
Matthieu Baumann
fc6a09e373 Fix rebase 2023-08-12 15:26:54 +02:00
Matthieu Baumann
a8a86a2952 Merge branch 'develop' into develop 2023-08-12 15:18:38 +02:00
Matthieu Baumann
cc958bfa2d Corrected ESASky link in README
Redo PR #104 commit directly on develop

Co-authored-by: imbasimba <https://www.henriknorman.com>
2023-08-12 15:06:13 +02:00
Matthieu Baumann
6c4ddce6b0 Merge pull request #113 from cds-astro/features/lineRasterizer
Features/line rasterizer
2023-08-12 15:04:17 +02:00
onekiloparsec
c1b2bd24b9 Reverting the insertion of /.idea into the gitignore.
It can be anaged individually.
2023-08-03 13:31:34 +02:00
Manon
46573a23da fix draw 2023-08-01 10:08:15 +02:00
Cédric Foellmi
121f4345bc Update src/js/gui/ContextMenu.js
Fixed the missing canvas parameter of the refactored `relMouseCoords` function.

Co-authored-by: Matthieu Baumann <baumannmatthieu0@gmail.com>
2023-07-19 04:01:47 +02:00
Cédric Foellmi
0665f2b65f Update src/js/View.js
Fixed the missing canvas parameter of the refactored `relMouseCoords` function.

Co-authored-by: Matthieu Baumann <baumannmatthieu0@gmail.com>
2023-07-19 04:01:38 +02:00
Cédric Foellmi
a58fb1dd8a Update src/js/View.js
Fixed the missing canvas parameter of the refactored `relMouseCoords` function.

Co-authored-by: Matthieu Baumann <baumannmatthieu0@gmail.com>
2023-07-19 04:01:29 +02:00
Cédric Foellmi
466472a1a7 Update src/js/View.js
Fixed the missing canvas parameter of the refactored `relMouseCoords` function.

Co-authored-by: Matthieu Baumann <baumannmatthieu0@gmail.com>
2023-07-19 04:01:14 +02:00
Cédric Foellmi
540f4e33be Update src/js/View.js
Fixed the missing canvas parameter of the refactored `relMouseCoords` function.

Co-authored-by: Matthieu Baumann <baumannmatthieu0@gmail.com>
2023-07-19 04:01:04 +02:00
Cédric Foellmi
0b92b6d1db Update src/js/GenericPointer.js
Fixed the missing canvas parameter of the refactored `relMouseCoords` function.

Co-authored-by: Matthieu Baumann <baumannmatthieu0@gmail.com>
2023-07-19 04:00:38 +02:00
Cédric Foellmi
06dcc126f9 Fixed import
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
04e552b7c3 Making a first test passing!
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
1bee9c8b77 Ignoring .idea (PyCharm/WebStorm)
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
c77f2aeda8 Making a dedicated dependency-free Constants file to avoid Utils import Aladin.js!
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
57c1b8423d Linting
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
ebf2d06f31 Using the Utils methods also in the examples
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
5d0ec40612 Fixing imports
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
82b2eb0423 Using the new Utils method
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:16 +02:00
Cédric Foellmi
2dc6f17c7d Renaming Utils.js into Utils.ts and correcting related imports.
Note that the content of Utils.ts has also been changed. More pecisely:

- `relMouseCoords` has been set as a function of the Utils object, to avoid attaching it to canvas prototype. This was very custom way of doing, and makes testing very complicated to run, while providing no real value.

- Removed the jQuery dependency and made `urlParam` a function of the Utils object.

- Added some types when possible / easy. But TS already reveal the misuse of some function sur as `parseInt` and `parseFloat` (which act on strings, not numbers)

Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:11:15 +02:00
Cédric Foellmi
402e270015 Introducing typescript & vitest
In order to push upward the code quailty of the Javascript code, I propose to introduce Typescript and Vitest for writing unit tests.

This first commit simply introduce the right dependencies and configuration.

Note the presence of “happy-dom” dev dep for manipulating the window object (which is involved in the first test written on Utils).

Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
2023-07-18 12:07:21 +02:00
39 changed files with 574 additions and 511 deletions

View File

@@ -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
View File

@@ -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

View File

@@ -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/).

View File

@@ -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 });
@@ -495,7 +497,7 @@
deleteOverlayTimeout = undefined;
}
isDrawing = true;
points.push([drawOverlayCanvas.relMouseCoords(e)]);
points.push([Utils.relMouseCoords(drawOverlayCanvas.imageCanvas, e)]);
});
@@ -504,7 +506,7 @@
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();

View File

@@ -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",
@@ -39,16 +39,20 @@
"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",

View File

@@ -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"

View File

@@ -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";
@@ -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();
}
}

View File

@@ -31,7 +31,7 @@
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";

View File

@@ -28,7 +28,7 @@
*
*****************************************************************************/
import { Utils } from "./Utils.js";
import { Utils } from "./Utils";
import { AladinUtils } from "./AladinUtils.js";
import { Overlay } from "./Overlay.js";

1
src/js/Constants.ts Normal file
View File

@@ -0,0 +1 @@
export const JSONP_PROXY = "https://alaskybis.cds.unistra.fr/cgi/JSONProxy";

View File

@@ -28,7 +28,7 @@
*
*****************************************************************************/
import { Utils } from "./Utils.js";
import { Utils } from "./Utils";
import { AladinUtils } from "./AladinUtils.js";
import { Overlay } from "./Overlay.js";

View File

@@ -34,7 +34,7 @@
*****************************************************************************/
import { AladinUtils } from './AladinUtils.js';
import { Utils } from './Utils.js';
import { Utils } from './Utils';
export let Footprint= (function() {
// constructor

View File

@@ -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.");
}
}
)
)

View File

@@ -28,7 +28,7 @@
*
*****************************************************************************/
import { Utils } from "./Utils.js";
import { Utils } from "./Utils";
import $ from 'jquery';
export let HiPSDefinition = (function() {

View File

@@ -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));
}
}

View File

@@ -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 () {

View File

@@ -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";

View File

@@ -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() {

View File

@@ -17,7 +17,7 @@
// along with Aladin Lite.
//
import { Utils } from "./Utils.js";
import { Utils } from "./Utils";
/******************************************************************************

View File

@@ -30,7 +30,7 @@
*
*****************************************************************************/
import { Utils } from './Utils.js';
import { Utils } from './Utils';
import A from "./A.js";

View File

@@ -28,7 +28,7 @@
*
*****************************************************************************/
import { Utils } from "./Utils.js";
import { Utils } from "./Utils";
import $ from 'jquery';

View File

@@ -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() {

View File

@@ -35,7 +35,7 @@
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";

View File

@@ -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';

View File

@@ -28,7 +28,7 @@
*
*****************************************************************************/
import { Utils } from "./Utils.js";
import { Utils } from "./Utils";
import $ from 'jquery';

View File

@@ -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() {

View File

@@ -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 = {

View File

@@ -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
View 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()
}

View File

@@ -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";
@@ -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()
@@ -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;
@@ -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);
@@ -766,7 +766,7 @@ 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'];

View File

@@ -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';

View File

@@ -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,7 +101,7 @@ 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));
}
}
@@ -115,9 +111,9 @@ export class ContextMenu {
this.contextMenuUl.className = 'aladin-context-menu';
this.contextMenuUl.innerHTML = '';
const xymouse = this.aladin.view.imageCanvas.relMouseCoords(e);
const xymouse = Utils.relMouseCoords(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 +150,6 @@ export class ContextMenu {
}
attachTo(el, options) {
this.contextMenuUl = document.createElement('ul');
this.menuOptions = options;

View File

@@ -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';

View File

@@ -30,7 +30,7 @@
*****************************************************************************/
import { VOTable } from "./VOTable.js";
import { Utils } from './../Utils.js';
import { Utils } from './../Utils';
export let Datalink = (function() {

View File

@@ -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;
})();

View File

@@ -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
View 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
View 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"
]
}

View File

@@ -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',
},
});
});