From 9c9ebb0ed11c87965974a3f8b0f6504bd5b343ff Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Wed, 18 Sep 2024 17:22:17 +0200 Subject: [PATCH] add sesame access in A.Utils + Aladin.remove that removes either an overlay or a layer --- CHANGELOG.md | 6 +- examples/al-vertices.html | 15 +++-- package.json | 2 +- src/core/src/lib.rs | 2 +- src/js/A.js | 44 +++++++------ src/js/Aladin.js | 33 ++++++---- src/js/AladinUtils.js | 23 +++++++ src/js/Catalog.js | 126 +++++++++++++++++++++++++++++++------- src/js/HiPS.js | 11 +++- src/js/MOC.js | 2 +- src/js/Sesame.js | 22 ++++--- src/js/View.js | 45 ++++++-------- 12 files changed, 230 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b54475c5c..a8135bf8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ # Changelogs -## [Unreleased] +## 3.5.1-beta * [feat] Add support for name removing in `removeOverlay` method * [test] Add support of playwright. Instructions in the readme for running the test matching snapshots [PR #176] -* [fixed] Order of overlays in the stack now matches the addMOC/addCatalog/addOverlay calls ordering +* [fix] Order of overlays in the stack now matches the addMOC/addCatalog/addOverlay calls ordering * [doc] Expose the API of Coo class * [fix] Insert aladin css inside the aladin lite so that it should be compliant with the use of shadow DOMs [cds-astro/ipyaladin#113], [marimo-team/marimo#2106] +* [feat] Add possibility of giving a local JS FileList to load a locally-stored HiPS without starting an HTTP server [cds-astro/aladin-lite#103] +* [fix] removeOverlayByName ## 3.5.0-beta diff --git a/examples/al-vertices.html b/examples/al-vertices.html index bd4167985..0219d64cb 100644 --- a/examples/al-vertices.html +++ b/examples/al-vertices.html @@ -11,10 +11,17 @@ A.init.then(() => { let vertices = A.Utils.HEALPix.vertices(Math.pow(2, 3), BigInt(276)) - //let lonlat = A.Utils.HEALPix.pix2ang(8, 0n) - //let ipix = A.Utils.HEALPix.ang2pix(8, 0.1, 0.4) - //console.log("vertices", vertices, lonlat, ipix) - console.log(vertices) + let lonlat = A.Utils.HEALPix.pix2ang(8, 0n) + let ipix = A.Utils.HEALPix.ang2pix(8, 0.1, 0.4) + console.log("vertices", vertices, lonlat, ipix) + + A.Utils.Sesame.resolveAstronomicalName("M101", (o) => { + console.log("object found", o) + }, + (err) => { + console.error("errr", err) + } + ) }) diff --git a/package.json b/package.json index 1383812b8..e7ca0a1da 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "homepage": "https://aladin.u-strasbg.fr/", "name": "aladin-lite", "type": "module", - "version": "3.5.1-alpha", + "version": "3.5.1-beta", "description": "An astronomical HiPS visualizer in the browser", "author": "Thomas Boch and Matthieu Baumann", "license": "GPL-3", diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index 312c25ffe..e3eb43035 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -1033,7 +1033,7 @@ impl WebClient { Ok(()) } - #[wasm_bindgen(js_name = addFITSMoc)] + #[wasm_bindgen(js_name = addFITSMOC)] pub fn add_fits_moc(&mut self, params: &al_api::moc::MOC, data: &[u8]) -> Result<(), JsValue> { //let bytes = js_sys::Uint8Array::new(array_buffer).to_vec(); let moc = match fits::from_fits_ivoa_custom(Cursor::new(&data[..]), false) diff --git a/src/js/A.js b/src/js/A.js index 075cfecbe..471b17ead 100644 --- a/src/js/A.js +++ b/src/js/A.js @@ -106,23 +106,18 @@ A.aladin = function (divSelector, options) { return new Aladin(divElement, options); }; -/** - * @function - * @name A.imageHiPS - * @memberof A - * @deprecated - * Old method name, use {@link A.HiPS} instead. - */ -A.imageHiPS = A.HiPS; - /** * Creates a HiPS image object * * @function * @name A.HiPS * @memberof A - * @param {string} id - Can be either an `url` that refers to a HiPS. - * Or it can be a "CDS ID" pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}. + * @param {string|FileList|Object} id - Can be:
+ * - an http url
+ * - a relative path to your HiPS
+ * - a special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}
+ * - a dict storing a local HiPS files. This object contains a tile file: hips[order][ipix] = File and refers to the properties file like so: hips["properties"] = File.
+ * A javascript FileList pointing to the opened webkit directory is also accepted. * @param {HiPSOptions} [options] - Options describing the survey * @returns {HiPS} - A HiPS image object */ @@ -138,6 +133,15 @@ A.HiPS = function (id, options) { ); } +/** + * @function + * @name A.imageHiPS + * @memberof A + * @deprecated + * Old method name, use {@link A.HiPS} instead. + */ + A.imageHiPS = A.HiPS; + /** * Creates a celestial source object with the given coordinates. * @@ -449,17 +453,19 @@ A.MOCFromURL = function (url, options, successCallback, errorCallback) { * @returns {MOC} Returns a new MOC object * * @example - * var json = {"3":[517], - * "4":[2065,2066,2067,2112,2344,2346,2432], - * "5":[8221,8257,8258,8259,8293,8304,8305,8307,8308,8452,8456,9346,9352,9354,9736], - * "6":[32861,32862,32863,32881,32882,32883,32892,32893,33025,33026,33027,33157,33168,33169,33171, + * var json = { + * "3": [517], + * "4": [2065,2066,2067,2112,2344,2346,2432], + * "5": [8221,8257,8258,8259,8293,8304,8305,8307,8308,8452,8456,9346,9352,9354,9736], + * "6": [32861,32862,32863,32881,32882,32883,32892,32893,33025,33026,33027,33157,33168,33169,33171, * 33181,33224,33225,33227,33236,33240,33812,33816,33828,33832,37377,37378,37379,37382,37388, * 37390,37412,37414,37420,37422,37562,38928,38930,38936,38948,38952], - * "7":[131423,131439,131443,131523,131556,131557,131580,131581,132099,132612,132613,132624,132625,132627,132637, + * "7": [131423,131439,131443,131523,131556,131557,131580,131581,132099,132612,132613,132624,132625,132627,132637, * 132680,132681,132683,132709,132720,132721,132904,132905,132948,132952,132964,132968,133008,133009,133012,135252,135256,135268,135316,135320,135332,135336,148143,148152,148154,149507,149520 - * ,149522,149523,149652,149654,149660,149662,149684,149686,149692,149694,149695,150120,150122,150208,150210,150216,150218,150240,150242,150243,155748,155752,155796,155800,155812,155816]}; + * ,149522,149523,149652,149654,149660,149662,149684,149686,149692,149694,149695,150120,150122,150208,150210,150216,150218,150240,150242,150243,155748,155752,155796,155800,155812,155816] + * }; * var moc = A.MOCFromJSON(json, {opacity: 0.25, color: 'magenta', lineWidth: 3}); - * aladin.addMOC(moc); + * aladin.addMOC(moc); */ A.MOCFromJSON = function (jsonMOC, options, successCallback, errorCallback) { var moc = new MOC(options); @@ -986,7 +992,7 @@ A.box = function(options) { } /** - * Returns utils object + * Returns Utils object. * * This contains utilitary methods such as HEALPix basic or projection methods. * diff --git a/src/js/Aladin.js b/src/js/Aladin.js index f828b170f..c1a5c036c 100644 --- a/src/js/Aladin.js +++ b/src/js/Aladin.js @@ -1462,7 +1462,7 @@ export let Aladin = (function () { * @memberof Aladin */ Aladin.prototype.removeOverlays = function () { - this.view.removeLayers(); + this.view.removeOverlays(); }; /** @@ -1497,10 +1497,6 @@ export let Aladin = (function () { Aladin.prototype.removeLayer = Aladin.prototype.removeOverlay; /** - * @deprecated - * Creates and return an image survey (HiPS) object - * Please use {@link A.hiPS} instead for creating a new survey image - * * @memberof Aladin * @param {string} id - Mandatory unique identifier for the survey. * @param {string} [name] - A convinient name for the survey, optional @@ -1533,10 +1529,6 @@ export let Aladin = (function () { }; /** - * @deprecated - * Creates and return an image survey (HiPS) object. - * Please use {@link A.hiPS} instead for creating a new survey image - * * @function createImageSurvey * @memberof Aladin * @static @@ -1655,7 +1647,6 @@ export let Aladin = (function () { * Please use {@link A.hiPS} instead for creating a new survey image * * @memberof Aladin - * @static * @param {string} id - Can be: * * @param {string} [layer="overlay"] - A layer name. By default 'overlay' is chosen and it is destined to be plot * on top the 'base' layer. If the layer is already present in the view, it will be replaced by the new HiPS/FITS image given here. diff --git a/src/js/AladinUtils.js b/src/js/AladinUtils.js index 33e68ab08..9c235bdcb 100644 --- a/src/js/AladinUtils.js +++ b/src/js/AladinUtils.js @@ -28,6 +28,7 @@ * *****************************************************************************/ import { Aladin } from "./Aladin"; +import { Sesame } from "./Sesame"; /** * @namespace AladinUtils @@ -145,6 +146,28 @@ export let AladinUtils = { } }, + /** + * @namespace Sesame + * @memberof AladinUtils + * @description Namespace for Sesame related service. + */ + Sesame: { + /** + * find RA, DEC for any target (object name or position)
+ * if successful, callback is called with an object {ra: ra-value, dec: dec-value}
+ * if not successful, errorCallback is called + * + * @function + * @memberof AladinUtils.Sesame + * @name resolveAstronomicalName + * + * @param {string} target - object name or position + * @param {Function} callback - if successful, callback is called with an object {ra: , dec: } + * @param {Function} errorCallback - if not successful, errorCallback is called + */ + resolveAstronomicalName: Sesame.getTargetRADec + }, + /** * @deprecated * diff --git a/src/js/Catalog.js b/src/js/Catalog.js index 433c1c8df..156133e60 100644 --- a/src/js/Catalog.js +++ b/src/js/Catalog.js @@ -79,7 +79,9 @@ export let Catalog = (function () { * markerSize: 15, * shape: "circle", * limit: 1000, - * onClick: (source) => { /* handle source click * }, + * onClick: (source) => { + * // handle sources + * }, * readOnly: true, * raField: "ra", * decField: "dec", @@ -575,17 +577,6 @@ export let Catalog = (function () { this.reportChange(); }; - /*Catalog.prototype.addFootprints = function(footprintsToAdd) { - footprintsToAdd = [].concat(footprintsToAdd); // make sure we have an array and not an individual footprints - this.footprints = this.footprints.concat(footprintsToAdd); - - footprintsToAdd.forEach(f => { - f.setCatalog(this); - }) - - this.reportChange(); - };*/ - Catalog.prototype.computeFootprints = function (sources) { let footprints = []; @@ -635,12 +626,14 @@ export let Catalog = (function () { this.showFieldCallback[field] = callback; }; - // API - // - // create sources from a 2d array and add them to the catalog - // - // @param columnNames: array with names of the columns - // @array: 2D-array, each item being a 1d-array with the same number of items as columnNames + /** + * Create sources from a 2d array and add them to the catalog + * + * @memberof Catalog + * + * @param {String[]} columnNames - array with names of the columns + * @param {String[][]|number[][]} array - 2D-array, each item being a 1d-array with the same number of items as columnNames + */ Catalog.prototype.addSourcesAsArray = function (columnNames, array) { var fields = []; for (var colIdx = 0; colIdx < columnNames.length; colIdx++) { @@ -682,7 +675,13 @@ export let Catalog = (function () { this.addSources(newSources); }; - // return the current list of Source objects + /** + * Get all the sources + * + * @memberof Catalog + * + * @returns {Source[]} - an array of all the sources in the catalog object + */ Catalog.prototype.getSources = function () { return this.sources; }; @@ -691,7 +690,11 @@ export let Catalog = (function () { return this.footprints; }; - // TODO : fonction générique traversant la liste des sources + /** + * Select all the source catalog + * + * @memberof Catalog + */ Catalog.prototype.selectAll = function () { if (!this.sources) { return; @@ -702,6 +705,11 @@ export let Catalog = (function () { } }; + /** + * Unselect all the source of the catalog + * + * @memberof Catalog + */ Catalog.prototype.deselectAll = function () { if (!this.sources) { return; @@ -712,7 +720,15 @@ export let Catalog = (function () { } }; - // return a source by index + /** + * Get one source by its index in the catalog + * + * @memberof Catalog + * + * @param {number} idx - the index of the source in the catalog sources + * + * @returns {Source} - the source at the index + */ Catalog.prototype.getSource = function (idx) { if (idx < this.sources.length) { return this.sources[idx]; @@ -730,37 +746,86 @@ export let Catalog = (function () { this.reportChange(); }; + /** + * Set the color of the catalog + * + * @memberof Catalog + * + * @param {String} - the new color + */ Catalog.prototype.setColor = function (color) { this.color = color; this.updateShape(); }; + /** + * Set the color of selected sources + * + * @memberof Catalog + * + * @param {String} - the new color + */ Catalog.prototype.setSelectionColor = function (color) { this.selectionColor = color; this.updateShape(); }; + /** + * Set the color of hovered sources + * + * @memberof Catalog + * + * @param {String} - the new color + */ Catalog.prototype.setHoverColor = function (color) { this.hoverColor = color; this.updateShape(); }; + /** + * Set the size of the catalog sources + * + * @memberof Catalog + * + * @param {number} - the new size + */ Catalog.prototype.setSourceSize = function (sourceSize) { // will be discarded in updateShape if the shape is an Image this.sourceSize = sourceSize; this.updateShape(); }; + /** + * Set the color of the catalog + * + * @memberof Catalog + * + * @param {string|Function|HTMLImageCanvas|HTMLImageElement} [shape="square"] - the type of the shape. Can be square, rhomb, plus, cross, triangle, circle. + * A callback function can also be called that return an HTMLImageElement in function of the source object. A canvas or an image can also be given. + */ Catalog.prototype.setShape = function (shape) { this.shape = shape; this.updateShape(); }; + /** + * Get the size of the catalog sources + * + * @memberof Catalog + * + * @returns {number} - the size of the sources + */ Catalog.prototype.getSourceSize = function () { return this.sourceSize; }; - // remove a source + /** + * Remove a specific source from the catalog + * + * @memberof Catalog + * + * @param {Source} - the source to remove + */ Catalog.prototype.remove = function (source) { var idx = this.sources.indexOf(source); if (idx < 0) { @@ -778,12 +843,19 @@ export let Catalog = (function () { this.reportChange(); }; + /** + * Clear all the sources from the catalog + * + * @memberof Catalog + */ Catalog.prototype.removeAll = Catalog.prototype.clear = function () { // TODO : RAZ de l'index this.sources = []; this.ra = []; this.dec = []; this.footprints = []; + + this.reportChange(); }; Catalog.prototype.draw = function (ctx, width, height) { @@ -929,6 +1001,11 @@ export let Catalog = (function () { this.view && this.view.requestRedraw(); }; + /** + * Show the catalog + * + * @memberof Catalog + */ Catalog.prototype.show = function () { if (this.isShowing) { return; @@ -942,6 +1019,11 @@ export let Catalog = (function () { this.reportChange(); }; + /** + * Hide the catalog + * + * @memberof Catalog + */ Catalog.prototype.hide = function () { if (!this.isShowing) { return; diff --git a/src/js/HiPS.js b/src/js/HiPS.js index 90f10e1d0..dffc5f298 100644 --- a/src/js/HiPS.js +++ b/src/js/HiPS.js @@ -153,6 +153,12 @@ PropertyParser.isPlanetaryBody = function (properties) { * @property {number} [brightness=0.0] - The brightness value for the color configuration. * @property {number} [contrast=0.0] - The contrast value for the color configuration. */ + +/** + * @typedef {Object} FileList + * + * JS {@link https://developer.mozilla.org/fr/docs/Web/API/FileList| FileList} API type + */ export let HiPS = (function () { /** * The object describing an image survey @@ -164,8 +170,9 @@ export let HiPS = (function () { * @param {string|FileList|Object} location - Can be: * - an http url
* - a relative path to your HiPS
- * - a special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here} - * - a dict storing a local HiPS. This object contains a tile file: hips[order][ipix] = and refers to the properties file like so: hips["properties"] = . A javascript FileList pointing to the opened webkit directory is also accepted. + * - a special ID pointing towards a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}
+ * - a dict storing a local HiPS. This object contains a tile file: hips[order][ipix] = File and refers to the properties file like so: hips["properties"] = File.
+ * A javascript FileList pointing to the opened webkit directory is also accepted. * @param {HiPSOptions} [options] - The option for the survey * * @description Giving a CDS ID will do a query to the MOCServer first to retrieve metadata. Then it will also check for the presence of faster HiPS nodes to choose a faster url to query to tiles from. diff --git a/src/js/MOC.js b/src/js/MOC.js index ce6ced78d..b919d5a84 100644 --- a/src/js/MOC.js +++ b/src/js/MOC.js @@ -134,7 +134,7 @@ export let MOC = (function() { if (data instanceof ArrayBuffer) { // from an url const buf = data; - self.view.wasm.addFITSMoc(self.mocParams, new Uint8Array(buf)); + self.view.wasm.addFITSMOC(self.mocParams, new Uint8Array(buf)); } else if(data.ra && data.dec && data.radius) { // circle const c = data; diff --git a/src/js/Sesame.js b/src/js/Sesame.js index fd4dd9fcf..a11308cc1 100644 --- a/src/js/Sesame.js +++ b/src/js/Sesame.js @@ -62,16 +62,18 @@ export let Sesame = (function() { // ask resolution by Sesame else { Sesame.resolve(target, - function(data) { // success callback - callback({ra: data.Target.Resolver.jradeg, - dec: data.Target.Resolver.jdedeg}); - }, - - function(data) { // error callback - if (errorCallback) { - errorCallback(); - } - } + function(data) { // success callback + callback({ + ra: data.coo.jradeg, + dec: data.coo.jdedeg + }); + }, + + function(data) { // error callback + if (errorCallback) { + errorCallback(data); + } + } ); } }; diff --git a/src/js/View.js b/src/js/View.js index 7579859f0..76a460f27 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -1291,33 +1291,25 @@ export let View = (function () { const now = performance.now(); const elapsedTime = now - this.then; this.dt = elapsedTime; - // If enough time has elapsed, draw the next frame - //if (elapsedTime >= View.FPS_INTERVAL) { - // Get ready for next frame by setting then=now, but also adjust for your - // specified fpsInterval not being a multiple of RAF's interval (16.7ms) - //if (this.dt > 10) - // console.log(this.dt) - // Drawing code - //try { - this.moving = this.wasm.update(elapsedTime); - - // inertia run throttled position - if (this.moving && this.aladin.callbacksByEventName && this.aladin.callbacksByEventName['positionChanged'] && this.wasm.isInerting()) { - // run the trottled position - this.throttledPositionChanged(false); - } - ////// 2. Draw catalogues//////// - const isViewRendering = this.wasm.isRendering(); - if (isViewRendering || this.needRedraw) { - this.drawAllOverlays(); - } - this.needRedraw = false; + this.moving = this.wasm.update(elapsedTime); + + // inertia run throttled position + if (this.moving && this.aladin.callbacksByEventName && this.aladin.callbacksByEventName['positionChanged'] && this.wasm.isInerting()) { + // run the trottled position + this.throttledPositionChanged(false); + } - this.then = now; - //this.then = now % View.FPS_INTERVAL; - requestAnimFrame(this.redrawClbk); - //} + ////// 2. Draw catalogues//////// + const isViewRendering = this.wasm.isRendering(); + if (isViewRendering || this.needRedraw) { + this.drawAllOverlays(); + } + this.needRedraw = false; + + this.then = now; + //this.then = now % View.FPS_INTERVAL; + requestAnimFrame(this.redrawClbk); }; View.prototype.drawAllOverlays = function () { @@ -2044,7 +2036,7 @@ export let View = (function () { return false; }; - View.prototype.removeLayers = function () { + View.prototype.removeOverlays = function () { this.catalogs = []; this.overlays = []; this.mocs = []; @@ -2094,7 +2086,6 @@ export let View = (function () { View.prototype.removeOverlayByName = function (overlayName) { let overlay = this.allOverlayLayers.find(o => o.name === overlayName); - console.log("jkj", overlay) if (!overlay) { console.error(`Overlay "${overlayName}" not found.`); return;