diff --git a/examples/ObsCore_003.xml b/examples/ObsCore_003.xml new file mode 100644 index 00000000..0ad292ed --- /dev/null +++ b/examples/ObsCore_003.xml @@ -0,0 +1,212 @@ + + + Mockup SKA discovery service response VOTable + + + ska.srcnet.resp/sia~1 SKA data discovery service from Italian node + + + calibration level (0,1,2,3) + + + RA of central coordinates + + + DEC of central coordinates + + + size of the region covered (~diameter of minimum bounding circle) + + + region bounded by observation + + + publisher dataset identifier + + + short name for the data colection + + + telescope name + + + instrument name + + + internal dataset identifier + + + type of product + + + free sub type of product + + + timestamp of date the data becomes publicly available + + + name of intended target + + + typical spatial resolution + + + dimensions (number of pixels) along one spatial axis + + + dimensions (number of pixels) along the other spatial axis + + + start time of observation (MJD) + + + end time of observation (MJD) + + + exposure time of observation + + + typical temporal resolution + + + dimensions (number of pixels) along the time axis + + + start spectral coordinate value + + + stop spectral coordinate value + + + typical spectral resolution + + + dimensions (number of pixels) along the energy axis + + + dimensions (number of pixels) along the polarization axis + + + URL to download the data + + + estimated size of the download + + + + polarization states present in the data + + + UCD describing the observable axis (pixel values) + + + format of the data file(s) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
3214.956.70.2polygon 215.92 56.25 214.03 56.25 214.03 57.34 215.92 57.34ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3APERTIF_DR1wsrtApertif200104010cubeHI_spectral_cubes2020-01-04T06:38:21ZNGC 55850.466166161416.355687561416.35637652777559.5750.112180.2110.21770000001000004https://raw.githubusercontent.com/VisIVOLab/SKA-Discovery-Service-Mockup/main/DataLink/DataLink_003.xml2128688640I Q U Vphot.flux.density;phys.polarizationapplication/x-votable+xml;content=datalink
3214.956.70.2polygon 215.92 56.25 214.03 56.25 214.03 57.34 215.92 57.34ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3APERTIF_DR1wsrtApertif200104010cubeHI_spectral_cubes2020-01-04T06:38:21ZNGC 55850.466166161416.355687561416.35637652777559.5750.112180.2110.21770000001000004https://raw.githubusercontent.com/VisIVOLab/SKA-Discovery-Service-Mockup/main/DataLink/DataLink_003.xml2128688640I Q U Vphot.flux.density;phys.polarizationapplication/x-votable+xml;content=datalink
+
+
diff --git a/examples/al-obscore.html b/examples/al-obscore.html new file mode 100644 index 00000000..0ce6b449 --- /dev/null +++ b/examples/al-obscore.html @@ -0,0 +1,21 @@ + + + + + + +
+
+ + + + + diff --git a/examples/al-stcs-footprints.html b/examples/al-stcs-footprints.html index b5a19e8b..b015f063 100644 --- a/examples/al-stcs-footprints.html +++ b/examples/al-stcs-footprints.html @@ -18,6 +18,8 @@ aladin.addCatalog(A.catalogFromURL('https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/data/alma-footprints.xml', {}, function(sources) { sources.forEach(source => { + console.log(A.footprintsFromSTCS(source.data['s_region'])) + overlay.addFootprints(A.footprintsFromSTCS(source.data['s_region'])) }); })); diff --git a/examples/datalink.xml b/examples/datalink.xml new file mode 100644 index 00000000..0e168000 --- /dev/null +++ b/examples/datalink.xml @@ -0,0 +1,99 @@ + + Mockup SKA discovery service response VOTable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3https://vo.astron.nl/getproduct/APERTIF_DR1/200110007_AP_B037/HI_image_cube3.fits + + #thisThe full datasetimage/fits2128688640cube
ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3https://alasky.cds.unistra.fr/hips-cube-services/compute/hips:httpsalasky.cds.unistra.fr;SKA-demo;hips;APERTIF;HiPS_APERTIF_cube_NGC5585-cubic-tiles%7Cexpr:s0_1211 + + #derivedMoment zero map of the cube (in HiPS format)application/hips2128688640image
ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3https://alasky.cds.unistra.fr/hips-cube-services/compute/hips:httpsalasky.cds.unistra.fr;SKA-demo;hips;APERTIF;HiPS_APERTIF_cube_NGC5585-cubic-tiles%7Cexpr:s345_410-(s0_1211;24) + + #derivedHI Line map derived from the cube (in HiPS format)application/hips2128688640image
ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3https://alasky.cds.unistra.fr/hips-cube-services/color/hips:httpsalasky.cds.unistra.fr;SKA-demo;hips;APERTIF;HiPS_APERTIF_cube_NGC5585%7Cblue:345-365%7Cgreen:365-385%7Cred:385-405 + + #derivedvelocity variation color map derived from the cube (in HiPS format)application/hips2128688640image
ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3 + soda-HiPS + #cutoutSODA-HiPS cutout of moment zero map of ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3image/fits +
ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3 + soda-sync + #cutoutSODA-sync cutout of ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3image/fits +
ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3 + soda-async + #cutoutSODA-async cutout of ivo://SKA/SrcNet/APERTIF_DR1/200110007_AP_B037/HI_image_cube3image/fits +
+
+
\ No newline at end of file diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index 1c21a9b5..5a7fd486 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -569,9 +569,9 @@ impl WebClient { /// * `lon` - A longitude in degrees /// * `lat` - A latitude in degrees #[wasm_bindgen(js_name = worldToScreen)] - pub fn world_to_screen(&self, lon: f64, lat: f64) -> Option> { + pub fn world_to_screen(&self, lon: f64, lat: f64) -> Option> { self.app.world_to_screen(lon, lat) - .map(|v| Box::new([v.x, v.y]) as Box<[f64]>) + .map(|v| Box::new([v.x as i32, v.y as i32]) as Box<[i32]>) } /// Screen to world unprojection @@ -820,7 +820,7 @@ impl WebClient { #[wasm_bindgen(js_name = parseVOTable)] pub fn parse_votable(&mut self, s: &str) -> Result { let votable: VOTableWrapper = votable::votable::VOTableWrapper::from_ivoa_xml_str(s) - .map_err(|_| JsValue::from_str("Error parsing votable"))?; + .map_err(|err| JsValue::from_str(&format!("Error parsing votable: {:?}", err)))?; let votable = serde_wasm_bindgen::to_value(&votable) .map_err(|_| JsValue::from_str("cannot convert votable to js type"))?; diff --git a/src/css/aladin.css b/src/css/aladin.css index 8921e694..958a81b9 100644 --- a/src/css/aladin.css +++ b/src/css/aladin.css @@ -2,9 +2,11 @@ position: relative; border: 1px solid #ddd; height: 100%; - /*overflow: hidden;*/ -} + /* disable x swipe on chrome, firefox */ + /* see. https://stackoverflow.com/questions/30636930/disable-web-page-navigation-on-swipeback-and-forward */ + overscroll-behavior-x: none; +} .aladin-imageCanvas { position: absolute; @@ -89,19 +91,31 @@ } .aladin-measurement-div { + background-color: rgba(255, 255, 255, 0.8); + z-index: 77; position:absolute; bottom: 20px; - background-color: rgba(255, 255, 255, 0.8); font-family: monospace; font-size: 12px; display: none; width: 100%; overflow: auto; + /* Allow scrolling but disable scroll bar */ + -ms-overflow-style: none; /* for Internet Explorer, Edge */ + scrollbar-width: none; /* for Firefox */ + overflow-y: scroll; + + /* disable x swipe on chrome, firefox */ + overscroll-behavior-x: none; +} + +.aladin-measurement-div::-webkit-scrollbar { + display: none; /* for Chrome, Safari, and Opera */ } .aladin-measurement-div table { - padding: 2px 4px 2px 4px; + table-layout: fixed; white-space: nowrap; } @@ -221,10 +235,6 @@ word-wrap:break-word; overflow-y: auto; } -element { - -} - .aladin-box { display: none; z-index: 30; diff --git a/src/js/Aladin.js b/src/js/Aladin.js index 7378cd1c..047394ab 100644 --- a/src/js/Aladin.js +++ b/src/js/Aladin.js @@ -68,6 +68,7 @@ import $ from 'jquery'; // Import aladin css inside the project import './../css/aladin.css'; +import { VOTable } from "./vo/VOTable.js"; export let Aladin = (function () { @@ -1832,8 +1833,8 @@ Aladin.prototype.setReduceDeformations = function (reduce) { } // API -A.footprintsFromSTCS = function (stcs) { - var footprints = Overlay.parseSTCS(stcs); +A.footprintsFromSTCS = function (stcs, options) { + var footprints = Overlay.parseSTCS(stcs, options); return footprints; } @@ -1861,8 +1862,25 @@ A.catalogFromURL = function (url, options, successCallback, useProxy) { var catalog = A.catalog(options); Catalog.parseVOTable( url, - function (sources) { + function (sources, footprints, fields) { + if (fields["access_url"]) { + // It is an obsore table pointing to a datalink table + catalog.addFieldClickCallback("access_url", (url) => { + VOTable.parse( + "./examples/datalink.xml", + (fields, rows) => { + let sources = []; + let footprints = []; + + console.log(fields, rows) + } + ) + }); + } + + catalog.addFootprints(footprints) catalog.addSources(sources); + if (successCallback) { successCallback(sources); } @@ -1875,24 +1893,6 @@ A.catalogFromURL = function (url, options, successCallback, useProxy) { return catalog; }; -A.obscoreFromURL = function (url, options, successCallback, useProxy) { - options = options.color || Obscore.COLOR; - let catalog = A.catalog(options); - - Obscore.parseVOTable( - url, - function (sources) { - catalog.addSources(sources); - - if (successCallback) { - successCallback(sources); - } - } - ); - - return catalog; -}; - // API // @param target: can be either a string representing a position or an object name, or can be an object with keys 'ra' and 'dec' (values being in decimal degrees) A.catalogFromSimbad = function (target, radius, options, successCallback) { diff --git a/src/js/Catalog.js b/src/js/Catalog.js index 8a04025e..7d4ff4db 100644 --- a/src/js/Catalog.js +++ b/src/js/Catalog.js @@ -35,6 +35,7 @@ import { Utils } from "./Utils.js"; import { AladinUtils } from "./AladinUtils.js"; import { Coo } from "./libs/astro/coo.js"; import { ALEvent } from "./events/ALEvent.js"; +import { Obscore } from "./vo/Obscore.js"; import { VOTable } from "./vo/VOTable.js"; import $ from 'jquery'; @@ -60,11 +61,11 @@ export let Catalog = (function() { 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 + this.fieldsClickCallbacks = {}; // callbacks when the user clicks on a cell in the measurement table associated + this.indexationNorder = 5; // à quel niveau indexe-t-on les sources this.sources = []; this.footprints = []; - //this.hpxIdx = new HealpixIndex(this.indexationNorder); - //this.hpxIdx.init(); this.displayLabel = options.displayLabel || false; this.labelColor = options.labelColor || this.color; @@ -266,149 +267,92 @@ export let Catalog = (function() { }; + Catalog.parseFields = function(fields, raField, decField) { + // This votable is not an obscore one + let [raFieldIdx, decFieldIdx] = findRADecFields(fields, raField, decField); + + let parsedFields = {}; + let fieldIdx = 0; + fields.forEach((field) => { + let key = field.name ? field.name : field.id; + + let nameField; + if (fieldIdx == raFieldIdx) { + nameField = 'ra'; + } else if (fieldIdx == decFieldIdx) { + nameField = 'dec'; + } else { + nameField = key; + } + + parsedFields[nameField] = { + name: key, + idx: fieldIdx, + }; + + fieldIdx++; + }) + + return parsedFields; + }; + // return an array of Source(s) from a VOTable url // callback function is called each time a TABLE element has been parsed Catalog.parseVOTable = function(url, callback, maxNbSources, useProxy, raField, decField) { - /* - // adapted from votable.js - function getPrefix($xml) { - var prefix; - // If Webkit chrome/safari/... (no need prefix) - if($xml.find('RESOURCE').length>0) { - prefix = ''; - } - else { - // Select all data in the document - prefix = $xml.find("*").first(); + VOTable.parse( + url, + (fields, rows) => { + let sources = []; + let footprints = []; - if (prefix.length==0) { - return ''; - } + rows.every(row => { + let ra, dec, region; + var mesures = {}; - // get name of the first tag - prefix = prefix.prop("tagName"); + for (const [fieldName, field] of Object.entries(fields)) { + if (fieldName === 's_region') { + // Obscore s_region param + region = row[field.idx]; + } else if (fieldName === 'ra' || fieldName === 's_ra') { + ra = row[field.idx] + } else if (fieldName === 'dec' || fieldName === 's_dec') { + dec = row[field.idx] + } - var idx = prefix.indexOf(':'); - - prefix = prefix.substring(0, idx) + "\\:"; - - - } - - return prefix; - } - - function doParseVOTable(xml, callback) { - xml = xml.replace(/^\s+/g, ''); // we need to trim whitespaces at start of document - var attributes = ["name", "ID", "ucd", "utype", "unit", "datatype", "arraysize", "width", "precision"]; - - var fields = []; - var k = 0; - var $xml = $($.parseXML(xml)); - var prefix = getPrefix($xml); - $xml.find(prefix + "FIELD").each(function() { - var f = {}; - for (var i=0; i { - let sources = []; - votable.votable.get("resources") - .forEach((resource) => { - let tables = resource.get("tables") - tables.forEach((table) => { - let fields = table.get("elems") - .map((field) => { - // convert a map into a javascript object - return Object.fromEntries(field); - }) - - var raDecFieldIdxes = findRADecFields(fields, raField, decField); - const raFieldIdx = raDecFieldIdxes[0]; - const decFieldIdx = raDecFieldIdxes[1]; - - let data = table.get("data"); - let rows = data.get("rows"); - - rows.every(row => { - var mesures = {}; - - let idxField = 0; - for (const field of fields) { - var key = field.name ? field.name : field.id; - - mesures[key] = row[idxField]; - idxField += 1; - } - - const ra = row[raFieldIdx]; - const dec = row[decFieldIdx]; - - sources.push(new Source(ra, dec, mesures)); - if (maxNbSources && sources.length == maxNbSources) { - return false; - } - - return true; - }) - }) - }); - - if (callback) { - callback(sources); - } - }) + }, + raField, + decField + ) }; + Catalog.prototype.addFieldClickCallback = function(field, callback) { + this.fieldsClickCallbacks[field] = callback; + } + // API Catalog.prototype.updateShape = function(options) { options = options || {}; @@ -557,13 +501,7 @@ export let Catalog = (function() { if (this._shapeIsFunction) { ctx.save(); } - /*var sourcesInView = []; - for (var k=0, len = this.sources.length; k { + f.draw(ctx, this.view) + }); + }; + + // callback function to be called when the status of one of the sources has changed Catalog.prototype.reportChange = function() { this.view && this.view.requestRedraw(); diff --git a/src/js/MeasurementTable.js b/src/js/MeasurementTable.js index 05649870..d9de296f 100644 --- a/src/js/MeasurementTable.js +++ b/src/js/MeasurementTable.js @@ -43,6 +43,8 @@ export let MeasurementTable = (function() { this.numPages = 1; this.numRowsByPage = 5; + this.columnClickAction = {}; + $(aladinLiteDiv).append(this.divEl); } @@ -51,7 +53,21 @@ export let MeasurementTable = (function() { rows.forEach(row => { tbody += '' for (let key in row.data) { - tbody += '' + row.data[key] + ''; + // check the type here + const val = row.data[key]; + tbody += '' + if (typeof(val) === "string") { + try { + let url = new URL(val); + let link = '' + url + ''; + tbody += link; + } catch(e) { + tbody += val + } + } else { + tbody += val + } + tbody += '' } tbody += ''; }); @@ -67,13 +83,27 @@ export let MeasurementTable = (function() { let tbody = this.divEl[0].querySelector(".content"); tbody.innerHTML = MeasurementTable.updateBodyTable(fullRows.slice(rowIdxStart, rowIdxStart + this.numRowsByPage)); + if (this.fieldsClickCallbacks) { + Object.entries(this.fieldsClickCallbacks) + .forEach(([key, callback]) => { + this.divEl[0].querySelectorAll("." + key).forEach((e) => { + e.addEventListener('click', (e) => { + callback(e.target.innerText) + + e.preventDefault(); + }, false) + }) + }); + } + // recompute page idx let pageIdxElt = this.divEl[0].querySelector("#pageIdx"); pageIdxElt.innerHTML = '

' + this.curPage + '/' + this.numPages + '

'; } // show measurement associated with a given source - MeasurementTable.prototype.showMeasurement = function(rows) { + MeasurementTable.prototype.showMeasurement = function(rows, table) { + this.fieldsClickCallbacks = table.fieldsClickCallbacks; // compute the number of pages this.numPages = Math.floor(rows.length / this.numRowsByPage); if (rows.length % this.numRowsByPage > 0) { @@ -89,13 +119,25 @@ export let MeasurementTable = (function() { thead += ''; let tbody = MeasurementTable.updateBodyTable(rows.slice(0, this.numRowsByPage)); - this.divEl.append('' + thead + tbody + '
'); + // Add the callbacks to the cells + if (this.fieldsClickCallbacks) { + Object.entries(this.fieldsClickCallbacks) + .forEach(([key, callback]) => { + this.divEl[0].querySelectorAll("." + key).forEach((e) => { + e.addEventListener('click', (e) => { + callback(e.target.innerText) + + e.preventDefault(); + }, false) + }) + }); + } if (this.numPages > 1) { this.divEl.append(''); - document.querySelector('#nextButton').addEventListener( + this.divEl[0].querySelector('#nextButton').addEventListener( 'click', () => { this.curPage++; @@ -107,7 +149,8 @@ export let MeasurementTable = (function() { } ,false ); - document.querySelector('#prevButton').addEventListener( + + this.divEl[0].querySelector('#prevButton').addEventListener( 'click', () => { this.curPage--; diff --git a/src/js/Overlay.js b/src/js/Overlay.js index 42f8eb4d..2247ef49 100644 --- a/src/js/Overlay.js +++ b/src/js/Overlay.js @@ -74,7 +74,9 @@ export let Overlay = (function() { }; // return an array of Footprint from a STC-S string - Overlay.parseSTCS = function(stcs) { + Overlay.parseSTCS = function(stcs, options) { + options = options || {}; + var footprints = []; var parts = stcs.match(/\S+/g); var k = 0, len = parts.length; @@ -99,7 +101,9 @@ export let Overlay = (function() { curPolygon.push([ra, dec]); k += 2; } - footprints.push(A.polygon(curPolygon, {closed: true})); + + options.closed = true; + footprints.push(A.polygon(curPolygon, options)); } } else if (s=='circle') { @@ -114,7 +118,7 @@ export let Overlay = (function() { dec = parseFloat(parts[k+2]); radiusDegrees = parseFloat(parts[k+3]); - footprints.push(A.circle(ra, dec, radiusDegrees)); + footprints.push(A.circle(ra, dec, radiusDegrees, options)); k += 3; } diff --git a/src/js/Source.js b/src/js/Source.js index 9e026950..699119ec 100644 --- a/src/js/Source.js +++ b/src/js/Source.js @@ -43,8 +43,6 @@ export let Source = (function() { this.useMarkerDefaultIcon = (options && options.useMarkerDefaultIcon!==undefined) ? options.useMarkerDefaultIcon : true; } - this.footprint = (options && options.footprint) || undefined; - this.isShowing = true; this.isSelected = false; }; @@ -100,7 +98,7 @@ export let Source = (function() { if (this.catalog.onClick=='showTable') { this.select(); - view.aladin.measurementTable.showMeasurement([this]); + view.aladin.measurementTable.showMeasurement([this], this.catalog); } else if (this.catalog.onClick=='showPopup') { diff --git a/src/js/View.js b/src/js/View.js index 723ecf4e..0311b90e 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -572,12 +572,13 @@ export let View = (function () { view.dragy - view.selectStartCoo.y ); - selectedObjects.forEach((obj) => { - obj.select() - }); - console.log(selectedObjects) - view.aladin.measurementTable.showMeasurement(selectedObjects); + selectedObjects.forEach((obj) => obj.select()); + if (selectedObjects.length > 0) { + let table = selectedObjects[0].catalog; + view.aladin.measurementTable.showMeasurement(selectedObjects, table); + } + view.selectedObjects = selectedObjects; view.aladin.fire( diff --git a/src/js/vo/Obscore.js b/src/js/vo/Obscore.js index 5d82a111..68ad673c 100644 --- a/src/js/vo/Obscore.js +++ b/src/js/vo/Obscore.js @@ -71,79 +71,56 @@ 'instrument_name': { name: 'instrument_name', ucd: 'meta.id;instr', utype: 'Provenance.ObsConfig.Instrument.name', units: null }, } + Obscore.clickOnAccessUrlAction = function(accessUrl) { + // Parse the datalink as a votable + VOTable.parse(accessUrl, (fields, rows) => { + console.log(fields) + }) + } + Obscore.COLOR = '#004500' function Obscore() {}; - Obscore.parseVOTable = function(url, callback) { - new VOTable(url, (votable) => { - votable.votable.get("resources") - .forEach((resource) => { - let tables = resource.get("tables") - tables.forEach((table) => { - let fields = table.get("elems") - .map((field) => { - // convert a map into a javascript object - return Object.fromEntries(field); - }) + Obscore.parseFields = function(fields) { + let parsedFields = {}; - let obsCoreFieldIndices = {}; - // Check for mandatory fields - ['s_ra', 's_dec', 'access_url', 's_region'] - .map((mandatoryFieldName) => { - const mandatoryField = Obscore.MANDATORY_FIELDS[mandatoryFieldName]; + const raField = Obscore.MANDATORY_FIELDS['s_ra']; + const decField = Obscore.MANDATORY_FIELDS['s_dec']; + const regionField = Obscore.MANDATORY_FIELDS['s_region']; + const accessUrlField = Obscore.MANDATORY_FIELDS['access_url']; - const fieldIdx = Obscore.findMandatoryField(fields, - mandatoryField.name, - mandatoryField.ucd, - mandatoryField.utype - ); + let raFieldIdx = Obscore.findMandatoryField(fields, raField.name, raField.ucd, raField.utype); + let decFieldIdx = Obscore.findMandatoryField(fields, decField.name, decField.ucd, decField.utype); + let regionFieldIdx = Obscore.findMandatoryField(fields, regionField.name, regionField.ucd, regionField.utype); + let accessUrlFieldIdx = Obscore.findMandatoryField(fields, accessUrlField.name, accessUrlField.ucd, accessUrlField.utype); - let field = fields[fieldIdx]; - let key = field.name ? field.name : field.id; + let fieldIdx = 0; + fields.forEach((field) => { + let key = field.name ? field.name : field.id; - obsCoreFieldIndices[mandatoryFieldName] = { - columnName: key, - idx: fieldIdx, - }; - }) + let nameField; + if (fieldIdx == raFieldIdx) { + nameField = 's_ra'; + } else if (fieldIdx == decFieldIdx) { + nameField = 's_dec'; + } else if (fieldIdx == regionFieldIdx) { + nameField = 's_region'; + } else if (fieldIdx == accessUrlFieldIdx) { + nameField = 'access_url'; + } else { + nameField = key; + } - // At this point we sure know we have an obscore table - let rows = table.get("data").get("rows"); - // We compute the obscore sources - let sources = []; - let footprints = []; - const raFieldIdx = obsCoreFieldIndices['s_ra'].idx; - const decFieldIdx = obsCoreFieldIndices['s_dec'].idx; - const sRegionIdx = obsCoreFieldIndices['s_region'].idx; - + parsedFields[nameField] = { + name: key, + idx: fieldIdx, + }; - rows.forEach(row => { - var mesures = {}; - - let idxField = 0; - for (const field of fields) { - var key = field.name ? field.name : field.id; - - mesures[key] = row[idxField]; - idxField += 1; - } - - const ra = row[raFieldIdx]; - const dec = row[decFieldIdx]; - const region = row[sRegionIdx]; - let footprint = A.footprintsFromSTCS(region)[0]; - - sources.push(new Source(ra, dec, mesures, {footprint: footprint})); - }) - - // Give the source list and a table of correspondance of mandatory obscore fields to source fields - if (callback) { - callback(sources, footprints) - } - }) - }); + fieldIdx++; }) + + return parsedFields; }; diff --git a/src/js/vo/VOTable.js b/src/js/vo/VOTable.js index dea3e3e6..b85292f5 100644 --- a/src/js/vo/VOTable.js +++ b/src/js/vo/VOTable.js @@ -26,6 +26,8 @@ * *****************************************************************************/ import { ALEvent } from "../events/ALEvent.js"; +import { Catalog } from "../Catalog.js"; +import { Obscore } from "./Obscore.js"; export let VOTable = (function() { @@ -39,6 +41,42 @@ export let VOTable = (function() { }}); }) }; + + VOTable.parse = function (url, callback, raField, decField) { + fetch(url) + .then((response) => response.text()) + .then((xml) => { + ALEvent.AL_USE_WASM.dispatchedTo(document.body, {callback: (wasm) => { + let votable = wasm.parseVOTable(xml); + + votable.votable.get("resources") + .forEach((resource) => { + let tables = resource.get("tables") + tables.forEach((table) => { + let fields = table.get("elems") + .map((field) => { + // convert a map into a javascript object + return Object.fromEntries(field); + }) + + try { + fields = Obscore.parseFields(fields); + } catch(e) { + // It is not an obscore table + fields = Catalog.parseFields(fields, raField, decField); + } + + let data = table.get("data"); + let rows = data.get("rows"); + + callback(fields, rows) + }) + }) + } + }) + }) + }; + // return an array of Source(s) from a VOTable url // callback function is called each time a TABLE element has been parsed