mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-06-12 19:11:42 -07:00
fix polygonal selection #339
This commit is contained in:
committed by
Matthieu Baumann
parent
1894f908f4
commit
c50fdb7430
+33
-16
@@ -19,6 +19,7 @@
|
||||
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="https://aladin.cds.unistra.fr/AladinLite/api/v3/latest/aladin.js" charset="utf-8"></script>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-1.10.1.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
@@ -38,8 +39,8 @@
|
||||
<!-- fin temporaire gestion cercle -->
|
||||
|
||||
<b>Orientation</b><br>
|
||||
<button id="hips-coronelli" class="pure-button" name="ref-hips" onclick="longitudeReversed = false; aladin.reverseLongitude(longitudeReversed)">Normal</button><br>
|
||||
<button id="hips-illenoroc" class="pure-button" name="ref-hips" onclick="longitudeReversed = true; aladin.reverseLongitude(longitudeReversed)">Inversé</button>
|
||||
<button id="hips-coronelli" class="pure-button" name="ref-hips" onclick="aladin.setImageSurvey('Coronelli');">Normal</button><br>
|
||||
<button id="hips-illenoroc" class="pure-button" name="ref-hips" onclick="aladin.setImageSurvey('illenoroC');">Inversé</button>
|
||||
<br><br>
|
||||
|
||||
<b>Constellations</b>
|
||||
@@ -75,6 +76,13 @@
|
||||
<a href="#"><img id="coronelli-stars-red" class="catcoro coro-star" src="star_red.png"></a>
|
||||
<a href="#"><img id="coronelli-stars-blue" class="catcoro coro-star" src="star_blue.png"></a>
|
||||
</div>
|
||||
<div>Coronelli2<br>
|
||||
<!--a id="coronelli-stars" class="pure-button catcoro" href="#">Coronelli</a-->
|
||||
<a href="#"><img id="coronelli-stars-white" class="catcoro coro-star" src="star_white.png"></a>
|
||||
<a href="#"><img id="coronelli-stars-yellow" class="catcoro coro-star" src="star_yellow.png"></a><br>
|
||||
<a href="#"><img id="coronelli-stars-red" class="catcoro coro-star" src="star_red.png"></a>
|
||||
<a href="#"><img id="coronelli-stars-blue" class="catcoro coro-star" src="star_blue.png"></a>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<b>Navigation</b> <br><button id="stop">Stop</button>
|
||||
@@ -99,6 +107,14 @@
|
||||
<a class="pure-button nav-button nav-goto" href="#">Halley</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
<div id="coo_halley">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Halley</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
<div id="coo_halley">
|
||||
<a class="pure-button nav-button nav-goto" href="#">Halley</a><br>
|
||||
→ <a class="pure-button nav-button nav-flyto" href="#">Move</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css"> .aladin-reticleColor { color: rgb(178, 50, 178); font-weight:bold;} </style>
|
||||
@@ -226,15 +242,16 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
import {Utils} from '../src/js/Utils';
|
||||
<script type="text/javascript">
|
||||
//import A from '../src/js/A.js';
|
||||
//import {Utils} from '../src/js/Utils';
|
||||
|
||||
A.init.then(() => {
|
||||
var hipsDir="http://alasky.u-strasbg.fr/CDS_P_Coronelli";
|
||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, expandLayersControl: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||
aladin.createImageSurvey('Coronelli', 'Coronelli', hipsDir, 'equatorial', 4, {imgFormat: 'jpg'});
|
||||
aladin.setImageSurvey('Coronelli');
|
||||
var hipsDir="http://alasky.cds.unistra.fr/CDS_P_Coronelli";
|
||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, lockNorthUp: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||
aladin.createImageSurvey('Coronelli', 'Coronelli', hipsDir, 'equatorial', 4, {imgFormat: 'jpg', longitudeReversed: true, minOrder: 3});
|
||||
aladin.createImageSurvey('illenoroC', 'illenoroC', hipsDir, 'equatorial', 4, {imgFormat: 'jpg', longitudeReversed: false, minOrder: 3});
|
||||
aladin.setImageSurvey('illenoroC');
|
||||
|
||||
$('#layersControlLeft').show();
|
||||
$('#layersCL2').show();
|
||||
@@ -344,14 +361,14 @@
|
||||
|
||||
// listen click on navigation buttons
|
||||
$('.nav-button').click(function() {
|
||||
var cooTarget = $(this).parent().attr('id');
|
||||
var cooTarget = $(this).parent().attr('id');
|
||||
|
||||
if ($(this).hasClass("nav-goto")) {
|
||||
aladin.gotoRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec);
|
||||
}
|
||||
else if ($(this).hasClass("nav-flyto")) {
|
||||
aladin.animateToRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec, cooNav[cooTarget].time);
|
||||
}
|
||||
if ($(this).hasClass("nav-goto")) {
|
||||
aladin.gotoRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec);
|
||||
}
|
||||
else if ($(this).hasClass("nav-flyto")) {
|
||||
aladin.animateToRaDec(cooNav[cooTarget].ra, cooNav[cooTarget].dec, cooNav[cooTarget].time);
|
||||
}
|
||||
});
|
||||
|
||||
// stop animations
|
||||
|
||||
+5180
-5180
File diff suppressed because it is too large
Load Diff
+16
-7
@@ -580,6 +580,10 @@
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
.aladin-not-found {
|
||||
color: darkorange;
|
||||
}
|
||||
|
||||
.aladin-button:hover {
|
||||
color: #ffffff;
|
||||
background-color: #3276b1;
|
||||
@@ -962,7 +966,7 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
-webkit-appearance: none;
|
||||
outline-style: none;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border: var(--border-size) solid var(--border-color);
|
||||
border-radius: 0.4rem;
|
||||
width: 2rem;
|
||||
height: 1.5rem;
|
||||
@@ -971,13 +975,11 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
|
||||
.aladin-input-color::-webkit-color-swatch {
|
||||
border: none;
|
||||
border-radius: 0.4rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aladin-input-color::-webkit-color-swatch-wrapper {
|
||||
border: none;
|
||||
border-radius: 0.4rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -1159,8 +1161,8 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.aladin-indicator.aladin-not-valid {
|
||||
background-color: var(--error-color);
|
||||
.aladin-indicator.aladin-not-found {
|
||||
background-color: darkorange;
|
||||
}
|
||||
|
||||
.aladin-indicator.aladin-valid {
|
||||
@@ -1204,6 +1206,7 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
|
||||
.aladin-stack-box {
|
||||
min-width: 17rem;
|
||||
max-width: 300px;
|
||||
}
|
||||
.aladin-item-selected {
|
||||
border: var(--border-size) solid orange;
|
||||
@@ -1221,11 +1224,11 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
|
||||
.aladin-HiPS-browser-box {
|
||||
height: 500px;
|
||||
min-width: 300px;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
.aladin-cat-browser-box {
|
||||
width: 300px;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.aladin-HiPS-browser-box .aladin-input-text {
|
||||
@@ -1306,6 +1309,12 @@ otherwise it fits its content options. If those are too big the select can go ou
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
max-width: 50vw;
|
||||
}
|
||||
|
||||
.aladin-status-bar{
|
||||
|
||||
@@ -209,35 +209,6 @@ export let Footprint= (function() {
|
||||
};
|
||||
|
||||
Footprint.prototype.intersectsBBox = function(x, y, w, h, view) {
|
||||
/*if(this.source) {
|
||||
let s = this.source;
|
||||
|
||||
if (!s.isShowing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let c = null;
|
||||
if (s.x && s.y) {
|
||||
c = {
|
||||
x: s.x,
|
||||
y: s.y,
|
||||
};
|
||||
} else {
|
||||
var xy = view.aladin.world2pix(s.ra, s.dec);
|
||||
if (!xy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
c = {
|
||||
x: xy[0],
|
||||
y: xy[1],
|
||||
};
|
||||
}
|
||||
|
||||
if (c.x >= x && c.x <= x + w && c.y >= y && c.y <= y + h) {
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
return this.shapes.some((shape) => shape.intersectsBBox(x, y, w, h, view));
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -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,client_category,dataproduct_subtype,hips_service_url,hips_initial_ra,hips_initial_dec,hips_initial_fov",
|
||||
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,dataproduct_subtype,hips_service_url,hips_initial_ra,hips_initial_dec,hips_initial_fov,em_min,em_max",
|
||||
};
|
||||
|
||||
this._allHiPSes = Utils.loadFromUrls(MocServer.MIRRORS_HTTPS, {
|
||||
@@ -96,7 +96,7 @@ export class MocServer {
|
||||
expr: "dataproduct_type=image&&ID=" + ids.join(','),
|
||||
get: "record",
|
||||
fmt: "json",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime,dataproduct_subtype,hips_service_url,hips_initial_ra,hips_initial_dec,hips_initial_fov",
|
||||
fields: "ID,hips_creator,hips_copyright,hips_frame,hips_tile_format,obs_title,obs_description,obs_copyright,obs_regime,dataproduct_subtype,hips_service_url,hips_initial_ra,hips_initial_dec,hips_initial_fov,em_min,em_max",
|
||||
};
|
||||
|
||||
return Utils.loadFromUrls(MocServer.MIRRORS_HTTPS, {
|
||||
|
||||
+4
-1
@@ -93,7 +93,7 @@ export let View = (function () {
|
||||
// 1. Print the original exception message in the console
|
||||
//console.error(e)
|
||||
// 2. Add a more explicite message to the end user
|
||||
console.error("Problem initializing Aladin Lite. Please contact the support by contacting Matthieu Baumann (baumannmatthieu0@gmail.com) or Thomas Boch (thomas.boch@astro.unistra.fr). You can also open an issue on the Aladin Lite github repository here: https://github.com/cds-astro/aladin-lite. Message error:" + e)
|
||||
console.error("Problem initializing Aladin Lite. Please contact the support by contacting Matthieu Baumann (matthieu.baumann@astro.unistra.fr) or Thomas Boch (thomas.boch@astro.unistra.fr). You can also open an issue on the Aladin Lite github repository here: https://github.com/cds-astro/aladin-lite. Message error:" + e)
|
||||
}
|
||||
|
||||
this._defineProperties();
|
||||
@@ -595,6 +595,9 @@ export let View = (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.spectraDisplayer)
|
||||
this.spectraDisplayer.hide();
|
||||
|
||||
if (imageLayer.dataproductType === "spectral-cube") {
|
||||
if (!this.spectraDisplayer) {
|
||||
this.spectraDisplayer = new SpectraDisplayer(this, {width: 800, height: 300});
|
||||
|
||||
@@ -110,10 +110,13 @@ export class HiPSBrowserBox extends Box {
|
||||
}
|
||||
|
||||
if (params.title) {
|
||||
if (!item.obs_title)
|
||||
if (!item.obs_title && !item.ID)
|
||||
return false;
|
||||
|
||||
if (!item.obs_title.toLowerCase().includes(params.title.toLowerCase())) {
|
||||
let obsTitleDoesNotMatch = !item.obs_title.toLowerCase().includes(params.title.toLowerCase());
|
||||
let creatorDidDoesNotMatch = !item.ID.toLowerCase().includes(params.title.toLowerCase());
|
||||
|
||||
if (obsTitleDoesNotMatch && creatorDidDoesNotMatch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -134,6 +137,13 @@ export class HiPSBrowserBox extends Box {
|
||||
let name = item.obs_title || item.ID;
|
||||
self._addHiPS(image, name)
|
||||
},
|
||||
dblclick: (item) => {
|
||||
let image = item.ID || item.hips_service_url;
|
||||
let name = item.obs_title || item.ID;
|
||||
self._addHiPS(image, name)
|
||||
|
||||
self.close();
|
||||
},
|
||||
// a callback called for filtering
|
||||
filter,
|
||||
aladin,
|
||||
@@ -168,7 +178,6 @@ export class HiPSBrowserBox extends Box {
|
||||
});
|
||||
|
||||
self.searchDropdown.update({ options: HiPSIDs });
|
||||
|
||||
self.searchTree.setHierarchy(hipsHierarchy)
|
||||
|
||||
// Initialize the autocompletion without any filtering
|
||||
@@ -281,7 +290,7 @@ export class HiPSBrowserBox extends Box {
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin,
|
||||
content: 'red: out of the view, green: in view'
|
||||
content: 'orange: out of the view, green: in view'
|
||||
},
|
||||
header: {
|
||||
title: [
|
||||
@@ -296,7 +305,7 @@ export class HiPSBrowserBox extends Box {
|
||||
url: helpIconUrl,
|
||||
monochrome: true,
|
||||
tooltip: {
|
||||
content: 'HiPS:<br/><span class="aladin-indicator aladin-not-valid"></span> out of the view<br /><span class="aladin-indicator aladin-valid"></span> in view',
|
||||
content: 'HiPS:<br/><span class="aladin-indicator aladin-not-found"></span> out of the view<br /><span class="aladin-indicator aladin-valid"></span> in view',
|
||||
mouse: true,
|
||||
aladin
|
||||
},
|
||||
@@ -485,7 +494,8 @@ export class HiPSBrowserBox extends Box {
|
||||
self.searchDropdown.addClass('aladin-not-valid');
|
||||
}
|
||||
});
|
||||
this.aladin.setOverlayImageLayer(hips, self.layer);
|
||||
|
||||
self.selected(hips)
|
||||
}
|
||||
|
||||
// This method is executed only if the filter is enabled
|
||||
@@ -525,7 +535,8 @@ export class HiPSBrowserBox extends Box {
|
||||
|
||||
_show(options) {
|
||||
// Regenerate a new layer name
|
||||
this.layer = (options && options.layer) || Utils.uuidv4();
|
||||
this.selected = options && options.selected;
|
||||
|
||||
super._show(options)
|
||||
|
||||
this._requestMOCServer();
|
||||
|
||||
+174
-241
@@ -17,19 +17,17 @@
|
||||
// along with Aladin Lite.
|
||||
//
|
||||
|
||||
import { MocServer } from "../../MocServer.js";
|
||||
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { Dropdown } from "../Input/Dropdown.js";
|
||||
import hipsIconUrl from "../../../../assets/icons/hips.svg";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { Layout } from "../Layout.js";
|
||||
import A from "../../A.js";
|
||||
import { Utils } from "../../Utils.ts";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import infoIconUrl from "../../../../assets/icons/info.svg"
|
||||
import addIconUrl from "../../../../assets/icons/plus.svg";
|
||||
import settingsIconUrl from "../../../../assets/icons/settings.svg";
|
||||
import { Icon } from "../Widgets/Icon.js";
|
||||
|
||||
import { HiPSSelector } from "../Input/HiPSSelector.js";
|
||||
import { HiPSBrowserBox } from "./HiPSBrowserBox.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { ActionButton } from "../Widgets/ActionButton.js";
|
||||
import { Form } from "../Widgets/Form.js";
|
||||
import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -41,273 +39,208 @@ import { Icon } from "../Widgets/Icon.js";
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
function fillHiPSHierarchy(name, hips, path, hierarchy) {
|
||||
let folders = path.split('/')
|
||||
let curFolder = folders.shift()
|
||||
|
||||
if(curFolder === 'Image') {
|
||||
let newPath = folders.join('/')
|
||||
fillHiPSHierarchy(name, hips, newPath, hierarchy);
|
||||
} else {
|
||||
// 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 HiPSCompositeBox extends Box {
|
||||
static HiPSList = {};
|
||||
|
||||
constructor(aladin, options) {
|
||||
let self;
|
||||
|
||||
// Search tree
|
||||
MocServer.getAllHiPSes().then((HiPSes) => {
|
||||
HiPSBrowserBox.HiPSList = {}
|
||||
|
||||
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;
|
||||
|
||||
if (h.client_category) {
|
||||
let path = h.client_category
|
||||
|
||||
fillHiPSHierarchy(name, h, path, hipsHierarchy)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const _parseHiPS = (e) => {
|
||||
const value = e.target.value;
|
||||
|
||||
let image, name;
|
||||
// A user can put an url
|
||||
try {
|
||||
image = new URL(value).href;
|
||||
name = image;
|
||||
} catch (e) {
|
||||
// Or he can select a HiPS from the list given
|
||||
const hips = HiPSBrowserBox.HiPSList[value];
|
||||
if (hips) {
|
||||
image = hips.ID || hips.hips_service_url;
|
||||
name = hips.obs_title || hips.ID;
|
||||
} else {
|
||||
// Finally if not found, interpret the input text value as the HiPS (e.g. ID)
|
||||
image = value;
|
||||
name = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (image) {
|
||||
self._addHiPS(image, name)
|
||||
}
|
||||
};
|
||||
|
||||
let searchDropdown = new Dropdown(aladin, {
|
||||
name: "HiPS browser",
|
||||
placeholder: "Browse a HiPS by an URL, ID or keywords",
|
||||
let nameInput = Input.text({
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin,
|
||||
content: 'HiPS url, ID or keyword accepted',
|
||||
content: 'What name for your composite survey?'
|
||||
},
|
||||
placeholder: "What name?...",
|
||||
autocomplete: 'off',
|
||||
autofocus: true,
|
||||
actions: {
|
||||
dblclick: (_) => {
|
||||
nameInput.set('')
|
||||
},
|
||||
keydown: (e) => {
|
||||
e.stopPropagation();
|
||||
//
|
||||
}
|
||||
},
|
||||
action: (e) => {}
|
||||
});
|
||||
|
||||
let infoCurrentHiPSBtn = new ActionButton({
|
||||
disable: true,
|
||||
icon: {
|
||||
size: 'medium',
|
||||
monochrome: true,
|
||||
url: infoIconUrl,
|
||||
},
|
||||
tooltip: {
|
||||
global: true,
|
||||
aladin,
|
||||
content: "More about that survey?"
|
||||
}
|
||||
});
|
||||
let content = [[
|
||||
new ActionButton({
|
||||
icon: {
|
||||
url: addIconUrl,
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {
|
||||
content: "Add a new layer",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
toggled: false,
|
||||
action(_) {
|
||||
self.content.push(self._addNewHiPS());
|
||||
self.update({content: self.content})
|
||||
}
|
||||
}),
|
||||
nameInput
|
||||
]];
|
||||
|
||||
super(
|
||||
{
|
||||
close: true,
|
||||
header: {
|
||||
title: Layout.horizontal([new Icon({
|
||||
size: 'medium',
|
||||
url: hipsIconUrl,
|
||||
monochrome: true,
|
||||
}), "HiPS Compositor"]),
|
||||
title: [
|
||||
new Icon({
|
||||
size: 'medium',
|
||||
url: hipsIconUrl,
|
||||
monochrome: true,
|
||||
}),
|
||||
"HiPS Compositor"
|
||||
],
|
||||
draggable: true,
|
||||
},
|
||||
content: Layout.vertical([
|
||||
[searchDropdown, infoCurrentHiPSBtn],
|
||||
]),
|
||||
content,
|
||||
...options,
|
||||
},
|
||||
aladin.aladinDiv
|
||||
);
|
||||
|
||||
self = this;
|
||||
|
||||
this.searchDropdown = searchDropdown;
|
||||
this.aladin = aladin;
|
||||
|
||||
this.infoCurrentHiPSBtn = infoCurrentHiPSBtn;
|
||||
self = this;
|
||||
|
||||
this._addListeners();
|
||||
this.numHiPSLayers = 0;
|
||||
this.content = content.concat([this._addNewHiPS()])
|
||||
this.update({content: this.content})
|
||||
|
||||
this.openSettings = null;
|
||||
}
|
||||
|
||||
_addListeners() {}
|
||||
|
||||
_addHiPS(id, name) {
|
||||
let self = this;
|
||||
|
||||
self.searchDropdown.update({value: name, title: name});
|
||||
|
||||
let hips = A.imageHiPS(id, {
|
||||
name,
|
||||
successCallback: (hips) => {
|
||||
self.searchDropdown.removeClass('aladin-not-valid');
|
||||
self.searchDropdown.addClass('aladin-valid');
|
||||
|
||||
self.infoCurrentHiPSBtn.update({
|
||||
disable: false,
|
||||
action(e) {
|
||||
window.open(hips.url);
|
||||
}
|
||||
})
|
||||
|
||||
self.aladin.removeUIByName("cube_displayer" + hips.layer)
|
||||
|
||||
if (!hips.cubeDepth)
|
||||
return;
|
||||
|
||||
let numSlices = hips.cubeDepth;
|
||||
let idxSlice = hips.cubeFirstFrame;
|
||||
|
||||
hips.setSliceNumber(idxSlice)
|
||||
|
||||
let toStr = (n, paddingBegin = false) => {
|
||||
let s = n.toString();
|
||||
let maxNumDigits = numSlices.toString().length;
|
||||
|
||||
if (s.length < maxNumDigits) {
|
||||
let r = ' '.repeat(maxNumDigits - s.length)
|
||||
if (paddingBegin) {
|
||||
s = r + s
|
||||
} else {
|
||||
s += r
|
||||
_addNewHiPS() {
|
||||
let newLayerLayout = [
|
||||
new HiPSSelector({
|
||||
change(e) {
|
||||
let name = e.target.value;
|
||||
|
||||
if (name === "More...") {
|
||||
if (!aladin.hipsBrowser) {
|
||||
aladin.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
aladin.hipsBrowser._show({
|
||||
selected: (hips) => {
|
||||
console.log(hips)
|
||||
},
|
||||
position: { anchor: "center center" }
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}),
|
||||
this._createLayerSettingsBox(),
|
||||
ActionButton.BUTTONS(aladin)
|
||||
.remove(
|
||||
(e) => {
|
||||
let node = e.target.parentElement.parentElement.parentElement;
|
||||
let idLayer = [...node.parentElement.children].indexOf(node);
|
||||
|
||||
this.content.splice(idLayer, 1)
|
||||
this.update({content: this.content})
|
||||
|
||||
this.numHiPSLayers = this.content.length - 1;
|
||||
}
|
||||
)
|
||||
];
|
||||
this.numHiPSLayers += 1;
|
||||
|
||||
return newLayerLayout;
|
||||
}
|
||||
|
||||
_createLayerSettingsBox() {
|
||||
let self = this;
|
||||
let layerSettingsBox = new Box({
|
||||
close: false,
|
||||
content: new Form({
|
||||
subInputs: [
|
||||
{
|
||||
type: 'color',
|
||||
label: "Color",
|
||||
value: 'red',
|
||||
name: 'color',
|
||||
change(e) {
|
||||
let hex = e.target.value;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Stretch',
|
||||
type: "select",
|
||||
name: 'stretch',
|
||||
value: 'linear',
|
||||
options: ['sqrt', 'linear', 'asinh', 'pow2', 'log'],
|
||||
change(e) {},
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
label: "Min cut",
|
||||
name: 'mincut',
|
||||
value: 0.0,
|
||||
change: (e) => {
|
||||
let minCut = +e.target.value
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Max cut',
|
||||
type: "number",
|
||||
name: 'maxcut',
|
||||
value: 0.0,
|
||||
change: (e) => {
|
||||
let maxCut = +e.target.value
|
||||
}
|
||||
},
|
||||
]
|
||||
}),
|
||||
}, this.aladin.aladinDiv);
|
||||
layerSettingsBox._hide()
|
||||
|
||||
// catalog settings
|
||||
let layerSettingsBtn = new TogglerActionButton({
|
||||
icon: { url: settingsIconUrl, monochrome: true },
|
||||
size: "small",
|
||||
tooltip: {
|
||||
content: "Settings",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
toggled: false,
|
||||
actionOn: (_) => {
|
||||
layerSettingsBox._show({
|
||||
position: {
|
||||
nextTo: layerSettingsBtn,
|
||||
direction: "right",
|
||||
aladin: self.aladin,
|
||||
},
|
||||
});
|
||||
|
||||
if (self.openSettings) {
|
||||
self.openSettings.close();
|
||||
}
|
||||
|
||||
let updateSlice = () => {
|
||||
slicer.update({
|
||||
value: idxSlice,
|
||||
tooltip: {content: (idxSlice + 1) + '/' + numSlices, position: {direction: 'bottom'}},
|
||||
})
|
||||
|
||||
hips.setSliceNumber(idxSlice)
|
||||
cubeDisplayer.update({
|
||||
position: cubeDisplayer.position,
|
||||
content: [prevBtn, nextBtn, slicer, toStr(idxSlice + 1, true) + '/' + toStr(numSlices, false)]
|
||||
})
|
||||
};
|
||||
|
||||
let slicer = Input.slider({
|
||||
label: "Slice",
|
||||
name: "cube_slicer" + hips.layer,
|
||||
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,
|
||||
name: "cube_displayer" + hips.layer,
|
||||
header: {
|
||||
title: 'Player for: ' + hips.name,
|
||||
draggable: true,
|
||||
},
|
||||
content: Layout.horizontal([prevBtn, nextBtn, slicer, toStr(idxSlice + 1, true) + '/' + toStr(numSlices, false)]),
|
||||
position: {anchor: 'center top'},
|
||||
});
|
||||
|
||||
self.aladin.addUI(cubeDisplayer)
|
||||
self.openSettings = layerSettingsBtn;
|
||||
},
|
||||
actionOff: (_) => {
|
||||
layerSettingsBox._hide();
|
||||
if (self.openSettings === layerSettingsBtn) {
|
||||
self.openSettings = null;
|
||||
}
|
||||
},
|
||||
errorCallback: (e) => {
|
||||
self.searchDropdown.removeClass('aladin-valid');
|
||||
self.searchDropdown.addClass('aladin-not-valid');
|
||||
}
|
||||
});
|
||||
this.aladin.setOverlayImageLayer(hips, self.layer);
|
||||
|
||||
return layerSettingsBtn
|
||||
}
|
||||
|
||||
_show(options) {
|
||||
// Regenerate a new layer name
|
||||
this.layer = (options && options.layer) || Utils.uuidv4();
|
||||
super._show(options)
|
||||
_hide() {
|
||||
if (this.openSettings)
|
||||
this.openSettings.close();
|
||||
|
||||
super._hide()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,9 +209,6 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
{
|
||||
label: 'min cut:',
|
||||
type: 'number',
|
||||
cssStyle: {
|
||||
width: '6rem',
|
||||
},
|
||||
tooltip: {content: 'Min cut', position: {direction: 'bottom'}},
|
||||
name: 'mincut',
|
||||
value: 0.0,
|
||||
@@ -223,9 +220,6 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
{
|
||||
type: 'number',
|
||||
label: 'max cut:',
|
||||
cssStyle: {
|
||||
width: '6rem',
|
||||
},
|
||||
tooltip: {content: 'Max cut', position: {direction: 'bottom'}},
|
||||
name: 'maxcut',
|
||||
value: 1.0,
|
||||
|
||||
+72
-117
@@ -49,13 +49,14 @@ import { TogglerActionButton } from "../Button/Toggler.js";
|
||||
import { Icon } from "../Widgets/Icon.js";
|
||||
import { Box } from "../Widgets/Box.js";
|
||||
import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
|
||||
import { Input } from "../Widgets/Input.js";
|
||||
import { Image } from "../../Image.js";
|
||||
import { HiPSBrowserBox } from "./HiPSBrowserBox.js";
|
||||
import { HiPSCompositeBox } from "./HiPSCompositeBox.js"
|
||||
import { Catalog } from "../../Catalog.js";
|
||||
import { ProgressiveCat } from "../../ProgressiveCat.js";
|
||||
import { Form } from "../Widgets/Form.js";
|
||||
import { HiPSSelector } from "./../Input/HiPSSelector.js";
|
||||
import { HiPS } from "../../HiPS.js";
|
||||
|
||||
export class OverlayStackBox extends Box {
|
||||
/*static previewImagesUrl = {
|
||||
@@ -191,8 +192,6 @@ export class OverlayStackBox extends Box {
|
||||
o.stopPropagation();
|
||||
o.preventDefault();
|
||||
|
||||
//self._hide();
|
||||
|
||||
const simbadHiPS = A.catalogHiPS(
|
||||
OverlayStackBox.predefinedCats.simbad
|
||||
.url,
|
||||
@@ -208,8 +207,6 @@ export class OverlayStackBox extends Box {
|
||||
o.stopPropagation();
|
||||
o.preventDefault();
|
||||
|
||||
//self._hide();
|
||||
|
||||
const simbadHiPS = A.catalogHiPS(
|
||||
OverlayStackBox.predefinedCats.gaia.url,
|
||||
OverlayStackBox.predefinedCats.gaia
|
||||
@@ -535,12 +532,19 @@ export class OverlayStackBox extends Box {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
if (!self.hipsBrowser)
|
||||
self.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
if (!aladin.hipsBrowser)
|
||||
aladin.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
|
||||
self.hipsBrowser._show({position: {
|
||||
anchor: 'center center'
|
||||
}});
|
||||
let newLayer = Utils.uuidv4();
|
||||
|
||||
aladin.hipsBrowser._show({
|
||||
selected: (hips) => {
|
||||
aladin.setOverlayImageLayer(hips, newLayer);
|
||||
},
|
||||
position: {
|
||||
anchor: 'center center'
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -661,13 +665,6 @@ export class OverlayStackBox extends Box {
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.GRAPHIC_OVERLAY_LAYER_CHANGED.listenedBy(
|
||||
this.aladin.aladinDiv,
|
||||
function (e) {
|
||||
updateOverlayList();
|
||||
}
|
||||
);
|
||||
|
||||
ALEvent.HIPS_LAYER_ADDED.listenedBy(
|
||||
this.aladin.aladinDiv,
|
||||
function (e) {
|
||||
@@ -717,42 +714,6 @@ export class OverlayStackBox extends Box {
|
||||
);
|
||||
|
||||
updateOverlayList();
|
||||
|
||||
// Add a listener for HiPS list changes
|
||||
ALEvent.FAVORITE_HIPS_LIST_UPDATED.listenedBy(document.body, (event) => {
|
||||
let favoritesHips = event.detail;
|
||||
|
||||
self.cachedHiPS = {};
|
||||
|
||||
for (var hips of favoritesHips) {
|
||||
let key = hips.name || hips.id || hips.url;
|
||||
self.cachedHiPS[key] = hips;
|
||||
}
|
||||
// Update the options of the selector
|
||||
const favorites = Object.keys(self.cachedHiPS);
|
||||
for (var key in self.ui) {
|
||||
let ui = self.ui[key];
|
||||
// refers to an HiPS image survey
|
||||
if (ui.HiPSSelector) {
|
||||
let currentHiPS = ui.HiPSSelector.options.value
|
||||
|
||||
let favoritesCopy = [...favorites];
|
||||
|
||||
// add the current hips to the selector as well, even if it has been manually
|
||||
// removed from the HiPSList
|
||||
if (favoritesCopy.indexOf(currentHiPS) < 0) {
|
||||
favoritesCopy.push(currentHiPS)
|
||||
}
|
||||
|
||||
// one must add the current HiPS too!
|
||||
favoritesCopy.sort();
|
||||
|
||||
favoritesCopy.push("More...")
|
||||
|
||||
ui.HiPSSelector.update({value: currentHiPS, options: favoritesCopy});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_hide() {
|
||||
@@ -780,7 +741,6 @@ export class OverlayStackBox extends Box {
|
||||
let layout = [[this.addOverlayBtn, "Overlays"]];
|
||||
|
||||
layout = layout.concat(this._createOverlaysList());
|
||||
|
||||
layout.push(
|
||||
[
|
||||
this.addHiPSBtn,
|
||||
@@ -790,7 +750,14 @@ export class OverlayStackBox extends Box {
|
||||
],
|
||||
);
|
||||
layout = layout.concat(this._createSurveysList());
|
||||
return Layout.vertical(layout);
|
||||
return Layout.vertical(layout,
|
||||
{
|
||||
cssStyle: {
|
||||
overflowWrap: "anywhere",
|
||||
wordBreak: "break-word",
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_createOverlaysList() {
|
||||
@@ -955,20 +922,11 @@ export class OverlayStackBox extends Box {
|
||||
}
|
||||
}
|
||||
|
||||
optBtn.push(new ActionButton({
|
||||
icon: {
|
||||
url: removeIconUrl,
|
||||
monochrome: true,
|
||||
},
|
||||
size: "small",
|
||||
tooltip: {
|
||||
content: "Remove",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
action(e) {
|
||||
optBtn.push(ActionButton.BUTTONS(self.aladin).remove(
|
||||
(e) => {
|
||||
self.aladin.removeLayer(overlay);
|
||||
},
|
||||
}))
|
||||
}
|
||||
));
|
||||
|
||||
layout.push(
|
||||
{
|
||||
@@ -984,98 +942,95 @@ export class OverlayStackBox extends Box {
|
||||
_createSurveysList() {
|
||||
let self = this;
|
||||
|
||||
const layers = Array.from(self.aladin.getStackLayers())
|
||||
let aladin = self.aladin;
|
||||
|
||||
const layers = Array.from(aladin.getStackLayers())
|
||||
.reverse()
|
||||
.map((name) => {
|
||||
let overlay = self.aladin.getOverlayImageLayer(name);
|
||||
let overlay = aladin.getOverlayImageLayer(name);
|
||||
return overlay;
|
||||
});
|
||||
|
||||
// survey list
|
||||
let layout = [];
|
||||
|
||||
let hipsOptions = Object.keys(self.cachedHiPS);
|
||||
hipsOptions.sort()
|
||||
|
||||
for (const layer of layers) {
|
||||
if (!layer) {
|
||||
for (const hips of layers) {
|
||||
if (!hips) {
|
||||
continue;
|
||||
}
|
||||
let options = Array.from([...hipsOptions])
|
||||
let value = layer.name || layer.id
|
||||
|
||||
if (options.indexOf(value) < 0) {
|
||||
options.push(value)
|
||||
}
|
||||
|
||||
options.push("More...")
|
||||
|
||||
let HiPSSelector = Input.select({
|
||||
value,
|
||||
options,
|
||||
title: layer.name,
|
||||
change: (e) => {
|
||||
let HiPSselect = new HiPSSelector({
|
||||
layer: hips,
|
||||
change(e) {
|
||||
let name = e.target.value;
|
||||
|
||||
if (name === "More...") {
|
||||
if (!self.hipsBrowser)
|
||||
self.hipsBrowser = new HiPSBrowserBox(self.aladin);
|
||||
if (!aladin.hipsBrowser) {
|
||||
aladin.hipsBrowser = new HiPSBrowserBox(aladin);
|
||||
}
|
||||
|
||||
self.hipsBrowser._show({ layer: layer.layer, position: { anchor: "center center" } });
|
||||
aladin.hipsBrowser._show({
|
||||
selected: (hips) => {
|
||||
self.aladin.setOverlayImageLayer(hips, hips.layer);
|
||||
},
|
||||
position: { anchor: "center center" }
|
||||
});
|
||||
return;
|
||||
}
|
||||
// search for the
|
||||
let overlayLayer;
|
||||
if (name in self.cachedHiPS) {
|
||||
// it is an hips
|
||||
let HiPSOptions = self.cachedHiPS[name];
|
||||
|
||||
let overlayLayer;
|
||||
if (name in HiPSSelector.cachedHiPS) {
|
||||
// it is an hips
|
||||
let HiPSOptions = HiPSSelector.cachedHiPS[name];
|
||||
overlayLayer = A.HiPS(HiPSOptions.id || HiPSOptions.url, HiPSOptions);
|
||||
} else {
|
||||
overlayLayer = layer
|
||||
overlayLayer = hips
|
||||
}
|
||||
|
||||
self.aladin.setOverlayImageLayer(overlayLayer, layer.layer);
|
||||
aladin.setOverlayImageLayer(overlayLayer, hips.layer);
|
||||
}
|
||||
});
|
||||
|
||||
let deleteBtn = ActionButton.createSmallSizedIconBtn({
|
||||
icon: { url: removeIconUrl, monochrome: true },
|
||||
//disable: layer.layer === "base",
|
||||
tooltip: { content: "Remove", position: { direction: "top" } },
|
||||
action(e) {
|
||||
self.aladin.removeImageLayer(layer.layer);
|
||||
aladin.removeImageLayer(hips.layer);
|
||||
// remove HiPS cube player if any
|
||||
self.aladin.removeUIByName("cube_displayer" + layer.layer)
|
||||
aladin.removeUIByName("cube_displayer" + hips.layer)
|
||||
|
||||
if (hips instanceof HiPS && hips === aladin.view.spectraDisplayer.hips) {
|
||||
aladin.view.spectraDisplayer.hide()
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let prevOpacity = null;
|
||||
let showBtn = ActionButton.createSmallSizedIconBtn({
|
||||
icon: {
|
||||
url: layer.getOpacity() === 0.0 ? hideIconUrl : showIconUrl,
|
||||
url: hips.getOpacity() === 0.0 ? hideIconUrl : showIconUrl,
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {
|
||||
content: layer.getOpacity() === 0.0 ? "Show" : "Hide",
|
||||
content: hips.getOpacity() === 0.0 ? "Show" : "Hide",
|
||||
position: { direction: "top" },
|
||||
},
|
||||
action(e, btn) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
let opacity = layer.getOpacity();
|
||||
let opacity = hips.getOpacity();
|
||||
if (opacity === 0.0) {
|
||||
let newOpacity = prevOpacity || 1.0;
|
||||
prevOpacity = null;
|
||||
layer.setOpacity(newOpacity);
|
||||
hips.setOpacity(newOpacity);
|
||||
btn.update({
|
||||
icon: { monochrome: true, url: showIconUrl },
|
||||
tooltip: { content: "Hide" },
|
||||
});
|
||||
} else {
|
||||
prevOpacity = opacity;
|
||||
layer.setOpacity(0.0);
|
||||
hips.setOpacity(0.0);
|
||||
btn.update({
|
||||
icon: { monochrome: true, url: hideIconUrl },
|
||||
tooltip: { content: "Show" },
|
||||
@@ -1085,7 +1040,7 @@ export class OverlayStackBox extends Box {
|
||||
});
|
||||
|
||||
let settingsBox = new HiPSSettingsBox(self.aladin);
|
||||
settingsBox.update({ layer });
|
||||
settingsBox.update({ layer: hips });
|
||||
settingsBox._hide();
|
||||
|
||||
let settingsBtn = new TogglerActionButton({
|
||||
@@ -1101,7 +1056,7 @@ export class OverlayStackBox extends Box {
|
||||
for (var l in self.ui) {
|
||||
let ui = self.ui[l]
|
||||
|
||||
if (l != layer.layer) {
|
||||
if (l != hips.layer) {
|
||||
ui.settingsBtn.close();
|
||||
}
|
||||
}
|
||||
@@ -1121,8 +1076,8 @@ export class OverlayStackBox extends Box {
|
||||
|
||||
let loadMOCBtn = ActionButton.BUTTONS(self.aladin)
|
||||
.addMOC({
|
||||
name: layer.name,
|
||||
url: layer.url + '/Moc.fits'
|
||||
name: hips.name,
|
||||
url: hips.url + '/Moc.fits'
|
||||
});
|
||||
|
||||
self.layer2swap = null;
|
||||
@@ -1142,9 +1097,9 @@ export class OverlayStackBox extends Box {
|
||||
let toggled = swapBtn.options.toggled;
|
||||
if (!toggled) {
|
||||
if (!self.layer2swap) {
|
||||
self.layer2swap = layer;
|
||||
self.layer2swap = hips;
|
||||
} else {
|
||||
self.aladin.view.swapLayers(self.layer2swap.layer, layer.layer);
|
||||
self.aladin.view.swapLayers(self.layer2swap.layer, hips.layer);
|
||||
}
|
||||
} else {
|
||||
if (self.layer2swap) {
|
||||
@@ -1160,17 +1115,17 @@ export class OverlayStackBox extends Box {
|
||||
|
||||
let btns = [showBtn, settingsBtn];
|
||||
|
||||
if (!(layer instanceof Image)) {
|
||||
if (!(hips instanceof Image)) {
|
||||
btns.push(loadMOCBtn);
|
||||
}
|
||||
btns = btns.concat([swapBtn, deleteBtn]);
|
||||
|
||||
let item = Layout.horizontal([HiPSSelector, Layout.horizontal(btns)]);
|
||||
let item = Layout.horizontal([HiPSselect, Layout.horizontal(btns)]);
|
||||
layout.push(item);
|
||||
|
||||
if (!(layer.layer in self.ui)) {
|
||||
self.ui[layer.layer] = {
|
||||
HiPSSelector,
|
||||
if (!(hips.layer in self.ui)) {
|
||||
self.ui[hips.layer] = {
|
||||
HiPSSelector: HiPSselect,
|
||||
settingsBox,
|
||||
settingsBtn,
|
||||
showBtn,
|
||||
|
||||
@@ -117,23 +117,7 @@ export class StatusBarBox extends Box {
|
||||
this.el.title = task.message;
|
||||
|
||||
// create message div
|
||||
let message = Layout.horizontal(task.message,
|
||||
{
|
||||
tooltip: {
|
||||
content: task.message,
|
||||
position: {
|
||||
direction: "top",
|
||||
},
|
||||
hoverable: true,
|
||||
delayShowUpTime: '500ms',
|
||||
cssStyle: {
|
||||
fontSize: 'x-small',
|
||||
maxWidth: "200px",
|
||||
"overflow-wrap": "break-word",
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
let message = Layout.horizontal(task.message);
|
||||
|
||||
message.addClass("aladin-status-bar-message")
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ import { Icon } from "./Icon";
|
||||
import { Layout } from "../Layout";
|
||||
|
||||
import infoIconUrl from "../../../../assets/icons/info.svg"
|
||||
import targetIconUrl from '../../../../assets/icons/target.svg';
|
||||
import targetIconUrl from "../../../../assets/icons/target.svg";
|
||||
import removeIconUrl from "../../../../assets/icons/remove.svg";
|
||||
import A from "../../A";
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
@@ -276,6 +277,19 @@ export class ActionButton extends DOMElement {
|
||||
})
|
||||
|
||||
return button;
|
||||
},
|
||||
remove: (action) => {
|
||||
return new ActionButton({
|
||||
icon: {
|
||||
url: removeIconUrl,
|
||||
monochrome: true,
|
||||
},
|
||||
size: "small",
|
||||
tooltip: {
|
||||
content: "Remove",
|
||||
},
|
||||
action
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ export class Box extends DOMElement {
|
||||
this._show();
|
||||
}
|
||||
|
||||
close() {
|
||||
this._hide()
|
||||
}
|
||||
|
||||
_show(options) {
|
||||
this.options = {
|
||||
...this.options,
|
||||
@@ -143,7 +147,7 @@ export class Box extends DOMElement {
|
||||
size: "small",
|
||||
monochrome: true,
|
||||
},
|
||||
tooltip: {content: 'Enlarge the window', global: true, aladin},
|
||||
tooltip: {content: 'Enlarge the window', global: true, aladin: this.aladin},
|
||||
cssStyle: {
|
||||
cursor: 'move',
|
||||
position: 'absolute',
|
||||
|
||||
+50
-40
@@ -23,6 +23,7 @@ import folderIconUrl from "../../../../assets/icons/folder.svg";
|
||||
|
||||
import { Layout } from "../Layout";
|
||||
import { ActionButton } from "./ActionButton";
|
||||
|
||||
/******************************************************************************
|
||||
* Aladin Lite project
|
||||
*
|
||||
@@ -42,6 +43,7 @@ export class Tree extends DOMElement {
|
||||
super(el, options);
|
||||
|
||||
this.click = options && options.click;
|
||||
this.dblclick = options && options.dblclick;
|
||||
this.aladin = options && options.aladin;
|
||||
|
||||
let rootNode = options && options.root || {};
|
||||
@@ -118,6 +120,31 @@ export class Tree extends DOMElement {
|
||||
|
||||
let listElt = document.createElement('ul');
|
||||
|
||||
let seekMinEmInNode = (n) => {
|
||||
const isLeaf = typeof n === 'object' && 'ID' in n;
|
||||
|
||||
if (isLeaf) {
|
||||
return (+n.em_min)
|
||||
} else if (typeof n === 'object') {
|
||||
let min = Number.POSITIVE_INFINITY;
|
||||
|
||||
for (var [key, child] of Object.entries(n)) {
|
||||
if (key === "parent" || key === "label") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let val = seekMinEmInNode(child);
|
||||
if (Number.isFinite(val)) {
|
||||
min = Math.min(val, min);
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
} else {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
};
|
||||
|
||||
let labels = Object.keys(node).sort((la, lb) => {
|
||||
let na = node[la];
|
||||
let nb = node[lb];
|
||||
@@ -127,10 +154,19 @@ export class Tree extends DOMElement {
|
||||
|
||||
if (aIsLeaf !== bIsLeaf) {
|
||||
return aIsLeaf - bIsLeaf;
|
||||
} else if (typeof na === "object" && typeof nb === "object") {
|
||||
let emNa = seekMinEmInNode(na)
|
||||
let emNb = seekMinEmInNode(nb)
|
||||
|
||||
if (emNa > emNb) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else if (la < lb) {
|
||||
return -1
|
||||
} else {
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
});
|
||||
|
||||
@@ -196,7 +232,6 @@ export class Tree extends DOMElement {
|
||||
.element(),
|
||||
])
|
||||
|
||||
console.log(layout)
|
||||
let childElt = new Layout(
|
||||
layout,
|
||||
{
|
||||
@@ -207,18 +242,18 @@ export class Tree extends DOMElement {
|
||||
`alt="${label}" />` +
|
||||
`<figcaption>${label}</figcaption>` +
|
||||
'</figure>',
|
||||
delayShowUpTime: "100ms",
|
||||
mouse: true,
|
||||
aladin: this.aladin,
|
||||
}
|
||||
}).element();
|
||||
|
||||
if (this.highlight) {
|
||||
if(this.highlight.includes(child.ID)) {
|
||||
childElt.classList.add("aladin-valid");
|
||||
childElt.classList.remove("aladin-not-valid");
|
||||
childElt.classList.remove("aladin-not-found");
|
||||
} else {
|
||||
childElt.classList.remove("aladin-valid");
|
||||
childElt.classList.add("aladin-not-valid");
|
||||
childElt.classList.add("aladin-not-found");
|
||||
}
|
||||
}
|
||||
elt.appendChild(childElt);
|
||||
@@ -249,10 +284,10 @@ export class Tree extends DOMElement {
|
||||
|
||||
if(this.hasChildLocatedInFov(child)) {
|
||||
elt.classList.add("aladin-valid");
|
||||
elt.classList.remove("aladin-not-valid");
|
||||
elt.classList.remove("aladin-not-found");
|
||||
} else {
|
||||
elt.classList.remove("aladin-valid");
|
||||
elt.classList.add("aladin-not-valid");
|
||||
elt.classList.add("aladin-not-found");
|
||||
}
|
||||
|
||||
child.label = label;
|
||||
@@ -269,6 +304,11 @@ export class Tree extends DOMElement {
|
||||
this._createDOM(child);
|
||||
}
|
||||
})
|
||||
elt.addEventListener('dblclick', (e) => {
|
||||
if (isLeaf) {
|
||||
this.dblclick(child)
|
||||
}
|
||||
})
|
||||
|
||||
listElt.appendChild(elt)
|
||||
}
|
||||
@@ -327,23 +367,8 @@ export class Tree extends DOMElement {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
let labels = Object.keys(node).sort((la, lb) => {
|
||||
let na = node[la];
|
||||
let nb = node[lb];
|
||||
|
||||
let aIsLeaf = typeof na === "object" && 'ID' in na;
|
||||
let bIsLeaf = typeof nb === "object" && 'ID' in nb;
|
||||
|
||||
if (aIsLeaf !== bIsLeaf) {
|
||||
return aIsLeaf - bIsLeaf;
|
||||
} else if (la < lb) {
|
||||
return -1
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
for (const label of labels) {
|
||||
if (label === "parent")
|
||||
for (const label of Object.keys(node)) {
|
||||
if (label === "parent" || label === "label")
|
||||
continue;
|
||||
|
||||
let child = node[label];
|
||||
@@ -370,22 +395,7 @@ export class Tree extends DOMElement {
|
||||
}
|
||||
} else {
|
||||
let num = 0;
|
||||
let labels = Object.keys(node).sort((la, lb) => {
|
||||
let na = node[la];
|
||||
let nb = node[lb];
|
||||
|
||||
let aIsLeaf = typeof na === "object" && 'ID' in na;
|
||||
let bIsLeaf = typeof nb === "object" && 'ID' in nb;
|
||||
|
||||
if (aIsLeaf !== bIsLeaf) {
|
||||
return aIsLeaf - bIsLeaf;
|
||||
} else if (la < lb) {
|
||||
return -1
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
for (const label of labels) {
|
||||
for (const label of Object.keys(node)) {
|
||||
if (label === "parent")
|
||||
continue;
|
||||
|
||||
|
||||
+92
-44
@@ -456,51 +456,111 @@ export let Polyline = (function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline.prototype.intersectsBBox = function(x, y, w, h, view) {
|
||||
for (let i = 0; i < this.raDecArray.length - 1; i++) {
|
||||
let p1 = this.raDecArray[i];
|
||||
let p2 = this.raDecArray[i + 1];
|
||||
Polyline.prototype.intersectsBBox = function (x, y, w, h, view) {
|
||||
let n = this.raDecArray.length;
|
||||
if (n < 2) return false;
|
||||
|
||||
let xy1 = view.aladin.world2pix(p1[0], p1[1]);
|
||||
let xy2 = view.aladin.world2pix(p2[0], p2[1]);
|
||||
// 2️⃣ Edge intersection test
|
||||
let i = this.closed ? n - 1 : 0;
|
||||
let j = this.closed ? 0 : 1;
|
||||
|
||||
let poly = [];
|
||||
while (j < n) {
|
||||
const p1 = this.raDecArray[i];
|
||||
const p2 = this.raDecArray[j];
|
||||
|
||||
const xy1 = view.aladin.world2pix(p1[0], p1[1]);
|
||||
const xy2 = view.aladin.world2pix(p2[0], p2[1]);
|
||||
|
||||
// Skip invalid segments, do NOT abort
|
||||
if (!xy1 || !xy2) {
|
||||
return false;
|
||||
i = j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
xy1 = {x: xy1[0], y: xy1[1]};
|
||||
xy2 = {x: xy2[0], y: xy2[1]};
|
||||
|
||||
// Check if line segment intersects with the bounding box
|
||||
if (this.lineIntersectsBox(xy1, xy2, x, y, w, h)) {
|
||||
const a = { x: xy1[0], y: xy1[1] };
|
||||
const b = { x: xy2[0], y: xy2[1] };
|
||||
|
||||
poly.push(a);
|
||||
|
||||
if (Polyline.segmentIntersectsBox(a, b, x, y, w, h)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
i = j++;
|
||||
}
|
||||
|
||||
if (this.closed && poly.length === this.raDecArray.length) {
|
||||
console.log("closed poly")
|
||||
const corners = [
|
||||
{ x, y },
|
||||
{ x: x + w, y },
|
||||
{ x: x + w, y: y + h },
|
||||
{ x, y: y + h }
|
||||
];
|
||||
|
||||
for (const c of corners) {
|
||||
if (Polyline.pointInPolygon(c, poly)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline.prototype.lineIntersectsBox = function(p1, p2, x, y, w, h) {
|
||||
// Check if line segment is completely outside the box
|
||||
if ((p1.x < x && p2.x < x) ||
|
||||
(p1.y < y && p2.y < y) ||
|
||||
(p1.x > x + w && p2.x > x + w) ||
|
||||
(p1.y > y + h && p2.y > y + h)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let m = (p2.y - p1.y) / (p2.x - p1.x); // Slope of the line
|
||||
let c = p1.y - m * p1.x; // y-intercept of the line
|
||||
Polyline.segmentIntersectsBox = function (p1, p2, x, y, w, h) {
|
||||
const x2 = x + w;
|
||||
const y2 = y + h;
|
||||
|
||||
// Check if line intersects with the sides of the box
|
||||
if ((p1.y >= y && p1.y <= y + h) ||
|
||||
(p2.y >= y && p2.y <= y + h) ||
|
||||
(m * x + c >= y && m * x + c <= y + h) ||
|
||||
(m * (x + w) + c >= y && m * (x + w) + c <= y + h)) {
|
||||
// 1️⃣ Endpoint inside box
|
||||
if (Polyline.pointInBox(p1, x, y, x2, y2) ||
|
||||
Polyline.pointInBox(p2, x, y, x2, y2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// 2️⃣ Check intersection with 4 box edges
|
||||
return (
|
||||
Polyline.segmentsIntersect(p1, p2, { x, y }, { x: x2, y }) || // top
|
||||
Polyline.segmentsIntersect(p1, p2, { x: x2, y }, { x: x2, y: y2 }) || // right
|
||||
Polyline.segmentsIntersect(p1, p2, { x: x2, y: y2 }, { x, y: y2 }) || // bottom
|
||||
Polyline.segmentsIntersect(p1, p2, { x, y: y2 }, { x, y }) // left
|
||||
);
|
||||
};
|
||||
|
||||
Polyline.pointInBox = function (p, x1, y1, x2, y2) {
|
||||
return p.x >= x1 && p.x <= x2 && p.y >= y1 && p.y <= y2;
|
||||
};
|
||||
|
||||
Polyline.pointInPolygon = function (xy, poly) {
|
||||
let inside = false;
|
||||
|
||||
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
||||
const xi = poly[i].x, yi = poly[i].y;
|
||||
const xj = poly[j].x, yj = poly[j].y;
|
||||
|
||||
const intersect =
|
||||
((yi > xy.y) !== (yj > xy.y)) &&
|
||||
(xy.x < (xj - xi) * (xy.y - yi) / (yj - yi) + xi);
|
||||
|
||||
if (intersect) inside = !inside;
|
||||
}
|
||||
|
||||
return inside;
|
||||
};
|
||||
|
||||
Polyline.segmentsIntersect = function (p1, p2, p3, p4) {
|
||||
function orient(a, b, c) {
|
||||
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
||||
}
|
||||
|
||||
const o1 = orient(p1, p2, p3);
|
||||
const o2 = orient(p1, p2, p4);
|
||||
const o3 = orient(p3, p4, p1);
|
||||
const o4 = orient(p3, p4, p2);
|
||||
|
||||
return o1 * o2 < 0 && o3 * o4 < 0;
|
||||
};
|
||||
|
||||
// static methods
|
||||
@@ -516,10 +576,10 @@ export let Polyline = (function() {
|
||||
|
||||
// check if the line has hit any of the rectangle's sides
|
||||
// uses the Line/Line function below
|
||||
let left = Polyline._intersectLine(x1, y1, x2, y2, 0, 0, 0, rh);
|
||||
let right = Polyline._intersectLine(x1, y1, x2, y2, rw, 0, rw, rh);
|
||||
let top = Polyline._intersectLine(x1, y1, x2, y2, 0, 0, rw, 0);
|
||||
let bottom = Polyline._intersectLine(x1, y1, x2, y2, 0, rh, rw, rh);
|
||||
let left = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: 0, y: 0}, {x: 0, y: rh});
|
||||
let right = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: rw, y: 0}, {x: rw, y: rh});
|
||||
let top = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: 0, y: 0}, {x: rw, y: 0});
|
||||
let bottom = Polyline.segmentsIntersect({x: x1, y: y1}, {x: x2, y: y2}, {x: 0, y: rh}, {x: rw, y: rh});
|
||||
|
||||
// if ANY of the above are true, the line
|
||||
// has hit the rectangle
|
||||
@@ -530,17 +590,5 @@ export let Polyline = (function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
Polyline._intersectLine = function(x1, y1, x2, y2, x3, y3, x4, y4) {
|
||||
// Calculate the direction of the lines
|
||||
let uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
|
||||
let uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
|
||||
|
||||
// If uA and uB are between 0-1, lines are colliding
|
||||
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return Polyline;
|
||||
})();
|
||||
|
||||
@@ -193,7 +193,7 @@ export let Vector = (function() {
|
||||
xy2 = {x: xy2[0], y: xy2[1]};
|
||||
|
||||
// Check if line segment intersects with the bounding box
|
||||
if (this.lineIntersectsBox(xy1, xy2, x, y, w, h)) {
|
||||
if (Polyline.segmentIntersectsBox(xy1, xy2, x, y, w, h)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user