mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-04-28 11:53:18 -07:00
first commit tree
This commit is contained in:
4
assets/icons/folder.svg
Normal file
4
assets/icons/folder.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 1H5L8 3H13V5H3.7457L2.03141 11H4.11144L5.2543 7H16L14 14H0V1Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 322 B |
@@ -8,8 +8,8 @@
|
||||
"dateModified": "2023-01-31",
|
||||
"issueTracker": "https://github.com/cds-astro/aladin-lite/issues",
|
||||
"name": "Aladin Lite",
|
||||
"version": "3.7.2-beta",
|
||||
"softwareVersion": "3.7.2-beta",
|
||||
"version": "3.7.3-beta",
|
||||
"softwareVersion": "3.7.3-beta",
|
||||
"description": "An astronomical HiPS visualizer in the browser.",
|
||||
"identifier": "10.5281/zenodo.7638833",
|
||||
"applicationCategory": "Astronomy, Visualization",
|
||||
|
||||
@@ -37,7 +37,10 @@
|
||||
colorPicker.value = cat.color;
|
||||
colorPicker.addEventListener('input', function (e) {
|
||||
// Change the color of the catalog
|
||||
cat.updateShape({color: this.value});
|
||||
console.log(this.value)
|
||||
cat.updateShape({color: () => {
|
||||
return '#00ff00'
|
||||
}});
|
||||
})
|
||||
|
||||
// Define the box
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<script type="text/javascript">
|
||||
var aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, cooFrame: "ICRSd", showSimbadPointerControl: true, showShareControl: true, showShareControl: true, survey: 'https://jafar.astro.unistra.fr/data/jafar_hips/Surveys/CFIS/IC0750/asinh_0_1/', fov: 180, showContextMenu: true});
|
||||
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, cooFrame: "ICRSd", showSimbadPointerControl: true, showShareControl: true, showShareControl: true, fov: 180, showContextMenu: true});
|
||||
// manage URL parameters
|
||||
const searchParams = new URL(document.location).searchParams;
|
||||
if (searchParams.has('baseImageLayer')) {
|
||||
|
||||
@@ -553,6 +553,7 @@ impl App {
|
||||
/*let is_there_new_available_tiles = self
|
||||
.downloader
|
||||
.get_resolved_tiles(/*&available_tiles, */&mut self.hipss);*/
|
||||
//self.tile_fetcher.clear();
|
||||
|
||||
if self.request_for_new_tiles
|
||||
&& Time::now() - self.last_time_request_for_new_tiles > DeltaTime::from(500.0)
|
||||
@@ -564,18 +565,18 @@ impl App {
|
||||
}
|
||||
|
||||
// Tiles are fetched if:
|
||||
let fetch_tiles =
|
||||
// * the user is not panning the view
|
||||
// * or the user is but did not move for at least 100ms
|
||||
//(Time::now() - self.camera.get_time_of_last_move() >= DeltaTime(100.0) || !self.dragging) &&
|
||||
// * no inertia action is in progress
|
||||
//self.inertia.is_none() &&
|
||||
// * the user is not zooming
|
||||
!self.camera.has_zoomed();
|
||||
//let fetch_tiles =
|
||||
// * the user is not panning the view
|
||||
// * or the user is but did not move for at least 100ms
|
||||
//(Time::now() - self.camera.get_time_of_last_move() >= DeltaTime(100.0) || !self.dragging) &&
|
||||
// * no inertia action is in progress
|
||||
//self.inertia.is_none() &&
|
||||
// * the user is not zooming
|
||||
// !self.camera.has_zoomed();
|
||||
|
||||
if fetch_tiles {
|
||||
self.tile_fetcher.notify(self.downloader.clone(), None);
|
||||
}
|
||||
//if fetch_tiles {
|
||||
self.tile_fetcher.notify(self.downloader.clone(), None);
|
||||
//}
|
||||
}
|
||||
|
||||
let rscs_received = self.downloader.borrow_mut().get_received_resources();
|
||||
|
||||
@@ -390,7 +390,15 @@ impl Layers {
|
||||
"Layer {second_layer:?} not found, so cannot be removed.",
|
||||
)))?;
|
||||
|
||||
self.layers.swap(id_first_layer, id_second_layer);
|
||||
if let (Some(k1), Some(k2)) = (self.ids.get(first_layer), self.ids.get(second_layer)) {
|
||||
if let (Some(v1), Some(v2)) = (self.hipses.remove(k1), self.hipses.remove(k2)) {
|
||||
self.hipses.insert(k2.to_string(), v1);
|
||||
self.hipses.insert(k1.to_string(), v2);
|
||||
} else if let (Some(v1), Some(v2)) = (self.images.remove(k1), self.images.remove(k2)) {
|
||||
self.images.insert(k2.to_string(), v1);
|
||||
self.images.insert(k1.to_string(), v2);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,44 @@
|
||||
--aladin-color-border: #fff;
|
||||
}
|
||||
|
||||
.aladin-tree {
|
||||
width: 100%;
|
||||
border-top: 1px solid white;
|
||||
border-bottom: 2px solid white;
|
||||
}
|
||||
|
||||
.aladin-tree .aladin-directory-path {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
width: 100%;
|
||||
border-bottom: 2px solid white;
|
||||
}
|
||||
|
||||
.aladin-tree ul {
|
||||
padding:0;
|
||||
margin:0;
|
||||
overflow-y: scroll;
|
||||
height: 300px;
|
||||
}
|
||||
.aladin-link {
|
||||
list-style-type: none;
|
||||
padding: 0.5em 0px;
|
||||
cursor:pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.aladin-tree li:hover {
|
||||
color: yellowgreen;
|
||||
}
|
||||
|
||||
.aladin-tree li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.aladin-tree li {
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
|
||||
.aladin-dark-theme {
|
||||
background-color: black;
|
||||
color: white;
|
||||
@@ -239,18 +277,15 @@
|
||||
font-family: monospace;
|
||||
background: #fff;
|
||||
|
||||
line-height: 1.3;
|
||||
color: #222;
|
||||
/*box-shadow: 0 0 6px rgba(0,0,0,0.2);*/
|
||||
|
||||
/* Allow scrolling but disable scroll bar */
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* for Firefox */
|
||||
/*overflow-y: auto;*/
|
||||
overflow-y: none;
|
||||
max-height: 500px;
|
||||
/*max-width: fit-content;*/
|
||||
height: fit-content;
|
||||
height: min-content;
|
||||
width: min-content;
|
||||
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.aladin-container canvas {
|
||||
@@ -319,7 +354,7 @@
|
||||
.aladin-box-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #d2d2d2;
|
||||
margin: 5px 0px 5px -4px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.aladin-restore {
|
||||
@@ -509,11 +544,11 @@
|
||||
}
|
||||
|
||||
.aladin-vertical-list > *:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.aladin-vertical-list > * {
|
||||
margin-top: 0.5rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.aladin-horizontal-list {
|
||||
@@ -1124,6 +1159,7 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
|
||||
.aladin-link:hover {
|
||||
color: greenyellow;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.aladin-simbadPointer-control {
|
||||
@@ -1160,9 +1196,13 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
.aladin-stack-box {
|
||||
width: 17rem;
|
||||
}
|
||||
.aladin-item-selected {
|
||||
border: 1px solid orange;
|
||||
}
|
||||
|
||||
.aladin-HiPS-filter-box {
|
||||
margin-top: 0.4rem;
|
||||
/*width: 250px;*/
|
||||
}
|
||||
|
||||
.aladin-HiPS-filter-box .aladin-horizontal-list {
|
||||
|
||||
@@ -2004,7 +2004,7 @@ export let Aladin = (function () {
|
||||
* </ul>
|
||||
*/
|
||||
Aladin.prototype.setBaseImageLayer = function (urlOrHiPSOrFITS) {
|
||||
return this.setOverlayImageLayer(urlOrHiPSOrFITS, "base");
|
||||
return this.setOverlayImageLayer(urlOrHiPSOrFITS, this.overlayLayers[0] || Utils.uuidv4());
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,7 +51,7 @@ export class MocServer {
|
||||
//expr: "dataproduct_type=image",
|
||||
get: "record",
|
||||
fmt: "json",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_order,hips_tile_width,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_order,hips_tile_width,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime,client_category",
|
||||
//fields: "ID,hips_initial_fov,hips_initial_ra,hips_initial_dec,hips_pixel_bitpix,hips_creator,hips_copyright,hips_frame,hips_order,hips_order_min,hips_tile_width,hips_tile_format,hips_pixel_cut,obs_title,obs_description,obs_copyright,obs_regime,hips_data_range,hips_service_url",
|
||||
};
|
||||
|
||||
|
||||
@@ -384,7 +384,6 @@ Utils.fetch = function(params) {
|
||||
// localhost url
|
||||
url = params.url;
|
||||
}
|
||||
|
||||
|
||||
let request = new Request(url, {
|
||||
method: params.method || 'GET',
|
||||
|
||||
@@ -1927,12 +1927,12 @@ export let View = (function () {
|
||||
this.wasm.swapLayers(firstLayer, secondLayer);
|
||||
|
||||
// Swap in overlaylayers
|
||||
const idxFirstLayer = this.overlayLayers.findIndex(overlayLayer => overlayLayer == firstLayer);
|
||||
const idxSecondLayer = this.overlayLayers.findIndex(overlayLayer => overlayLayer == secondLayer);
|
||||
/*const idxFirstLayer = this.overlayLayers.indexOf(firstLayer);
|
||||
const idxSecondLayer = this.overlayLayers.indexOf(secondLayer);
|
||||
|
||||
const tmp = this.overlayLayers[idxFirstLayer];
|
||||
this.overlayLayers[idxFirstLayer] = this.overlayLayers[idxSecondLayer];
|
||||
this.overlayLayers[idxSecondLayer] = tmp;
|
||||
this.overlayLayers[idxSecondLayer] = tmp;*/
|
||||
|
||||
// Tell the layer hierarchy has changed
|
||||
ALEvent.HIPS_LAYER_SWAP.dispatchedTo(this.aladinDiv, { firstLayer: firstLayer, secondLayer: secondLayer });
|
||||
|
||||
@@ -33,6 +33,8 @@ import { Utils } from "../../Utils.ts";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import infoIconUrl from "../../../../assets/icons/info.svg"
|
||||
import { Icon } from "../Widgets/Icon.js";
|
||||
import { Tree } from "../Widgets/Tree.js";
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
@@ -44,32 +46,109 @@ import { Icon } from "../Widgets/Icon.js";
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
function fillHiPSHierarchy(name, hips, path, hierarchy) {
|
||||
let folders = path.split('/')
|
||||
let curFolder = folders.shift()
|
||||
|
||||
// Some exceptions because the MOCServer client_category field may contain some typos
|
||||
if (['x', 'x-ray', 'xray'].includes(curFolder)) {
|
||||
curFolder = 'x-ray'
|
||||
}
|
||||
|
||||
if (['radion', 'radio'].includes(curFolder)) {
|
||||
curFolder = 'radio'
|
||||
}
|
||||
|
||||
if (curFolder === "deprecated")
|
||||
return;
|
||||
|
||||
hierarchy[curFolder] = hierarchy[curFolder] || {};
|
||||
if (folders.length == 0) {
|
||||
hierarchy[curFolder][name] = hips
|
||||
} else {
|
||||
let newPath = folders.join('/')
|
||||
fillHiPSHierarchy(name, hips, newPath, hierarchy[curFolder])
|
||||
}
|
||||
}
|
||||
|
||||
export class HiPSBrowserBox extends Box {
|
||||
static HiPSList = {};
|
||||
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
|
||||
let filter = (item, params) => {
|
||||
if (params.regime) {
|
||||
if (!item.obs_regime)
|
||||
return false;
|
||||
|
||||
if (params.regime.toLowerCase() !== item.obs_regime.toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.resolution) {
|
||||
if (!item.hips_tile_width || !item.hips_order) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let pixelHEALPixOrder = Math.log2(item.hips_tile_width) + (+item.hips_order);
|
||||
let resPixel = Math.sqrt(Math.PI / (3*Math.pow(4, pixelHEALPixOrder)));
|
||||
|
||||
if (resPixel > params.resolution)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.title) {
|
||||
if (!item.obs_title)
|
||||
return false;
|
||||
|
||||
if (!item.obs_title.toLowerCase().includes(params.title.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Search tree
|
||||
let searchTree = new Tree({
|
||||
// a JS object describing the tree to show
|
||||
label: (item) => {
|
||||
let name = item.obs_title.replace(/:|\'/g, '');
|
||||
return name;
|
||||
},
|
||||
// a callback called when the user selects a leaf item of the tree
|
||||
click: (item) => {
|
||||
let image = item.ID || item.hips_service_url;
|
||||
let name = item.obs_title || item.ID;
|
||||
self._addHiPS(image, name)
|
||||
},
|
||||
// a callback called for filtering
|
||||
filter,
|
||||
});
|
||||
|
||||
MocServer.getAllHiPSes().then((HiPSes) => {
|
||||
HiPSBrowserBox.HiPSList = {}
|
||||
|
||||
self.HiPSTree = {};
|
||||
let hipsHierarchy = {};
|
||||
// Fill the HiPSList from the MOCServer
|
||||
|
||||
// Build a hierarchy w.r.t sorted by regime
|
||||
HiPSes.forEach((h) => {
|
||||
let name = h.obs_title;
|
||||
name = name.replace(/:|\'/g, '');
|
||||
|
||||
HiPSBrowserBox.HiPSList[name] = h;
|
||||
|
||||
self.HiPSTree[h.obs_regime] = self.HiPSTree[h.obs_regime] || {};
|
||||
if (self.HiPSTree[h.obs_regime]) {
|
||||
self.HiPSTree[h.obs_regime][name] = h
|
||||
if (h.client_category) {
|
||||
let path = h.client_category.toLowerCase()
|
||||
|
||||
fillHiPSHierarchy(name, h, path, hipsHierarchy)
|
||||
}
|
||||
});
|
||||
|
||||
console.log("jkjk", self.HiPSTree)
|
||||
|
||||
self.searchTree.setHierarchy(hipsHierarchy)
|
||||
|
||||
// Initialize the autocompletion without any filtering
|
||||
self._filterHiPSList({})
|
||||
@@ -98,7 +177,6 @@ export class HiPSBrowserBox extends Box {
|
||||
|
||||
if (image) {
|
||||
self._addHiPS(image, name)
|
||||
self.searchDropdown.update({title: value});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,14 +206,11 @@ export class HiPSBrowserBox extends Box {
|
||||
disable: true,
|
||||
})
|
||||
|
||||
self.searchTree.triggerFilter({title: e.target.value});
|
||||
|
||||
searchDropdown.removeClass('aladin-valid')
|
||||
searchDropdown.removeClass('aladin-not-valid')
|
||||
},
|
||||
change(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault()
|
||||
_parseHiPS(e)
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -193,13 +268,9 @@ export class HiPSBrowserBox extends Box {
|
||||
},
|
||||
toggled: false,
|
||||
actionOn: (e) => {
|
||||
self.filterBox._show({
|
||||
position: {
|
||||
nextTo: filterBtn,
|
||||
direction: "bottom",
|
||||
aladin,
|
||||
},
|
||||
});
|
||||
self.filterBox._show({position: {
|
||||
anchor: 'right center'
|
||||
}});
|
||||
},
|
||||
actionOff: (e) => {
|
||||
self.filterBox._hide();
|
||||
@@ -216,15 +287,17 @@ export class HiPSBrowserBox extends Box {
|
||||
size: 'medium',
|
||||
url: hipsIconUrl,
|
||||
monochrome: true,
|
||||
}), "HiPS browser"])
|
||||
},
|
||||
onDragged: () => {
|
||||
if (self.filterBtn.toggled) {
|
||||
self.filterBtn.toggle();
|
||||
}
|
||||
}), "HiPS browser"]),
|
||||
draggable: true,
|
||||
},
|
||||
//onDragged: () => {
|
||||
//if (self.filterBtn.toggled) {
|
||||
//self.filterBtn.toggle();
|
||||
//}
|
||||
//},
|
||||
classList: ['aladin-HiPS-browser-box'],
|
||||
content: Layout.vertical([
|
||||
searchTree,
|
||||
Layout.horizontal(["Search:", searchDropdown, infoCurrentHiPSBtn]),
|
||||
Layout.horizontal(["Filter:", Layout.horizontal([filterEnabler, filterBtn, filterNumberElt])]),
|
||||
]),
|
||||
@@ -233,6 +306,9 @@ export class HiPSBrowserBox extends Box {
|
||||
aladin.aladinDiv
|
||||
);
|
||||
|
||||
self = this;
|
||||
|
||||
this.searchTree = searchTree;
|
||||
this.filterBox = new HiPSFilterBox(aladin, {
|
||||
callback: (params) => {
|
||||
self._filterHiPSList(params);
|
||||
@@ -247,48 +323,42 @@ export class HiPSBrowserBox extends Box {
|
||||
|
||||
this.infoCurrentHiPSBtn = infoCurrentHiPSBtn;
|
||||
|
||||
self = this;
|
||||
|
||||
this.filterCallback = (HiPS, params) => {
|
||||
if (params.regime) {
|
||||
if (!HiPS.obs_regime)
|
||||
return false;
|
||||
|
||||
if (params.regime.toLowerCase() !== HiPS.obs_regime.toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.spatial) {
|
||||
if (!HiPS.ID)
|
||||
return false;
|
||||
|
||||
if (Array.isArray(params.spatial) && !(params.spatial.includes(HiPS.ID))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.resolution) {
|
||||
if (!HiPS.hips_tile_width || !HiPS.hips_order) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let pixelHEALPixOrder = Math.log2(HiPS.hips_tile_width) + (+HiPS.hips_order);
|
||||
let resPixel = Math.sqrt(Math.PI / (3*Math.pow(4, pixelHEALPixOrder)));
|
||||
|
||||
if (resPixel > params.resolution)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
this.filter = filter;
|
||||
|
||||
filterEnabler.action({target: {checked: true}});
|
||||
|
||||
this._addListeners();
|
||||
|
||||
this._requestMOCServer();
|
||||
}
|
||||
|
||||
_addListeners() {
|
||||
const requestMOCServerDebounced = Utils.debounce(() => {
|
||||
this._requestMOCServer()
|
||||
}, 500);
|
||||
|
||||
ALEvent.POSITION_CHANGED.listenedBy(this.aladin.aladinDiv, requestMOCServerDebounced);
|
||||
ALEvent.ZOOM_CHANGED.listenedBy(this.aladin.aladinDiv, requestMOCServerDebounced);
|
||||
}
|
||||
|
||||
_requestMOCServer() {
|
||||
if (this.isHidden && this.searchTree) {
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
MocServer.getAllHiPSesInsideView(this.aladin)
|
||||
.then((HiPSes) => {
|
||||
let HiPSIDs = HiPSes.map((x) => x.ID);
|
||||
self.searchTree.highlightNodes(HiPSIDs)
|
||||
})
|
||||
}
|
||||
|
||||
_addHiPS(id, name) {
|
||||
let self = this;
|
||||
|
||||
self.searchDropdown.update({value: name, title: name});
|
||||
|
||||
let hips = A.imageHiPS(id, {
|
||||
name,
|
||||
successCallback: (hips) => {
|
||||
@@ -414,8 +484,8 @@ export class HiPSBrowserBox extends Box {
|
||||
let HiPS = HiPSBrowserBox.HiPSList[key];
|
||||
// apply filtering
|
||||
if (
|
||||
self.filterCallback &&
|
||||
self.filterCallback(HiPS, params)
|
||||
self.filter &&
|
||||
self.filter(HiPS, params)
|
||||
) {
|
||||
// search with the name or id
|
||||
let name = HiPS.obs_title;
|
||||
@@ -425,14 +495,15 @@ export class HiPSBrowserBox extends Box {
|
||||
}
|
||||
}
|
||||
|
||||
if (self.searchTree) {
|
||||
self.searchTree.triggerFilter(params);
|
||||
}
|
||||
|
||||
self.searchDropdown.update({ options: HiPSIDs });
|
||||
self.filterNumberElt.innerHTML = HiPSIDs.length + "/" + Object.keys(HiPSBrowserBox.HiPSList).length;
|
||||
}
|
||||
|
||||
_hide() {
|
||||
if (this.filterBox)
|
||||
this.filterBox.signalBrowserStatus(true)
|
||||
|
||||
if (this.filterBtn && this.filterBtn.toggled) {
|
||||
this.filterBtn.toggle();
|
||||
}
|
||||
@@ -443,10 +514,6 @@ export class HiPSBrowserBox extends Box {
|
||||
_show(options) {
|
||||
// Regenerate a new layer name
|
||||
this.layer = (options && options.layer) || Utils.uuidv4();
|
||||
|
||||
if (this.filterBox)
|
||||
this.filterBox.signalBrowserStatus(false)
|
||||
|
||||
super._show(options)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,17 +19,11 @@
|
||||
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { Form } from "../Widgets/Form.js";
|
||||
import { MocServer } from "../../MocServer.js";
|
||||
import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
import { Angle } from "../../libs/astro/angle.js";
|
||||
import { ALEvent } from "../../events/ALEvent.js";
|
||||
import { Utils } from "../../Utils.ts";
|
||||
import { AladinUtils } from "../../AladinUtils.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import freqIconUrl from '../../../../assets/icons/freq.svg';
|
||||
import inViewIconUrl from '../../../../assets/icons/inside.svg';
|
||||
import targetIconUrl from '../../../../assets/icons/target.svg';
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
@@ -45,120 +39,96 @@ export class HiPSFilterBox extends Box {
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
|
||||
let regimeBtn = new TogglerActionButton({
|
||||
content: 'Freq',
|
||||
icon: {
|
||||
monochrome: true,
|
||||
size: 'medium',
|
||||
url: freqIconUrl,
|
||||
},
|
||||
tooltip: {content: 'Observation bandwidth', position: {direction: 'bottom'}},
|
||||
toggled: false,
|
||||
actionOn: () => {
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
actionOff: () => {
|
||||
let regimeBtn = Input.checkbox({
|
||||
name: 'Freq',
|
||||
tooltip: {content: 'Observation bandwidth', position: {direction: 'left'}},
|
||||
type: 'checkbox',
|
||||
checked: false,
|
||||
click(e) {
|
||||
self._triggerFilteringCallback();
|
||||
}
|
||||
});
|
||||
let spatialBtn = new TogglerActionButton({
|
||||
content: 'In view',
|
||||
icon: {
|
||||
monochrome: true,
|
||||
size: 'medium',
|
||||
url: inViewIconUrl,
|
||||
},
|
||||
tooltip: {content: 'Survey in view only!', position: {direction: 'bottom'}},
|
||||
toggled: false,
|
||||
actionOn: () => {
|
||||
self._requestMOCServer();
|
||||
},
|
||||
actionOff: () => {
|
||||
self._triggerFilteringCallback();
|
||||
}
|
||||
});
|
||||
let resolutionBtn = new TogglerActionButton({
|
||||
content: 'Resolution',
|
||||
icon: {
|
||||
monochrome: true,
|
||||
size: 'medium',
|
||||
url: targetIconUrl,
|
||||
},
|
||||
tooltip: {content: 'Check for HiPS with a specific pixel resolution.', position: {direction: 'bottom'}},
|
||||
toggled: false,
|
||||
actionOn: () => {
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
actionOff: () => {
|
||||
let resolutionBtn = Input.checkbox({
|
||||
name: 'Resolution',
|
||||
tooltip: {content: 'Check for HiPS with a specific pixel resolution.', position: {direction: 'left'}},
|
||||
type: 'checkbox',
|
||||
checked: false,
|
||||
click(e) {
|
||||
self._triggerFilteringCallback();
|
||||
}
|
||||
});
|
||||
|
||||
let logSlider = new Input({
|
||||
let regimeOption = Layout.horizontal({
|
||||
tooltip: {
|
||||
content: "Observation regime",
|
||||
position: { direction: "right" },
|
||||
},
|
||||
label: 'Freq: ',
|
||||
layout: [Input.select({
|
||||
value: "Optical",
|
||||
options: [
|
||||
"Radio",
|
||||
"Infrared",
|
||||
"Millimeter",
|
||||
"Optical",
|
||||
"UV",
|
||||
"EUV",
|
||||
"X-ray",
|
||||
"Gamma-ray",
|
||||
],
|
||||
change: (e) => {
|
||||
let regime = e.target.value;
|
||||
self.params["regime"] = regime;
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
}), regimeBtn]
|
||||
});
|
||||
|
||||
let resolutionOption = Layout.horizontal({
|
||||
label: "Max resolution [°/px]:",
|
||||
name: "res",
|
||||
value: 0.1,
|
||||
type: 'range',
|
||||
cssStyle: {
|
||||
width: '100%'
|
||||
},
|
||||
tooltip: {content: AladinUtils.degreesToString(0.1), position: {direction: 'bottom'}},
|
||||
ticks: [0.1 / 3600, 1 / 3600, 1 / 60, 0.1],
|
||||
stretch: "log",
|
||||
min: 0.1 / 3600,
|
||||
max: 0.1,
|
||||
reversed: true,
|
||||
change: (e, slider, deg) => {
|
||||
slider.update({value: e.target.value, tooltip: {content: AladinUtils.degreesToString(deg), position:{direction:'bottom'}}});
|
||||
layout: [
|
||||
new Input({
|
||||
name: "res",
|
||||
value: 0.1,
|
||||
type: 'range',
|
||||
cssStyle: {
|
||||
width: '200px'
|
||||
},
|
||||
tooltip: {content: AladinUtils.degreesToString(0.1), position: {direction: 'bottom'}},
|
||||
ticks: [0.1 / 3600, 1 / 3600, 1 / 60, 0.1],
|
||||
stretch: "log",
|
||||
min: 0.1 / 3600,
|
||||
max: 0.1,
|
||||
reversed: true,
|
||||
change: (e, slider, deg) => {
|
||||
slider.update({value: e.target.value, tooltip: {content: AladinUtils.degreesToString(deg), position:{direction:'bottom'}}});
|
||||
|
||||
let resolution = new Angle(deg);
|
||||
self.params["resolution"] = resolution.degrees();
|
||||
let resolution = new Angle(deg);
|
||||
self.params["resolution"] = resolution.degrees();
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
}),
|
||||
resolutionBtn,
|
||||
]
|
||||
});
|
||||
super(
|
||||
{
|
||||
classList: ['aladin-HiPS-filter-box'],
|
||||
header: {
|
||||
title: 'Filter tags',
|
||||
draggable: false,
|
||||
},
|
||||
close: false,
|
||||
classList: ['aladin-HiPS-filter-box'],
|
||||
content: Layout.vertical([
|
||||
'<b>Filter by:</b>',
|
||||
Layout.horizontal([regimeBtn, spatialBtn, resolutionBtn]),
|
||||
'<b>Details:</b>',
|
||||
new Form({
|
||||
subInputs: [
|
||||
{
|
||||
type: "group",
|
||||
subInputs: [
|
||||
{
|
||||
label: "Freq:",
|
||||
name: "regime",
|
||||
value: "Optical",
|
||||
type: 'select',
|
||||
options: [
|
||||
"Radio",
|
||||
"Infrared",
|
||||
"Millimeter",
|
||||
"Optical",
|
||||
"UV",
|
||||
"EUV",
|
||||
"X-ray",
|
||||
"Gamma-ray",
|
||||
],
|
||||
change: (e) => {
|
||||
let regime = e.target.value;
|
||||
self.params["regime"] = regime;
|
||||
|
||||
//regimeBtn.update({content: regime});
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
},
|
||||
tooltip: {
|
||||
content: "Observation regime",
|
||||
position: { direction: "right" },
|
||||
},
|
||||
},
|
||||
logSlider
|
||||
regimeOption,
|
||||
resolutionOption
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -170,60 +140,28 @@ export class HiPSFilterBox extends Box {
|
||||
|
||||
self = this;
|
||||
|
||||
this.browserClosed = false;
|
||||
|
||||
this.callback = options.callback;
|
||||
|
||||
this.regimeBtn = regimeBtn;
|
||||
this.spatialBtn = spatialBtn;
|
||||
this.resolutionBtn = resolutionBtn;
|
||||
|
||||
this.params = {
|
||||
regime: "Optical",
|
||||
spatial: true,
|
||||
highlight: true,
|
||||
resolution: 1, // 1°/pixel
|
||||
};
|
||||
this.on = false;
|
||||
this.aladin = aladin;
|
||||
this._addListeners();
|
||||
}
|
||||
|
||||
_addListeners() {
|
||||
const requestMOCServerDebounced = Utils.debounce(() => {
|
||||
this._requestMOCServer()
|
||||
}, 500);
|
||||
|
||||
ALEvent.POSITION_CHANGED.listenedBy(this.aladin.aladinDiv, requestMOCServerDebounced);
|
||||
ALEvent.ZOOM_CHANGED.listenedBy(this.aladin.aladinDiv, requestMOCServerDebounced);
|
||||
}
|
||||
|
||||
_requestMOCServer() {
|
||||
if (!this.spatialBtn.toggled || !this.on || this.browserClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
MocServer.getAllHiPSesInsideView(this.aladin)
|
||||
.then((HiPSes) => {
|
||||
let HiPSIDs = HiPSes.map((x) => x.ID);
|
||||
self.params["spatial"] = HiPSIDs;
|
||||
|
||||
self._triggerFilteringCallback();
|
||||
})
|
||||
}
|
||||
|
||||
_triggerFilteringCallback() {
|
||||
let filterParams = {};
|
||||
|
||||
if (this.regimeBtn.toggled) {
|
||||
if (this.regimeBtn.checked) {
|
||||
filterParams['regime'] = this.params['regime']
|
||||
}
|
||||
|
||||
if (this.spatialBtn.toggled) {
|
||||
filterParams['spatial'] = this.params['spatial']
|
||||
}
|
||||
|
||||
if (this.resolutionBtn.toggled) {
|
||||
if (this.resolutionBtn.checked) {
|
||||
filterParams['resolution'] = this.params['resolution']
|
||||
}
|
||||
|
||||
@@ -232,21 +170,18 @@ export class HiPSFilterBox extends Box {
|
||||
}
|
||||
}
|
||||
|
||||
signalBrowserStatus(closed) {
|
||||
/*signalBrowserStatus(closed) {
|
||||
this.browserClosed = closed;
|
||||
|
||||
// open
|
||||
if (!closed) {
|
||||
this._requestMOCServer()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
enable(enable) {
|
||||
this.on = enable;
|
||||
|
||||
if (this.on)
|
||||
this._requestMOCServer();
|
||||
|
||||
this._triggerFilteringCallback();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1115,6 +1115,7 @@ export class OverlayStackBox extends Box {
|
||||
|
||||
let item = Layout.horizontal({
|
||||
layout: [HiPSSelector, Layout.horizontal(btns)],
|
||||
cssStyle: {'padding': '10px 0px'}
|
||||
});
|
||||
|
||||
layout.push(item);
|
||||
@@ -1129,7 +1130,18 @@ export class OverlayStackBox extends Box {
|
||||
}
|
||||
}
|
||||
|
||||
return layout;
|
||||
return Layout.vertical({
|
||||
layout,
|
||||
draggable: (a, b) => {
|
||||
let i1 = layout.findIndex((x) => x.element() === a);
|
||||
let i2 = layout.findIndex((x) => x.element() === b);
|
||||
|
||||
let h1 = layers[i1];
|
||||
let h2 = layers[i2];
|
||||
|
||||
self.aladin.view.swapLayers(h1.layer, h2.layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_addOverlayIcon(overlay) {
|
||||
|
||||
@@ -79,7 +79,7 @@ export class Dropdown extends Input {
|
||||
|
||||
super({
|
||||
type: 'text',
|
||||
autocomplete: {options: options.options},
|
||||
//autocomplete: {options: options.options},
|
||||
...options
|
||||
})
|
||||
this.el.classList.add('search')
|
||||
@@ -91,11 +91,11 @@ export class Dropdown extends Input {
|
||||
update(options) {
|
||||
let newOptions = {};
|
||||
|
||||
if (options && options.options) {
|
||||
/*if (options && options.options) {
|
||||
newOptions['autocomplete'] = {options: options.options};
|
||||
|
||||
delete options.options;
|
||||
}
|
||||
}*/
|
||||
|
||||
// add the other input text options
|
||||
newOptions = {...newOptions, ...options};
|
||||
|
||||
@@ -67,6 +67,47 @@ export class Layout extends DOMElement {
|
||||
this.appendContent(item)
|
||||
}
|
||||
}
|
||||
|
||||
if (options.draggable) {
|
||||
// retrieve the children and add the drag listeners
|
||||
let draggableFn = options.draggable;
|
||||
let firstSelected = null;
|
||||
|
||||
this.el.childNodes.forEach(div => {
|
||||
div.addEventListener("click", () => {
|
||||
// If nothing selected yet → select this one
|
||||
if (!firstSelected) {
|
||||
firstSelected = div;
|
||||
div.classList.add("aladin-item-selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// If clicking the same one again → unselect
|
||||
if (firstSelected === div) {
|
||||
div.classList.remove("aladin-item-selected");
|
||||
firstSelected = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise: swap the two elements
|
||||
let a = firstSelected;
|
||||
let b = div;
|
||||
|
||||
let temp = document.createElement("div");
|
||||
a.parentNode.insertBefore(temp, a);
|
||||
b.parentNode.insertBefore(a, b);
|
||||
temp.parentNode.insertBefore(b, temp);
|
||||
temp.remove();
|
||||
|
||||
// Exec callback
|
||||
draggableFn(a, b)
|
||||
|
||||
// Clear selection
|
||||
a.classList.remove("aladin-item-selected");
|
||||
firstSelected = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// The tooltip has to be set once the element
|
||||
@@ -182,9 +223,5 @@ export class Layout extends DOMElement {
|
||||
if (this.options.position) {
|
||||
this.setPosition(this.options.position)
|
||||
}
|
||||
|
||||
//super._show()
|
||||
// attach to the DOM again
|
||||
//this.attachTo(this.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,11 +137,7 @@ export class Box extends DOMElement {
|
||||
|
||||
if (this.options.content) {
|
||||
let content = this.options.content
|
||||
//if (Array.isArray(content)) {
|
||||
this.appendContent(content);
|
||||
//} else {
|
||||
// this.appendContent(content);
|
||||
//}
|
||||
this.appendContent(content);
|
||||
}
|
||||
|
||||
if (this.options.position) {
|
||||
|
||||
@@ -74,12 +74,17 @@ export class Input extends DOMElement {
|
||||
this.el.type = this.type;
|
||||
|
||||
this.el.checked = this.options.checked;
|
||||
this.checked = this.options.checked;
|
||||
|
||||
// for checkbox widgets, we authorize calling the callback name click or change
|
||||
let action = this.options.click || this.options.change;
|
||||
if (action) {
|
||||
this.el.removeEventListener('click', this.action);
|
||||
this.action = action;
|
||||
this.action = (e) => {
|
||||
this.checked = this.el.checked;
|
||||
|
||||
action(e);
|
||||
};
|
||||
this.el.addEventListener('click', this.action);
|
||||
}
|
||||
} else if (this.type === "select") {
|
||||
@@ -374,6 +379,7 @@ export class Input extends DOMElement {
|
||||
set(value) {
|
||||
if (this.el.type === "checkbox") {
|
||||
this.el.checked = value;
|
||||
this.checked = value;
|
||||
} else {
|
||||
this.el.value = value;
|
||||
}
|
||||
|
||||
313
src/js/gui/Widgets/Tree.js
Normal file
313
src/js/gui/Widgets/Tree.js
Normal file
@@ -0,0 +1,313 @@
|
||||
// Copyright 2023 - 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.
|
||||
//
|
||||
|
||||
import { DOMElement } from "./Widget";
|
||||
import { Icon } from "./Icon";
|
||||
import folderIconUrl from "../../../../assets/icons/folder.svg";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
* File gui/Tree.js
|
||||
*
|
||||
* A tree
|
||||
*
|
||||
* Author: Matthieu Baumann[CDS]
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
export class Tree extends DOMElement {
|
||||
constructor(options, target, position = "beforeend") {
|
||||
let el = document.createElement("div");
|
||||
el.classList.add('aladin-tree');
|
||||
|
||||
super(el, options);
|
||||
|
||||
this.click = options && options.click;
|
||||
|
||||
let rootNode = options && options.root || {};
|
||||
this.params = null;
|
||||
this.filter = options && options.filter;
|
||||
this.label = options && options.label;
|
||||
|
||||
this._setRoot(rootNode);
|
||||
|
||||
this.attachTo(target, position);
|
||||
this._show();
|
||||
this.addClass('aladin-dark-theme')
|
||||
}
|
||||
|
||||
_setRoot(root) {
|
||||
if (root) {
|
||||
root.label = new Icon({
|
||||
size: "small",
|
||||
url: folderIconUrl,
|
||||
monochrome: true,
|
||||
cssStyle: {'display': 'inline-block'}
|
||||
}).element().outerHTML;
|
||||
}
|
||||
|
||||
this.root = root;
|
||||
this._createDOM(root);
|
||||
}
|
||||
|
||||
_createDOM(node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.el.innerHTML = "";
|
||||
this.curNode = node;
|
||||
|
||||
// create the parent directory
|
||||
let curNode = this.curNode;
|
||||
|
||||
let directoryLinks = []
|
||||
|
||||
var levelsOfParenty = 0;
|
||||
|
||||
while (curNode) {
|
||||
let parentLinkEl = document.createElement('a');
|
||||
parentLinkEl.innerHTML = curNode.label;
|
||||
let curLevel = levelsOfParenty;
|
||||
parentLinkEl.addEventListener('click', () => {
|
||||
this.navigate(curLevel)
|
||||
})
|
||||
levelsOfParenty += 1;
|
||||
|
||||
parentLinkEl.classList.add("aladin-link");
|
||||
directoryLinks.push(parentLinkEl);
|
||||
|
||||
curNode = curNode.parent;
|
||||
}
|
||||
|
||||
directoryLinks.reverse()
|
||||
|
||||
let directoryListEl = document.createElement('div');
|
||||
directoryListEl.classList.add('aladin-directory-path');
|
||||
directoryListEl.style.display = "inline-block"
|
||||
|
||||
for (var link of directoryLinks) {
|
||||
directoryListEl.appendChild(link);
|
||||
|
||||
// root node
|
||||
let spanSplitEl = document.createElement('span')
|
||||
spanSplitEl.innerText = ' \/ '
|
||||
directoryListEl.appendChild(spanSplitEl)
|
||||
}
|
||||
|
||||
this.el.appendChild(directoryListEl)
|
||||
|
||||
let listElt = document.createElement('ul');
|
||||
|
||||
for (const label of Object.keys(node).sort()) {
|
||||
if (label !== 'parent' && label !== "label") {
|
||||
let elt = document.createElement('li');
|
||||
// points towards the parent node
|
||||
let child = node[label];
|
||||
let isLeaf = typeof child === "object" && 'ID' in child;
|
||||
if (isLeaf) {
|
||||
if(this.params && this.filter && !this.filter(child, this.params)) {
|
||||
elt.style.display = "none";
|
||||
} else {
|
||||
elt.style.display = "block";
|
||||
}
|
||||
|
||||
elt.innerHTML = this.label(child);
|
||||
} else {
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
// * the number of children matching the filter params
|
||||
let numFilteringMatching = this.numChildMatchingFilter(child, true);
|
||||
let numTotal = this.numChildMatchingFilter(child, false);
|
||||
|
||||
elt.innerHTML = label + ` (${numFilteringMatching}/${numTotal})`
|
||||
}
|
||||
|
||||
elt.style.color = this.hasChildLocatedInFov(child) ? 'green' : 'orange';
|
||||
|
||||
child.label = label;
|
||||
child.parent = node;
|
||||
|
||||
elt.for = label;
|
||||
elt.classList.add("aladin-link");
|
||||
|
||||
elt.addEventListener('click', (e) => {
|
||||
if (isLeaf) {
|
||||
this.click(child)
|
||||
} else {
|
||||
// not leaf
|
||||
this._createDOM(child);
|
||||
}
|
||||
})
|
||||
|
||||
listElt.appendChild(elt)
|
||||
}
|
||||
}
|
||||
|
||||
this.el.appendChild(listElt);
|
||||
}
|
||||
|
||||
setHierarchy(root) {
|
||||
this._setRoot(root)
|
||||
}
|
||||
|
||||
navigate(numOfLevels) {
|
||||
let curNode = this.curNode;
|
||||
while (curNode && curNode.parent && numOfLevels >= 1) {
|
||||
numOfLevels -= 1;
|
||||
curNode = curNode.parent;
|
||||
}
|
||||
|
||||
this._createDOM(curNode)
|
||||
}
|
||||
|
||||
highlightNodes(highlight) {
|
||||
this.highlight = highlight
|
||||
|
||||
let elts = this.el.querySelectorAll("li");
|
||||
let i = 0;
|
||||
|
||||
for (const label of Object.keys(this.curNode).sort()) {
|
||||
if (label !== 'parent' && label !== "label") {
|
||||
let elt = elts[i];
|
||||
i += 1;
|
||||
// points towards the parent node
|
||||
let child = this.curNode[label];
|
||||
let isLeaf = typeof child === "object" && 'ID' in child;
|
||||
if (isLeaf) {
|
||||
// Check if its ID is found in the view
|
||||
if (this.highlight) {
|
||||
elt.style.color = this.highlight.includes(child.ID) ? 'green' : 'orange';
|
||||
}
|
||||
} else {
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
// * the number of children matching the filter params
|
||||
elt.style.color = this.hasChildLocatedInFov(child) ? 'green' : 'orange';
|
||||
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
// * the number of children matching the filter params
|
||||
let numFilteringMatching = this.numChildMatchingFilter(child, true);
|
||||
let numTotal = this.numChildMatchingFilter(child, false);
|
||||
|
||||
let name = elt.innerText.split('(');
|
||||
elt.innerHTML = name[0] + ` (${numFilteringMatching}/${numTotal})`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set params to null, undefined or {} to disable the filtering
|
||||
triggerFilter(params) {
|
||||
if (params && params.title) {
|
||||
params.title = params.title.toLowerCase()
|
||||
}
|
||||
|
||||
this.params = params;
|
||||
|
||||
let elts = this.el.querySelectorAll("li");
|
||||
let i = 0;
|
||||
|
||||
for (const label of Object.keys(this.curNode).sort()) {
|
||||
if (label !== 'parent' && label !== "label") {
|
||||
let elt = elts[i];
|
||||
i += 1;
|
||||
// points towards the parent node
|
||||
let child = this.curNode[label];
|
||||
let isLeaf = typeof child === "object" && 'ID' in child;
|
||||
if (isLeaf) {
|
||||
if(this.params && this.filter && !this.filter(child, this.params)) {
|
||||
elt.style.display = "none"
|
||||
} else {
|
||||
elt.style.display = "block"
|
||||
}
|
||||
} else {
|
||||
// we see a parent, we must determine:
|
||||
// * its color: he has at least 1 child inside the FoV => green
|
||||
// * the number of children matching the filter params
|
||||
let numFilteringMatching = this.numChildMatchingFilter(child, true);
|
||||
let numTotal = this.numChildMatchingFilter(child, false);
|
||||
|
||||
let name = elt.innerText.split('(');
|
||||
elt.innerHTML = name[0] + ` (${numFilteringMatching}/${numTotal})`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasChildLocatedInFov(node) {
|
||||
if (!this.highlight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof node !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
let isLeaf = typeof node === "object" && 'ID' in node;
|
||||
if (isLeaf) {
|
||||
if (this.highlight.includes(node.ID)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
for (const label of Object.keys(node).sort()) {
|
||||
if (label === "parent")
|
||||
continue;
|
||||
|
||||
let child = node[label];
|
||||
if (child && this.hasChildLocatedInFov(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
numChildMatchingFilter(node, filtering) {
|
||||
if (typeof node !== "object") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let isLeaf = typeof node === "object" && 'ID' in node;
|
||||
if (isLeaf) {
|
||||
if (!filtering || (this.params && this.filter && this.filter(node, this.params))) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
let num = 0;
|
||||
for (const label of Object.keys(node).sort()) {
|
||||
if (label === "parent")
|
||||
continue;
|
||||
|
||||
let child = node[label];
|
||||
|
||||
if (child) {
|
||||
num += this.numChildMatchingFilter(child, filtering);
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ export class SAMPConnector {
|
||||
let params = message["samp.params"];
|
||||
|
||||
const {url, name} = params;
|
||||
const image = aladin.createImageFITS(url, {name}, (e) => window.alert(e));
|
||||
const image = aladin.createImageFITS(url, {name}, undefined, (e) => window.alert(e));
|
||||
|
||||
aladin.setOverlayImageLayer(image, name);
|
||||
};
|
||||
@@ -92,6 +92,8 @@ export class SAMPConnector {
|
||||
let url = params['url'];
|
||||
let name = params['name'] || id;
|
||||
|
||||
console.log(id, url, name)
|
||||
|
||||
A.catalogFromURL(
|
||||
url,
|
||||
{name, onClick: 'showTable'},
|
||||
@@ -99,7 +101,7 @@ export class SAMPConnector {
|
||||
(catalog) => {
|
||||
aladin.addCatalog(catalog)
|
||||
},
|
||||
(e) => window.alert(e)
|
||||
(e) => window.alert(e),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user