toggle refac + toolbar

This commit is contained in:
Matthieu Baumann
2026-01-29 19:21:24 +01:00
committed by Matthieu Baumann
parent 09ebaeea79
commit e7d58d42ee
20 changed files with 4293 additions and 4011 deletions
+2
View File
@@ -23,6 +23,8 @@
reticleSize: 64, // change reticle size
showContextMenu: true,
showShareControl: true,
showCooGridControl: true,
showColorPickerControl: true,
showFrame: true,
showZoomControl:true,
showSettingsControl:true,
+3515 -3515
View File
File diff suppressed because it is too large Load Diff
+15 -35
View File
@@ -837,7 +837,13 @@
margin-left: 2px;
}
.aladin-context-menu-item:hover > .aladin-context-sub-menu {
.aladin-stack-box .aladin-overlay-label {
text-align: center;
width: 100%;
}
.aladin-context-menu-item:hover > .aladin-context-sub-menu,
.aladin-context-menu-item:focus-within > .aladin-context-sub-menu {
display: block;
}
@@ -1140,18 +1146,6 @@ otherwise it fits its content options. If those are too big the select can go ou
*
*/
.aladin-stack-control {
position: absolute;
top: 3rem;
left: 0.2rem;
}
.aladin-settings-control {
position: absolute;
top: 5.4rem;
left: 0.2rem;
}
.aladin-indicator {
display: inline-block;
width: 10px;
@@ -1173,25 +1167,6 @@ otherwise it fits its content options. If those are too big the select can go ou
text-decoration: underline;
}
.aladin-simbadPointer-control {
position: absolute;
top: 7.8rem;
left: 0.2rem;
}
.aladin-grid-control {
position: absolute;
top: 10.2rem;
left: 0.2rem;
}
.aladin-colorPicker-control {
position: absolute;
top: 15rem;
left: 0.2rem;
}
.aladin-cooFrame {
position: absolute;
top: 0.2rem;
@@ -1208,6 +1183,7 @@ otherwise it fits its content options. If those are too big the select can go ou
min-width: 17rem;
max-width: 300px;
}
.aladin-item-selected {
border: var(--border-size) solid orange;
}
@@ -1323,10 +1299,14 @@ otherwise it fits its content options. If those are too big the select can go ou
color: var(--text-color);
}
.aladin-share-control {
.aladin-widgets-toolbar {
position: absolute;
top: 12.6rem;
left: 0.2rem;
top: 3rem;
left: .2rem;
}
.aladin-widgets-toolbar > * {
padding-top: 0rem;
}
.aladin-fullScreen-control {
+40 -36
View File
@@ -42,7 +42,8 @@ import { Coo } from "./libs/astro/coo.js";
import { CooConversion } from "./CooConversion.js";
import { HiPSCache } from "./HiPSCache.js";
import { HiPSList } from "./DefaultHiPSList.js";
import stackOverlayIconUrl from './../../assets/icons/stack.svg';
import { Toolbar } from "./gui/Toolbar.js";
import { ProjectionEnum } from "./ProjectionEnum.js";
import { ALEvent } from "./events/ALEvent.js";
@@ -64,17 +65,18 @@ import A from "./A.js";
import { StatusBarBox } from "./gui/Box/StatusBarBox.js";
import { FullScreenActionButton } from "./gui/Button/FullScreen.js";
import { ProjectionActionButton } from "./gui/Button/Projection.js";
import { Stack } from "./gui/Button/Stack.js";
// features
import { SettingsButton } from "./gui/Button/Settings";
import { SimbadPointer } from "./gui/Button/SimbadPointer";
import { ColorPicker } from "./gui/Button/ColorPicker";
import { OverlayStackButton } from "./gui/Button/OverlayStack";
import { OverlayStackBox } from "./gui/Box/StackBox.js";
import { GridEnabler } from "./gui/Button/GridEnabler";
import { CooFrame } from "./gui/Input/CooFrame";
import { Circle } from "./shapes/Circle";
import { Ellipse } from "./shapes/Ellipse";
import { Polyline } from "./shapes/Polyline";
import { WidgetTogglerButton } from "./gui/Button/Toggler.js";
/**
* @typedef {Object} AladinOptions
@@ -586,50 +588,52 @@ export let Aladin = (function () {
}
////////////////////////////////////////////////////
let stack = new OverlayStackButton(this);
let simbad = new SimbadPointer(this);
let colorPicker = new ColorPicker(this);
let grid = new GridEnabler(this);
this.addUI(stack);
this.addUI(simbad);
this.addUI(grid);
this.addUI(colorPicker)
let widgets = {};
// Add the layers control
if (!options.showLayersControl) {
stack._hide();
}
// Add the simbad pointer control
if (!options.showSimbadPointerControl) {
simbad._hide();
}
// Add the projection control
// Add the coo grid control
if (!options.showCooGridControl) {
grid._hide();
}
// Add the projection control
// Add the coo grid control
if (!options.showColorPickerControl) {
colorPicker._hide();
if (options.showLayersControl) {
let stack = new Stack(this);
widgets["stack"] = stack
}
// Settings control
if (options.showSettingsControl) {
let settings = new SettingsButton(this, {
features: { stack, simbad, grid },
});
this.addUI(settings);
let settings = new SettingsButton(this);
widgets["settings"] = settings
}
// Add the simbad pointer control
if (options.showSimbadPointerControl) {
let simbad = new SimbadPointer(this);
widgets["simbad"] = simbad
}
// Add the projection control
// Add the coo grid control
if (options.showCooGridControl) {
let grid = new GridEnabler(this);
widgets["grid"] = grid;
}
// Add the projection control
// Add the coo grid control
if (options.showColorPickerControl) {
let picker = new ColorPicker(this);
widgets["picker"] = picker;
}
// share control panel
if (options.showShareControl) {
this.addUI(new ShareActionButton(self));
let share = new ShareActionButton(this);
widgets["share"] = share;
}
let toolbar = new Toolbar(widgets, {
classList: ["aladin-widgets-toolbar"]
})
this.toolbar = toolbar;
this.addUI(toolbar)
if (options.showProjectionControl) {
this.projBtn = new ProjectionActionButton(this);
this.addUI(this.projBtn);
@@ -768,7 +772,7 @@ export let Aladin = (function () {
self.isInFullscreen = !self.isInFullscreen;
ContextMenu.hideAll();
this.contextMenu && this.contextMenu._hide();
this.ui.forEach(ui => {
if (ui.toggle) {
+3 -1
View File
@@ -362,7 +362,9 @@ export let Image = (function () {
// Private method for updating the view with the new meta
Image.prototype._updateMetadata = HiPS.prototype._updateMetadata;
Image.prototype._add2View = function (layer) {
Image.prototype._removeFromView = HiPS.prototype._removeFromView;
Image.prototype._addToView = function (layer) {
this.layer = layer;
let self = this;
+1 -1
View File
@@ -944,7 +944,7 @@ export let View = (function () {
DefaultActionsForContextMenu.getDefaultActions(view.aladin),
null
);
ctxMenu.show({e});
ctxMenu._show({e});
}
view.rightClick = false;
+13 -14
View File
@@ -27,7 +27,7 @@ import filterOffUrl from "../../../../assets/icons/filter-off.svg";
import helpIconUrl from "../../../../assets/icons/help.svg";
import { Input } from "../Widgets/Input.js";
import { TogglerActionButton } from "../Button/Toggler.js";
import { WidgetTogglerButton } from "../Button/Toggler.js";
import { Layout } from "../Layout.js";
import { HiPSFilterBox } from "./HiPSFilterBox.js";
import A from "../../A.js";
@@ -262,7 +262,12 @@ export class HiPSBrowserBox extends Box {
let infoCurrentHiPSBtn = ActionButton.BUTTONS(aladin)
.infoHiPS({disable: true})
let filterBtn = new TogglerActionButton({
let filterBox = new HiPSFilterBox(aladin, {
callback: (params) => {
self._filterHiPSList(params);
},
})
let filterBtn = new WidgetTogglerButton({
icon: {
url: filterOffUrl,
monochrome: true,
@@ -273,14 +278,12 @@ export class HiPSBrowserBox extends Box {
position: { direction: "top" },
},
toggled: false,
actionOn: (e) => {
self.filterBox._show({position: {
widget: {
position: {
anchor: 'right center'
}});
},
actionOff: (e) => {
self.filterBox._hide();
},
},
obj: filterBox,
}
});
let filterNumberElt = document.createElement("div");
@@ -331,11 +334,7 @@ export class HiPSBrowserBox extends Box {
self = this;
this.searchTree = searchTree;
this.filterBox = new HiPSFilterBox(aladin, {
callback: (params) => {
self._filterHiPSList(params);
},
})
this.filterBox = filterBox;
this.filterNumberElt = filterNumberElt;
this.filterBox._hide();
+4 -5
View File
@@ -224,8 +224,7 @@ export class HiPSCompositeBox extends Box {
}, this.aladin.aladinDiv);
layerSettingsBox._hide()
// catalog settings
let layerSettingsBtn = new TogglerActionButton({
/*let layerSettingsBtn = new TogglerActionButton({
icon: { url: settingsIconUrl, monochrome: true },
size: "small",
tooltip: {
@@ -233,7 +232,7 @@ export class HiPSCompositeBox extends Box {
position: { direction: "top" },
},
toggled: false,
actionOn: (_) => {
on: (_) => {
layerSettingsBox._show({
position: {
nextTo: layerSettingsBtn,
@@ -248,13 +247,13 @@ export class HiPSCompositeBox extends Box {
self.openSettings = layerSettingsBtn;
},
actionOff: (_) => {
off: (_) => {
layerSettingsBox._hide();
if (self.openSettings === layerSettingsBtn) {
self.openSettings = null;
}
},
});
});*/
return layerSettingsBtn
}
+5 -6
View File
@@ -36,7 +36,7 @@ import { Form } from "../Widgets/Form.js";
import pixelHistIconUrl from '../../../../assets/icons/pixel_histogram.svg';
import { RadioButton } from "../Widgets/Radio.js";
import waveOnIconUrl from '../../../../assets/icons/wave-on.svg';
import { TogglerActionButton } from "../Button/Toggler.js";
import { WidgetTogglerButton } from "../Button/Toggler.js";
import { Layout } from "../Layout.js";
export class HiPSSettingsBox extends Box {
@@ -317,7 +317,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
if (options.layer.isSpectralCube && options.layer.isSpectralCube()) {
let spectraDisplayer = self.aladin.view.spectraDisplayer;
self.spectraBtn = new TogglerActionButton({
self.spectraBtn = new WidgetTogglerButton({
content: 'Spectra',
icon: {
size: 'small',
@@ -326,12 +326,11 @@ import { TogglerActionButton } from "../Button/Toggler.js";
},
tooltip: {content: 'Show/hide spectra', position: {direction: 'bottom'}},
toggled: true,
actionOn: () => {
enabled(o) {
spectraDisplayer.attachHiPS3D(options.layer)
spectraDisplayer.show()
},
actionOff: () => {
spectraDisplayer.hide()
widget: {
obj: spectraDisplayer
}
});
+43 -64
View File
@@ -45,7 +45,7 @@ import settingsIconUrl from "../../../../assets/icons/settings.svg";
import searchIconImg from "../../../../assets/icons/search.svg";
import downloadIconUrl from '../../../../assets/icons/download.svg';
import swapIcon from '../../../../assets/icons/swap.svg'
import { TogglerActionButton } from "../Button/Toggler.js";
import { WidgetTogglerButton } from "../Button/Toggler.js";
import { Icon } from "../Widgets/Icon.js";
import { Box } from "../Widgets/Box.js";
import { CtxMenuActionButtonOpener } from "../Button/CtxMenuOpener.js";
@@ -126,7 +126,7 @@ export class OverlayStackBox extends Box {
},
};
// Constructor
constructor(aladin, stackBtn) {
constructor(aladin) {
super(
{
close: true,
@@ -138,8 +138,6 @@ export class OverlayStackBox extends Box {
},
aladin.aladinDiv
);
this.stackBtn = stackBtn;
this.aladin = aladin;
this.mode = "stack";
@@ -730,12 +728,9 @@ export class OverlayStackBox extends Box {
}
}
if (this.addOverlayBtn) this.addOverlayBtn.hideMenu();
if (this.addOverlayBtn) this.addOverlayBtn.close();
if (this.addHiPSBtn) this.addHiPSBtn.hideMenu();
// toggle the button because the window is closed
this.stackBtn.update({toggled: false});
if (this.addHiPSBtn) this.addHiPSBtn.close();
super._hide();
}
@@ -767,6 +762,7 @@ export class OverlayStackBox extends Box {
_createOverlaysList() {
let self = this;
let aladin = self.aladin;
let layout = [];
const overlays = Array.from(this.aladin.getOverlays())
@@ -848,21 +844,15 @@ export class OverlayStackBox extends Box {
label: 'Shape',
name: 'shape',
type: 'select',
options: (() => {
if (overlay.shapeFn) {
return ['custom']
} else {
return [
{ value: "plus", label: "+" },
{ value: "rhomb", label: "" },
{ value: "triangle", label: "△" },
{ value: "cross", label: "✕" },
{ value: "square", label: "□" },
{ value: "circle", label: "○" },
]
}
})(),
value: overlay.shape,
options: [
{ value: "plus", label: "+" },
{ value: "rhomb", label: "◇" },
{ value: "triangle", label: "△" },
{ value: "cross", label: "✕" },
{ value: "square", label: "" },
{ value: "circle", label: "" },
],
value: (overlay.shapeFn && "square") || overlay.shape,
change: (e) => {
const shape = e.target.value
overlay.setShape(shape)
@@ -884,7 +874,7 @@ export class OverlayStackBox extends Box {
catSettingsBox._hide()
// catalog settings
let catSettingsBtn = new TogglerActionButton({
let catSettingsBtn = new WidgetTogglerButton({
icon: { url: settingsIconUrl, monochrome: true },
size: "small",
tooltip: {
@@ -892,7 +882,7 @@ export class OverlayStackBox extends Box {
position: { direction: "top" },
},
toggled: false,
actionOn: (e) => {
enable: (_) => {
// toggle off the other settings if opened
for (var l in self.ui) {
let ui = self.ui[l]
@@ -903,17 +893,16 @@ export class OverlayStackBox extends Box {
}
}
catSettingsBox._show({
position: {
nextTo: catSettingsBtn,
direction: "right",
aladin: self.aladin,
},
});
},
actionOff: (e) => {
catSettingsBox._hide();
let spectraDisplayer = aladin.view.spectraDisplayer;
if (spectraDisplayer)
spectraDisplayer.attachHiPS3D(options.layer)
},
widget: {
obj: catSettingsBox,
position: {
direction: "right",
}
}
});
optBtn.push(catSettingsBtn);
@@ -933,12 +922,11 @@ export class OverlayStackBox extends Box {
}
));
layout.push(
{
start: [this._addOverlayIcon(overlay), name],
end: [optBtn]
},
);
layout.push([
this._addOverlayIcon(overlay),
'<div class="aladin-overlay-label">' + name + "</div>",
optBtn
]);
}
return layout;
@@ -999,7 +987,7 @@ export class OverlayStackBox extends Box {
let deleteBtn = ActionButton.createSmallSizedIconBtn({
icon: { url: removeIconUrl, monochrome: true },
tooltip: { content: "Remove", position: { direction: "top" } },
action(e) {
action: (e) => {
aladin.removeImageLayer(hips.layer);
// remove HiPS cube player if any
aladin.removeUIByName("cube_displayer" + hips.layer)
@@ -1045,13 +1033,10 @@ export class OverlayStackBox extends Box {
},
});
if (!this.settingsBox) {
this.settingsBox = new HiPSSettingsBox(self.aladin);
}
let settingsBox = new HiPSSettingsBox(self.aladin);
settingsBox._hide();
this.settingsBox._hide();
let settingsBtn = new TogglerActionButton({
let settingsBtn = new WidgetTogglerButton({
icon: { url: settingsIconUrl, monochrome: true },
size: "small",
tooltip: {
@@ -1059,7 +1044,7 @@ export class OverlayStackBox extends Box {
position: { direction: "top" },
},
toggled: false,
actionOn: (e) => {
enable: (_) => {
// toggle off the other settings if opened
for (var l in self.ui) {
let ui = self.ui[l]
@@ -1069,18 +1054,14 @@ export class OverlayStackBox extends Box {
}
}
this.settingsBox.update({ layer: hips });
this.settingsBox._show({
position: {
nextTo: settingsBtn,
direction: "right",
aladin: self.aladin,
},
});
},
actionOff: (e) => {
this.settingsBox._hide();
settingsBox.update({ layer: hips });
},
widget: {
obj: settingsBox,
position: {
direction: "right",
}
}
});
let loadMOCBtn = ActionButton.BUTTONS(self.aladin)
@@ -1135,7 +1116,7 @@ export class OverlayStackBox extends Box {
if (!(hips.layer in self.ui)) {
self.ui[hips.layer] = {
HiPSSelector: HiPSselect,
settingsBox: this.settingsBox,
settingsBox,
settingsBtn,
showBtn,
};
@@ -1200,7 +1181,5 @@ export class OverlayStackBox extends Box {
...options,
...{ position: this.position },
});
this.stackBtn.update({toggled: true});
}
}
+81 -27
View File
@@ -28,12 +28,10 @@
*
*****************************************************************************/
import { ActionButton } from "../Widgets/ActionButton.js";
import { WidgetTogglerButton } from "./Toggler.js";
/*
export class CtxMenuActionButtonOpener extends ActionButton {
static currentlyOpened = null;
// Constructor
constructor(options, aladin) {
let self;
@@ -49,36 +47,19 @@ export class CtxMenuActionButtonOpener extends ActionButton {
})
};
super({
action(e) {
enableTooltips()
let isHidden = self.ctxMenu.isHidden;
let wasClosed = self.ctxMenu.isHidden;
self.close()
self.ctxMenu._hide()
if (self.ctxMenu.attached === self && !isHidden) {
if (self.ctxMenu.toggler === self && !wasClosed) {
return;
}
// If it was hidden then reopen it
if (options.action) {
options.action(e)
}
if (self.layout) {
self.ctxMenu.attach(self.layout, self)
}
self.ctxMenu.show({
position: {
nextTo: self,
direction: options.openDirection,
},
});
CtxMenuActionButtonOpener.currentlyOpened = self;
self.open(e);
// the panel is now open and we know the button has a tooltip
// => we close it!
@@ -98,12 +79,85 @@ export class CtxMenuActionButtonOpener extends ActionButton {
this.layout = options.ctxMenu;
}
hideMenu() {
close() {
this.closed = true;
this.ctxMenu._hide();
}
open(e) {
if (this.layout) {
this.ctxMenu.attach(this.layout, this)
}
this.ctxMenu.show({
position: {
nextTo: this,
direction: this.options.openDirection,
},
});
this.closed = false;
}
_hide() {
this.hideMenu();
this.close();
super._hide();
}
}*/
export class CtxMenuActionButtonOpener extends WidgetTogglerButton {
// Constructor
constructor(options, aladin) {
let self;
const enableTooltips = () => {
aladin.aladinDiv.removeEventListener('click', enableTooltips);
aladin.aladinDiv.querySelectorAll('.aladin-tooltip')
// for each tooltips reset its visibility and transition delay
.forEach((t) => {
t.style.visibility = ''
t.style.transitionDelay = ''
})
};
super({
widget: {
obj: aladin.contextMenu,
position: {direction: (options && options.openDirection) || 'right'}
},
enable(e) {
enableTooltips()
// If it was hidden then reopen it
if (self.layout) {
self.ctxMenu.attach(self.layout, self)
}
// the panel is now open and we know the button has a tooltip
// => we close it!
if (self.tooltip && !self.ctxMenu.isHidden) {
self.tooltip.element().style.visibility = 'hidden'
self.tooltip.element().style.transitionDelay = '0ms';
aladin.aladinDiv.addEventListener("click", enableTooltips)
}
},
...options,
})
self = this;
this.ctxMenu = aladin.contextMenu;
this.layout = options.ctxMenu;
}
update(options) {
if (options && options.ctxMenu) {
console.log(this.ctxMenu, "attach", options.ctxMenu)
this.layout = options.ctxMenu;
this.ctxMenu.attach(this.layout, this)
}
super.update(options)
}
}
+4 -2
View File
@@ -44,7 +44,9 @@ import { ALEvent } from "../../events/ALEvent";
constructor(aladin, options) {
options = options || {};
options.verbosity = (options && options.verbosity) || 'full';
let projectionName = aladin.getProjectionName();
let self;
let ctxMenu = _buildLayout(aladin);
super({
@@ -57,9 +59,11 @@ import { ALEvent } from "../../events/ALEvent";
content: projectionName,
tooltip: {content: 'Change the view projection', position: {direction: 'bottom left'}},
ctxMenu,
openDirection: 'left',
...options
}, aladin);
self = this;
this.aladin = aladin;
this._addEventListeners()
@@ -81,13 +85,11 @@ import { ALEvent } from "../../events/ALEvent";
function _buildLayout(aladin) {
let layout = [];
let aladinProj = aladin.getProjectionName();
for (const key in ProjectionEnum) {
let proj = ProjectionEnum[key];
layout.push({
label: proj.label,
selected: aladinProj === key,
action(o) {
aladin.setProjection(key)
}
+289 -226
View File
@@ -27,6 +27,11 @@ import { Utils } from "../../Utils";
import { GridSettingsCtxMenu } from "./../CtxMenu/GridSettings.js";
import { CtxMenuActionButtonOpener } from "./CtxMenuOpener";
import settingsIconUrl from './../../../../assets/icons/settings.svg';
import { SimbadPointer } from "./SimbadPointer.js";
import { GridEnabler } from "./GridEnabler.js";
import { Stack } from "./Stack.js";
import { ColorPicker } from "./ColorPicker.js";
import { ShareActionButton } from "./ShareView.js";
/******************************************************************************
* Aladin Lite project
@@ -62,248 +67,306 @@ import settingsIconUrl from './../../../../assets/icons/settings.svg';
direction: 'right'
}
},
ctxMenu: _buildLayout(aladin, options),
ctxMenu: undefined,
...options
}, aladin);
}
}
function _buildLayout(aladin, options) {
let backgroundColorInput = Input.color({
name: 'color',
value: (() => {
let {r, g, b} = aladin.getBackgroundColor();
return Color.rgbToHex(r, g, b);
})(),
change(e) {
let hex = e.target.value;
aladin.setBackgroundColor(hex)
}
});
let reticleColorInput = Input.color({
value: new Color(aladin.getReticle().getColor()).toHex(),
name: 'reticleColor',
change(e) {
let hex = e.target.value;
aladin.setDefaultColor(hex)
}
});
// Event received from aladin
ALEvent.BACKGROUND_COLOR_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
const {r, g, b} = e.detail.color;
let hex = Color.rgbToHex(r, g, b);
backgroundColorInput.set(hex)
});
ALEvent.RETICLE_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
const color = e.detail.color;
let hex = new Color(color).toHex();
reticleColorInput.set(hex)
});
const toggleCheckbox = (checkbox) => {
const pastVal = checkbox.get();
const curVal = !pastVal;
checkbox.set(curVal)
return curVal;
};
let hpxGridCheckbox = Input.checkbox({
name: 'hpxgrid', checked: aladin.healpixGrid(),
click(e) {
let newVal = toggleCheckbox(hpxGridCheckbox);
aladin.showHealpixGrid(newVal)
}
})
let reticleCheckbox = Input.checkbox({
name: 'reticle',
checked: aladin.isReticleDisplayed(),
click(e) {
let newVal = toggleCheckbox(reticleCheckbox);
aladin.showReticle(newVal)
}
})
let features = options && options.features;
const toggleFeature = (name) => {
let feature = features[name];
if(feature.isHidden) {
feature._show();
} else {
feature._hide();
}
this.aladin = aladin;
let ctxMenu = this._buildLayout()
this.update({ctxMenu})
}
let reticle = aladin.getReticle();
let sliderReticleSize = Input.slider({
name: 'reticleSize',
type: 'range',
min: 0.0,
max: 50,
value: reticle.getSize(),
change(e) {
reticle.update({size: e.target.value})
}
});
let sampBtn = new SAMPActionButton({
size: 'small',
action(conn) {
if (conn.isConnected()) {
conn.unregister();
} else {
conn.register();
_buildLayout() {
let self = this;
let aladin = this.aladin;
let backgroundColorInput = Input.color({
name: 'color',
value: (() => {
let {r, g, b} = aladin.getBackgroundColor();
return Color.rgbToHex(r, g, b);
})(),
change(e) {
let hex = e.target.value;
aladin.setBackgroundColor(hex)
}
});
//self._hide()
}
}, aladin);
return [
GridSettingsCtxMenu.getLayout(aladin),
{
label: {
content: ['Reticle']
},
subMenu: [
{
label: {
content: [reticleCheckbox, 'Show/Hide']
},
mustHide: false,
action(o) {
let newVal = toggleCheckbox(reticleCheckbox);
aladin.showReticle(newVal)
}
},
{
label: {
content: [reticleColorInput, 'Color']
},
},
{
label: Layout.horizontal(['Size', sliderReticleSize]),
}
]
},
{
label: {
content: [backgroundColorInput, 'Back color']
},
},
{
label: {
content: 'Light/Dark mode'
},
action(o) {
const currentTheme = aladin.aladinDiv.getAttribute("data-theme");
const newTheme = currentTheme === "dark" ? "light" : "dark";
aladin.aladinDiv.setAttribute("data-theme", newTheme);
localStorage.setItem("theme", newTheme);
let reticleColorInput = Input.color({
value: new Color(aladin.getReticle().getColor()).toHex(),
name: 'reticleColor',
change(e) {
let hex = e.target.value;
aladin.setDefaultColor(hex)
}
},
{
label: {
content: [hpxGridCheckbox, 'HEALPix grid']
},
mustHide: false,
action(o) {
});
// Event received from aladin
ALEvent.BACKGROUND_COLOR_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
const {r, g, b} = e.detail.color;
let hex = Color.rgbToHex(r, g, b);
backgroundColorInput.set(hex)
});
ALEvent.RETICLE_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
const color = e.detail.color;
let hex = new Color(color).toHex();
reticleColorInput.set(hex)
});
const toggleCheckbox = (checkbox) => {
const pastVal = checkbox.get();
const curVal = !pastVal;
checkbox.set(curVal)
return curVal;
};
let hpxGridCheckbox = Input.checkbox({
name: 'hpxgrid', checked: aladin.healpixGrid(),
click(e) {
let newVal = toggleCheckbox(hpxGridCheckbox);
aladin.showHealpixGrid(newVal)
}
},
{
label: {
content: [sampBtn, 'SAMP']
},
},
{
label: 'Tools',
subMenu: [
{
label: 'Stack',
selected: !features['stack'].isHidden,
action(o) {
toggleFeature('stack')
}
},
{
label: 'Simbad',
selected: !features['simbad'].isHidden,
action(o) {
toggleFeature('simbad');
}
},
{
label: 'Grid',
selected: !features['grid'].isHidden,
action(o) {
toggleFeature('grid');
}
})
let reticleCheckbox = Input.checkbox({
name: 'reticle',
checked: aladin.isReticleDisplayed(),
click(e) {
let newVal = toggleCheckbox(reticleCheckbox);
aladin.showReticle(newVal)
}
})
let reticle = aladin.getReticle();
let sliderReticleSize = Input.slider({
name: 'reticleSize',
type: 'range',
min: 0.0,
max: 50,
value: reticle.getSize(),
change(e) {
reticle.update({size: e.target.value})
}
});
let sampBtn = new SAMPActionButton({
size: 'small',
action(conn) {
if (conn.isConnected()) {
conn.unregister();
} else {
conn.register();
}
]
},
{
label: {
icon: {
monochrome: true,
tooltip: {content: 'Documentation about Aladin Lite', position: {direction: 'top'}},
url: helpIconBtn,
size: 'small',
cssStyle: {
cursor: 'help',
}
//self._hide()
}
}, aladin);
return [
GridSettingsCtxMenu.getLayout(aladin),
{
label: {
content: ['Reticle']
},
content: 'Help'
},
subMenu: [
{
label: 'Aladin Lite API',
action(o) {
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/')
}
},
{
label: {
content: 'Contact us',
tooltip: { content: 'For bug reports, discussions, feature ideas...', position: {direction: 'bottom'} }
},
subMenu: [
{
label: 'GitHub',
action(o) {
Utils.openNewTab('https://github.com/cds-astro/aladin-lite/issues')
}
subMenu: [
{
label: {
content: [reticleCheckbox, 'Show/Hide']
},
{
label: 'by email',
action(o) {
Utils.openNewTab('mailto:matthieu.baumann@astro.unistra.fr,thomas.boch@astro.unistra.fr?subject=Aladin Lite issue&body=message%20goes%20here')
mustHide: false,
action(o) {
let newVal = toggleCheckbox(reticleCheckbox);
aladin.showReticle(newVal)
}
},
{
label: {
content: [reticleColorInput, 'Color']
},
},
{
label: Layout.horizontal(['Size', sliderReticleSize]),
}
]
},
{
label: {
content: [backgroundColorInput, 'Back color']
},
},
{
label: {
content: 'Light/Dark mode'
},
mustHide: false,
action(o) {
const currentTheme = aladin.aladinDiv.getAttribute("data-theme");
const newTheme = currentTheme === "dark" ? "light" : "dark";
aladin.aladinDiv.setAttribute("data-theme", newTheme);
localStorage.setItem("theme", newTheme);
}
},
{
label: {
content: [hpxGridCheckbox, 'HEALPix grid']
},
mustHide: false,
action(o) {
let newVal = toggleCheckbox(hpxGridCheckbox);
aladin.showHealpixGrid(newVal)
}
},
{
label: {
content: [sampBtn, 'SAMP']
},
},
{
label: 'Tools',
subMenu: [
{
label: 'Stack',
mustHide: false,
action: (o) => {
let toolbar = aladin.toolbar;
if (!toolbar.has('stack')) {
toolbar.add('stack', new Stack(aladin));
} else {
if (toolbar.enabled('stack')) {
toolbar.disable('stack')
} else {
toolbar.enable('stack')
}
}
}
],
},
{
label: 'Simbad',
mustHide: false,
action: (o) => {
let toolbar = aladin.toolbar;
if (!toolbar.has('simbad')) {
toolbar.add('simbad', new SimbadPointer(aladin));
} else {
if (toolbar.enabled('simbad')) {
toolbar.disable('simbad')
} else {
toolbar.enable('simbad')
}
}
}
},
{
label: 'Grid',
mustHide: false,
action: (o) => {
let toolbar = aladin.toolbar;
if (!toolbar.has('grid')) {
toolbar.add('grid', new GridEnabler(aladin));
} else {
if (toolbar.enabled('grid')) {
toolbar.disable('grid')
} else {
toolbar.enable('grid')
}
}
}
},
{
label: 'Color picker',
mustHide: false,
action: (o) => {
let toolbar = aladin.toolbar;
if (!toolbar.has('picker')) {
toolbar.add('picker', new ColorPicker(aladin));
} else {
if (toolbar.enabled('picker')) {
toolbar.disable('picker')
} else {
toolbar.enable('picker')
}
}
}
},
{
label: 'Share view',
mustHide: false,
action: (o) => {
let toolbar = aladin.toolbar;
if (!toolbar.has('share')) {
toolbar.add('share', new ShareActionButton(aladin));
} else {
if (toolbar.enabled('share')) {
toolbar.disable('share')
} else {
toolbar.enable('share')
}
}
}
},
]
},
{
label: {
icon: {
monochrome: true,
tooltip: {content: 'Documentation about Aladin Lite', position: {direction: 'top'}},
url: helpIconBtn,
size: 'small',
cssStyle: {
cursor: 'help',
}
},
content: 'Help'
},
{
label: 'General documentation',
action(o) {
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/')
subMenu: [
{
label: 'Aladin Lite API',
action(o) {
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/')
}
},
{
label: {
content: 'Contact us',
tooltip: { content: 'For bug reports, discussions, feature ideas...', position: {direction: 'bottom'} }
},
subMenu: [
{
label: 'GitHub',
action(o) {
Utils.openNewTab('https://github.com/cds-astro/aladin-lite/issues')
}
},
{
label: 'by email',
action(o) {
Utils.openNewTab('mailto:matthieu.baumann@astro.unistra.fr,thomas.boch@astro.unistra.fr?subject=Aladin Lite issue&body=message%20goes%20here')
}
}
],
},
{
label: 'General documentation',
action(o) {
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/')
}
},
{
label: Layout.horizontal('Examples', { tooltip: { content: 'How to embed Aladin Lite <br \>into your own webpages!', position: {direction: 'bottom'}}}),
action(o) {
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/')
}
}
},
{
label: Layout.horizontal('Examples', { tooltip: { content: 'How to embed Aladin Lite <br \>into your own webpages!', position: {direction: 'bottom'}}}),
action(o) {
Utils.openNewTab('https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/')
}
}
]
}
]
]
}
]
}
}
@@ -17,11 +17,9 @@
// along with Aladin Lite.
//
import { CtxMenuActionButtonOpener } from "./CtxMenuOpener";
import stackOverlayIconUrl from './../../../../assets/icons/stack.svg';
import { OverlayStackBox } from "../Box/StackBox";
import { ActionButton } from "./../Widgets/ActionButton";
import { WidgetTogglerButton } from "./Toggler";
import stackOverlayIconUrl from "./../../../../assets/icons/stack.svg";
/******************************************************************************
* Aladin Lite project
*
@@ -34,18 +32,22 @@ import { ActionButton } from "./../Widgets/ActionButton";
*
*****************************************************************************/
/**
* Class representing a Tabs layout
* @extends CtxMenuActionButtonOpener
* Class representing the stack
* @extends WidgetTogglerButton
*/
export class OverlayStackButton extends ActionButton {
export class Stack extends WidgetTogglerButton {
/**
* UI responsible for displaying the viewport infos
* @param {Aladin} aladin - The aladin instance.
*/
constructor(aladin, options) {
let self;
let stack;
constructor(aladin) {
super({
widget: {
obj: new OverlayStackBox(aladin),
position: {
direction: "right"
}
},
icon: {
size: 'medium',
monochrome: true,
@@ -58,24 +60,6 @@ import { ActionButton } from "./../Widgets/ActionButton";
direction: 'top right'
}
},
toggled: false,
action(e) {
if (stack.isHidden) {
aladin.contextMenu && aladin.contextMenu._hide()
stack._show({
position: {
nextTo: self,
direction: 'right'
}
})
} else {
stack._hide()
}
},
...options
});
self = this;
stack = new OverlayStackBox(aladin, self);
}
}
+65 -8
View File
@@ -43,8 +43,7 @@ export class TogglerActionButton extends ActionButton {
...options,
toggled,
action(o) {
options.action && options.action(o);
self.toggle(o);
self.toggle(o)
}
})
this.toggled = toggled;
@@ -67,15 +66,73 @@ export class TogglerActionButton extends ActionButton {
toggle(o) {
this.toggled = !this.toggled;
if (this.toggled && this.options.actionOn) {
this.options.actionOn(o)
if (this.toggled && this.options.on) {
this.options.on(o)
}
if (!this.toggled && this.options.actionOff) {
this.options.actionOff(o)
if (!this.toggled && this.options.off) {
this.options.off(o)
}
// once the actions has been executed, modify the styling
this.update({toggled: this.toggled, tooltip: this.toggled ? this.options.tooltipOn : this.options.tooltipOff})
this.update({toggled: this.toggled})
}
}
// It may happen that the widget closes and so the toggler
// has to be notified. For example when the user clicks on a Box that
// is attached to a toggler.
notify(state) {
if (this.toggled === state)
return;
this.toggled = state;
this.update({toggled: this.toggled})
}
}
/**
* Class representing a Tabs layout
* @extends TogglerActionButton
*/
export class WidgetTogglerButton extends TogglerActionButton {
/**
* UI responsible for displaying the viewport infos
* @param {Aladin} aladin - The aladin instance.
*/
constructor(options) {
let self;
let {position, obj} = options && options.widget;
let widget = obj;
let enable = options && options.enable;
super({
toggled: false,
on(o) {
if (enable)
enable(o)
widget._show({position})
},
off(_) {
self.close();
},
...options
});
self = this;
widget.setToggler(this);
this.widget = widget;
if (position && position.direction) {
position['nextTo'] = this;
}
}
close() {
this.widget._hide();
super.close()
}
}
+144
View File
@@ -0,0 +1,144 @@
// 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 { Layout } from "./Layout";
/******************************************************************************
* Aladin Lite project
*
* File gui/Widgets/layout/Horizontal.js
*
* A layout grouping widgets horizontaly
*
*
* Author: Matthieu Baumann[CDS]
*
*****************************************************************************/
export class Toolbar extends Layout {
/**
* Create a layout
* @param {layout: Array.<DOMElement | String>} layout - Represents the structure of the Tabs
* @param {Object} options - Options object
* @param {DOMElement} target - The parent element.
* @param {String} position - The position of the tabs layout relative to the target.
* For the list of possibilities, see https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
*/
constructor(widgets, options, target, position = "beforeend") {
let layout = Object.values(widgets);
super(
layout,
{
vertical: true,
...options
},
target,
position
)
this.toggled = null;
let self = this;
for (let widget of this.layout) {
const action = widget.options.action;
widget.update({
action: (o) => {
// toggle off the current toggled widget
self._toggleOffWidget(widget)
self.toggled = widget;
action(o)
}
})
}
this.widgets = widgets;
}
// Close the toggled widget if the user clicks on another one
_toggleOffWidget(widget) {
if (this.toggled && this.toggled !== widget) {
let canBeClosed = this.toggled && this.toggled.close;
if (canBeClosed) {
this.toggled.close();
}
this.toggled = null;
}
}
has(name) {
return name in this.widgets;
}
enabled(name) {
if (!this.has(name)) {
return false;
}
let widget = this.widgets[name];
return widget.el.disabled === false;
}
enable(name) {
if (!this.has(name)) {
return;
}
let widget = this.widgets[name];
widget.update({disable: false})
}
disable(name) {
if (!this.has(name)) {
return;
}
let widget = this.widgets[name];
widget.update({disable: true})
}
add(name, widget) {
this.widgets[name] = widget;
const action = widget.options.action;
widget.update({
action: (o) => {
// toggle off the current toggled widget
this._toggleOffWidget(widget)
this.toggled = widget;
action(o)
}
})
this.appendLast(widget);
}
remove(name) {
let widget = this.widgets[name];
if (this.toggled === widget)
this.toggled = null;
this.removeItem(widget);
delete this.widgets[name];
widget.remove()
}
}
+30 -14
View File
@@ -25,6 +25,7 @@ import { Layout } from "../Layout";
import infoIconUrl from "../../../../assets/icons/info.svg"
import targetIconUrl from "../../../../assets/icons/target.svg";
import removeIconUrl from "../../../../assets/icons/remove.svg";
import A from "../../A";
/******************************************************************************
* Aladin Lite project
@@ -68,19 +69,20 @@ import A from "../../A";
*
* @example
* const actionButton = new ActionButton({
* toggled: false,
* action: (e) => { /* callback function * },
* title: "Click me",
* iconURL: "path/to/icon.png",
* cssStyle: "color: red;",
* tooltip: {
* position: {
* direction: 'left,
* },
* content: 'A tooltip'
* },
* position: { nextTo: someDOMElement, direction: 'right' }
* }, document.getElementById('container'));
size: 'small',
content: '❌',
//tooltip: {content: 'Close the window', position: {direction: 'bottom'}},
action(e) {
self._hide();
},
cssStyle: {
position: 'absolute',
},
position: {
top: 0,
right: 0,
}
});
*/
export class ActionButton extends DOMElement {
constructor(options, target, position = "beforeend") {
@@ -290,7 +292,21 @@ export class ActionButton extends DOMElement {
},
action
})
}
},
close: (widget) => {
return new ActionButton({
size: 'small',
content: '❌',
action(_) {
widget.close();
},
cssStyle: {
position: 'absolute',
top: 0,
right: 0,
},
});
},
}
}
}
+4 -16
View File
@@ -26,7 +26,7 @@ import { Layout } from "../Layout";
/******************************************************************************
* Aladin Lite project
*
* File gui/Tab.js
* File gui/Widgets/Box.js
*
* A context menu that shows when the user right clicks, or long touch on touch device
*
@@ -62,21 +62,9 @@ export class Box extends DOMElement {
let close = this.options.close === false ? false : true;
let draggable = false;
if (close) {
new ActionButton({
size: 'small',
content: '❌',
//tooltip: {content: 'Close the window', position: {direction: 'bottom'}},
action(e) {
self._hide();
},
cssStyle: {
position: 'absolute',
},
position: {
top: 0,
right: 0,
}
}, this.el);
this.el.appendChild(
ActionButton.BUTTONS(null).close(this).element()
);
}
if (this.options.onDragged) {
+7 -10
View File
@@ -55,7 +55,7 @@ export class ContextMenu extends DOMElement {
this.cssStyleDefault = el.style;
if (!options || options.hideOnClick === undefined || options.hideOnClick === true || typeof options.hideOnClick === 'function') {
/*if (!options || options.hideOnClick === undefined || options.hideOnClick === true || typeof options.hideOnClick === 'function') {
this.aladin.aladinDiv.addEventListener('click', (e) => {
if (!el.contains(e.target)) {
if (options && options.hideOnClick && typeof options.hideOnClick === 'function') {
@@ -65,7 +65,7 @@ export class ContextMenu extends DOMElement {
}
}
});
}
}*/
if (!options || options.hideOnResize === undefined || options.hideOnResize === true) {
if (Utils.hasTouchScreen()) {
@@ -333,7 +333,7 @@ export class ContextMenu extends DOMElement {
parent.style.display = "";
}
show(options) {
_show(options) {
this.el.innerHTML = '';
this.el.style = this.cssStyleDefault
@@ -363,14 +363,11 @@ export class ContextMenu extends DOMElement {
super._show()
}
attach(options, attached) {
this.attached = attached;
this.menuOptions = options;
}
attach(options, toggler) {
this._hide()
this.setToggler(toggler)
/* Hide all the defined menus */
static hideAll() {
ContextMenu._menus.forEach((menu) => menu._hide())
this.menuOptions = options;
}
/// Context menu predefined items
+16 -3
View File
@@ -105,9 +105,10 @@ export class DOMElement {
} else if (elmt instanceof Element) {
parent.insertAdjacentElement('beforeend', elmt);
} else {
let wrapEl = document.createElement('div');
wrapEl.innerHTML = elmt;
parent.insertAdjacentElement('beforeend', wrapEl);
const template = document.createElement('template');
template.innerHTML = elmt;
parent.append(template.content.cloneNode(true));
}
}
}
@@ -297,12 +298,24 @@ export class DOMElement {
}
}
setToggler(toggler) {
this.toggler = toggler;
}
_show() {
if (this.toggler) {
this.toggler.notify(true)
}
this.el.style.display = ""
this.isHidden = false;
}
_hide() {
if (this.toggler) {
this.toggler.notify(false)
}
this.isHidden = true;
this.el.style.display = 'none';
}