fix #225. I set to the hips object the cached options if there are instead of erasing the Hips object given by the user with a new one with the cached options

This commit is contained in:
Matthieu Baumann
2025-02-11 19:04:14 +01:00
parent 8844dc3c61
commit f75211902b
5 changed files with 279 additions and 272 deletions

View File

@@ -10,7 +10,7 @@
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {survey: "data/hips/PanSTARRS_DR1_color-z-zg-g", fov:2.0, target: "22 35 58.39 +33 57 57.8", showSettingsControl: true, log: false});
aladin = A.aladin('#aladin-lite-div', {samp: true, survey: "data/hips/PanSTARRS_DR1_color-z-zg-g", fov:2.0, target: "22 35 58.39 +33 57 57.8", showSettingsControl: true, log: false});
aladin.setProjection('AIT');
let cfht = aladin.createImageSurvey("CFHT", "CFHT MegaCam u+g+r", "./data/hips/CFHT", "equatorial", 10, {imgFormat: 'png'});
let jwst1 = aladin.createImageSurvey("CDS/P/JWST/Stephans-Quintet/NIRCam+MIRI", "JWST NIRCam+MIRI", "data/hips/JWST_NIRCam_MIRI", null, null, {imgFormat: 'png'});

View File

@@ -12,10 +12,13 @@
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {projection: 'AIT', cooFrame: 'galactic', fov: 200, target: 'galactic center'});
let dss = aladin.createImageSurvey("DSS blue band", "Color DSS blue HiPS", "http://alasky.cds.unistra.fr/DSS/DSS2-blue-XJ-S/", "equatorial", 9, {imgFormat: 'fits'})
aladin.setBaseImageLayer(dss);
aladin.getBaseImageLayer().setCuts(2, 10000);
});
</script>

View File

@@ -15,10 +15,6 @@
// 'rdbu', 'rdylbu', 'redtemperature', 'sinebow', 'spectral', 'summer', 'viridis', 'ylgnbu' and 'ylorbr'
hips = aladin.getBaseImageLayer()
hips.setColormap("cubehelix");
aladin.setImageSurvey('astron.nl/P/lotss_dr2_high')
//aladin.getBaseImageLayer().setColor([1.0, 0.0, 1.0, 1.0], { tf: 'Linear'} );
});
</script>

View File

@@ -1876,22 +1876,21 @@ export let Aladin = (function () {
// 2/ Not in the cache, then we create the hips from this url/id and
// go to the case 3
imageLayer = A.HiPS(idOrUrl);
return this.setOverlayImageLayer(imageLayer, layer);
}
} else {
// 3/ It is an image survey.
imageLayer = urlOrHiPSOrFITS;
if (imageLayer instanceof HiPS) {
let cachedLayerOptions = hipsCache.get(imageLayer.id)
if (!cachedLayerOptions) {
hipsCache.append(imageLayer.id, imageLayer.options)
} else {
// first set the options of the cached layer to the one of the user
// if it is in the cache we get it from the cache
imageLayer = A.HiPS(imageLayer.id, cachedLayerOptions)
// set the options from what is in the cache
imageLayer.setOptions(cachedLayerOptions);
}
}
}

View File

@@ -47,301 +47,310 @@ export let Datalink = (function() {
Datalink.prototype.handleActions = function(url, obscoreRow, aladinInstance) {
//const url = obscoreRow["access_url"];
new VOTable(
url,
(rsc) => {
rsc = VOTable.parseRsc(rsc);
let success = (rsc) => {
rsc = VOTable.parseRsc(rsc);
// It is a table
if (rsc && rsc.fields && rsc.rows) {
let table = rsc;
table.fields = Catalog.parseFields(table.fields);
// It is a table
if (rsc && rsc.fields && rsc.rows) {
let table = rsc;
table.fields = Catalog.parseFields(table.fields);
// Get the fields and the rows
let measures = [];
const { fields, rows } = table;
rows.forEach(row => {
let data = {};
// Get the fields and the rows
let measures = [];
const { fields, rows } = table;
rows.forEach(row => {
let data = {};
for (const [_, field] of Object.entries(fields)) {
var key = field.name;
data[key] = row[field.idx];
}
for (const [_, field] of Object.entries(fields)) {
var key = field.name;
data[key] = row[field.idx];
}
measures.push({data: data})
})
let self = this;
let datalinkTable = {
name: 'Datalink:' + url,
color: 'purple',
rows: measures,
fields,
showCallback: {
content_type: (data) => {
let contentType = data['content_type'];
measures.push({data: data})
})
let self = this;
let datalinkTable = {
name: 'Datalink:' + url,
color: 'purple',
rows: measures,
fields,
showCallback: {
content_type: (data) => {
let contentType = data['content_type'];
if (contentType && contentType.includes('datalink')) {
return new ActionButton({
size: 'small',
content: '🔗',
tooltip: {content: 'Datalink VOTable', aladin: aladinInstance, global: true},
action(e) {}
}).element();
} else {
return contentType;
}
},
'service_def': (data) => {
const serviceName = data['service_def'];
if (contentType && contentType.includes('datalink')) {
return new ActionButton({
size: 'small',
content: '🔗',
tooltip: {content: 'Datalink VOTable', aladin: aladinInstance, global: true},
action(e) {}
}).element();
} else {
return contentType;
}
},
'service_def': (data) => {
const serviceName = data['service_def'];
if (data['semantics'] === "#cutout") {
return new ActionButton({
size: 'small',
content: '📡',
tooltip: {global: true, aladin: aladinInstance, content: 'Open the cutout service form'},
action(e) {
if (self.serviceQueryBox) {
self.serviceQueryBox.remove()
}
self.serviceQueryBox = new ServiceQueryBox(aladinInstance);
self.serviceQueryBox._hide();
self.serviceQueryBox.attach(self.services[serviceName]);
self.serviceQueryBox._show({
position: {
anchor: 'center center'
}
});
if (data['semantics'] === "#cutout") {
return new ActionButton({
size: 'small',
content: '📡',
tooltip: {global: true, aladin: aladinInstance, content: 'Open the cutout service form'},
action(e) {
if (self.serviceQueryBox) {
self.serviceQueryBox.remove()
}
}).element();
} else {
return serviceName || '--';
}
},
'access_url': (data) => {
let url = data['access_url'];
let accessUrlEl = document.createElement('div');
if (url) {
let contentType = data['content_type'];
let contentQualifier = data['content_qualifier'];
try {
// Just create a URL object to verify it is a good url
// If not, it will throw an exception
let _ = new URL(url);
accessUrlEl.classList.add('aladin-href-td-container');
accessUrlEl.innerHTML = '<a href=' + url + ' target="_blank">' + url + '</a>';
accessUrlEl.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
let processImageFitsClick = () => {
var successCallback = ((ra, dec, fov, _) => {
aladinInstance.gotoRaDec(ra, dec);
aladinInstance.setFoV(fov);
});
let image = aladinInstance.createImageFITS(url, {name: url}, successCallback);
aladinInstance.setOverlayImageLayer(image, Utils.uuidv4())
};
switch (contentType) {
// A datalink response containing links to datasets or services attached to the current dataset
case 'application/x-votable+xml;content=datalink':
new Datalink().handleActions(url, obscoreRow, aladinInstance);
break;
case 'application/hips':
// Clic on a HiPS
let layer = Utils.uuidv4();
if (contentQualifier === "cube") {
let cubeOnTheFlyUrl = url + '/';
HiPSProperties.fetchFromUrl(cubeOnTheFlyUrl)
.then(properties => {
let numSlices = +properties.hips_cube_depth;
let idxSlice = +properties.hips_cube_firstframe;
let updateSlice = () => {
let colorCfg = aladinInstance.getOverlayImageLayer(layer).getColorCfg();
let hips = aladinInstance.setOverlayImageLayer(cubeOnTheFlyUrl + idxSlice, layer)
hips.setOptions({
opacity: colorCfg.opacity,
minCut: colorCfg.minCut,
maxCut: colorCfg.maxCut,
colormap: colorCfg.colormap,
stretch: colorCfg.stretch,
reversed: colorCfg.reversed
})
slicer.update({
value: idxSlice,
tooltip: {content: (idxSlice + 1) + '/' + numSlices, position: {direction: 'bottom'}},
})
cubeDisplayer.update({content: Layout.horizontal([prevBtn, nextBtn, slicer, (idxSlice + 1) + '/' + numSlices])})
};
let slicer = Input.slider({
label: "Slice",
name: "cube slicer",
ticks: [idxSlice],
tooltip: {content: (idxSlice + 1) + '/' + numSlices , position: {direction: 'bottom'}},
min: 0,
max: numSlices - 1,
value: idxSlice,
actions: {
change: (e) => {
idxSlice = Math.round(e.target.value);
updateSlice();
},
input: (e) => {
idxSlice = Math.round(e.target.value);
slicer.update({
value: idxSlice,
tooltip: {content: (idxSlice + 1) + '/' + numSlices, position: {direction: 'bottom'}},
})
}
},
cssStyle: {
width: '300px'
}
});
let prevBtn = A.button({
size: 'small',
content: '<',
action(o) {
idxSlice = Math.max(idxSlice - 1, 0);
updateSlice()
}
})
let nextBtn = A.button({
size: 'small',
content: '>',
action(o) {
idxSlice = Math.min(idxSlice + 1, numSlices - 1);
updateSlice()
}
})
let cubeDisplayer = A.box({
close: true,
header: {
title: 'HiPS cube player',
draggable: true,
},
content: Layout.horizontal([prevBtn, nextBtn, slicer, (idxSlice + 1) + '/' + numSlices]),
position: {anchor: 'center top'},
});
aladinInstance.addUI(cubeDisplayer)
aladinInstance.setOverlayImageLayer(cubeOnTheFlyUrl + idxSlice, layer)
})
} else {
let survey = aladinInstance.newImageSurvey(url);
aladinInstance.setOverlayImageLayer(survey, layer)
}
break;
// Any generic FITS file
case 'application/fits':
if (contentQualifier === "cube") {
// fits cube
console.warn("Cube not handled, only first slice downloaded")
}
processImageFitsClick();
break;
case 'image/fits':
if (contentQualifier === "cube") {
// fits cube
console.warn("Cube not handled, only first slice downloaded")
}
processImageFitsClick();
break;
default:
// When all has been done, download what's under the link
Utils.openNewTab(url);
break;
self.serviceQueryBox = new ServiceQueryBox(aladinInstance);
self.serviceQueryBox._hide();
self.serviceQueryBox.attach(self.services[serviceName]);
self.serviceQueryBox._show({
position: {
anchor: 'center center'
}
});
} catch(e) {
accessUrlEl.innerText = '--';
}
} else {
}).element();
} else {
return serviceName || '--';
}
},
'access_url': (data) => {
let url = data['access_url'];
let accessUrlEl = document.createElement('div');
if (url) {
let contentType = data['content_type'];
let contentQualifier = data['content_qualifier'];
try {
// Just create a URL object to verify it is a good url
// If not, it will throw an exception
let _ = new URL(url);
accessUrlEl.classList.add('aladin-href-td-container');
accessUrlEl.innerHTML = '<a href=' + url + ' target="_blank">' + url + '</a>';
accessUrlEl.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
let processImageFitsClick = () => {
var successCallback = ((ra, dec, fov, _) => {
aladinInstance.gotoRaDec(ra, dec);
aladinInstance.setFoV(fov);
});
let image = aladinInstance.createImageFITS(url, {name: url}, successCallback);
aladinInstance.setOverlayImageLayer(image, Utils.uuidv4())
};
switch (contentType) {
// A datalink response containing links to datasets or services attached to the current dataset
case 'application/x-votable+xml;content=datalink':
new Datalink().handleActions(url, obscoreRow, aladinInstance);
break;
case 'application/hips':
// Clic on a HiPS
let layer = Utils.uuidv4();
if (contentQualifier === "cube") {
let cubeOnTheFlyUrl = url + '/';
HiPSProperties.fetchFromUrl(cubeOnTheFlyUrl)
.then(properties => {
let numSlices = +properties.hips_cube_depth;
let idxSlice = +properties.hips_cube_firstframe;
let updateSlice = () => {
let colorCfg = aladinInstance.getOverlayImageLayer(layer).getColorCfg();
let hips = aladinInstance.setOverlayImageLayer(cubeOnTheFlyUrl + idxSlice, layer)
hips.setOptions({
opacity: colorCfg.opacity,
minCut: colorCfg.minCut,
maxCut: colorCfg.maxCut,
colormap: colorCfg.colormap,
stretch: colorCfg.stretch,
reversed: colorCfg.reversed
})
slicer.update({
value: idxSlice,
tooltip: {content: (idxSlice + 1) + '/' + numSlices, position: {direction: 'bottom'}},
})
cubeDisplayer.update({content: Layout.horizontal([prevBtn, nextBtn, slicer, (idxSlice + 1) + '/' + numSlices])})
};
let slicer = Input.slider({
label: "Slice",
name: "cube slicer",
ticks: [idxSlice],
tooltip: {content: (idxSlice + 1) + '/' + numSlices , position: {direction: 'bottom'}},
min: 0,
max: numSlices - 1,
value: idxSlice,
actions: {
change: (e) => {
idxSlice = Math.round(e.target.value);
updateSlice();
},
input: (e) => {
idxSlice = Math.round(e.target.value);
slicer.update({
value: idxSlice,
tooltip: {content: (idxSlice + 1) + '/' + numSlices, position: {direction: 'bottom'}},
})
}
},
cssStyle: {
width: '300px'
}
});
let prevBtn = A.button({
size: 'small',
content: '<',
action(o) {
idxSlice = Math.max(idxSlice - 1, 0);
updateSlice()
}
})
let nextBtn = A.button({
size: 'small',
content: '>',
action(o) {
idxSlice = Math.min(idxSlice + 1, numSlices - 1);
updateSlice()
}
})
let cubeDisplayer = A.box({
close: true,
header: {
title: 'HiPS cube player',
draggable: true,
},
content: Layout.horizontal([prevBtn, nextBtn, slicer, (idxSlice + 1) + '/' + numSlices]),
position: {anchor: 'center top'},
});
aladinInstance.addUI(cubeDisplayer)
aladinInstance.setOverlayImageLayer(cubeOnTheFlyUrl + idxSlice, layer)
})
} else {
let survey = aladinInstance.newImageSurvey(url);
aladinInstance.setOverlayImageLayer(survey, layer)
}
break;
// Any generic FITS file
case 'application/fits':
if (contentQualifier === "cube") {
// fits cube
console.warn("Cube not handled, only first slice downloaded")
}
processImageFitsClick();
break;
case 'image/fits':
if (contentQualifier === "cube") {
// fits cube
console.warn("Cube not handled, only first slice downloaded")
}
processImageFitsClick();
break;
default:
// When all has been done, download what's under the link
Utils.openNewTab(url);
break;
}
});
} catch(e) {
accessUrlEl.innerText = '--';
}
return accessUrlEl;
} else {
accessUrlEl.innerText = '--';
}
return accessUrlEl;
}
}
}
aladinInstance.measurementTable.showMeasurement([datalinkTable]);
// SODA service descriptor
} else if (rsc && rsc.baseUrl && rsc.inputParams) {
// Try to parse a SODA service descriptor resource
let serviceDesc = rsc;
aladinInstance.measurementTable.showMeasurement([datalinkTable]);
// SODA service descriptor
} else if (rsc && rsc.baseUrl && rsc.inputParams) {
// Try to parse a SODA service descriptor resource
let serviceDesc = rsc;
if (serviceDesc) {
// Try to populate the SODA form fields with obscore values
let populateSODAFields = (SODAParams) => {
for (const name in SODAParams.inputParams) {
let inputParam = SODAParams.inputParams[name];
if (serviceDesc) {
// Try to populate the SODA form fields with obscore values
let populateSODAFields = (SODAParams) => {
for (const name in SODAParams.inputParams) {
let inputParam = SODAParams.inputParams[name];
if (inputParam.type === "group") {
for (const param of inputParam.subInputs) {
if (param.value) {
continue;
}
if (inputParam.type === "group") {
for (const param of inputParam.subInputs) {
if (param.value) {
continue;
}
if (param.name === "ra") {
param.value = obscoreRow['s_ra'];
} else if (param.name === "dec") {
param.value = obscoreRow['s_dec'];
} else if (param.name === "fmin") {
param.value = obscoreRow['em_min'];
} else if (param.name === "fmax") {
param.value = obscoreRow['em_max'];
} else if (param.name === "rad") {
param.value = obscoreRow['s_fov'] / 2;
}
if (param.name === "ra") {
param.value = obscoreRow['s_ra'];
} else if (param.name === "dec") {
param.value = obscoreRow['s_dec'];
} else if (param.name === "fmin") {
param.value = obscoreRow['em_min'];
} else if (param.name === "fmax") {
param.value = obscoreRow['em_max'];
} else if (param.name === "rad") {
param.value = obscoreRow['s_fov'] / 2;
}
}
}
};
}
};
// Request the base url of the SODA server to check if there
// is a self description VOTable
new VOTable(serviceDesc.baseUrl, (rsc) => {
const res = VOTable.parseRsc(rsc);
// Request the base url of the SODA server to check if there
// is a self description VOTable
new VOTable(serviceDesc.baseUrl, (rsc) => {
const res = VOTable.parseRsc(rsc);
if (res && res.baseUrl && res.inputParams) {
for (const name in res.inputParams) {
let inputParam = res.inputParams[name];
if (!serviceDesc.inputParams[name]) {
serviceDesc.inputParams[name] = inputParam;
}
if (res && res.baseUrl && res.inputParams) {
for (const name in res.inputParams) {
let inputParam = res.inputParams[name];
if (!serviceDesc.inputParams[name]) {
serviceDesc.inputParams[name] = inputParam;
}
}
populateSODAFields(serviceDesc);
}, undefined, true);
}
populateSODAFields(serviceDesc);
}, undefined, true);
this.services[serviceDesc.name] = serviceDesc;
}
populateSODAFields(serviceDesc);
this.services[serviceDesc.name] = serviceDesc;
}
}
};
new VOTable(
url,
success,
() => {
new VOTable(
url,
success,
undefined,
true
)
},
undefined,
false
)
};