@geogirafe/lib-geoportal 1.2.0-dev.2843240863 → 1.2.0-dev.2845014898
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/apigeogirafeapp.js +4 -2
- package/api/style.css +4 -10
- package/assets/i18n/de.json +4 -0
- package/assets/i18n/en.json +4 -0
- package/assets/i18n/fr.json +4 -0
- package/assets/i18n/it.json +4 -0
- package/components/basemap/component.js +1 -1
- package/components/layout/component.d.ts +34 -3
- package/components/layout/component.js +66 -28
- package/components/layout/style.css +13 -0
- package/components/main.d.ts +1 -0
- package/components/main.js +1 -0
- package/components/map-2d/component.d.ts +0 -6
- package/components/map-2d/component.js +3 -22
- package/components/map-3d/component.d.ts +4 -2
- package/components/map-3d/component.js +7 -18
- package/components/map-grid/component.d.ts +70 -0
- package/components/map-grid/component.js +206 -0
- package/components/map-grid/style.css +99 -0
- package/components/menu-buttons-mobile/MenuMobile3dButton.js +3 -1
- package/components/themes-mobile/layer-selected/component.js +1 -1
- package/components/treeview/treeviewitem/component.js +1 -1
- package/package.json +1 -1
- package/styles/iframe.css +4 -10
- package/styles/index.css +4 -10
- package/styles/mobile.css +4 -10
- package/templates/iframe.html +2 -2
- package/templates/index.html +2 -2
- package/templates/mobile.html +2 -2
- package/templates/public/about.json +1 -1
- package/tools/app/geogirafeapp-mobile.js +2 -0
- package/tools/app/geogirafeapp.js +2 -0
- package/tools/configuration/girafeconfig.d.ts +4 -0
- package/tools/configuration/girafeconfig.js +20 -2
- package/tools/main.d.ts +3 -0
- package/tools/main.js +2 -0
- package/tools/share/serializers/globeserializer.d.ts +2 -0
- package/tools/share/serializers/globeserializer.js +26 -4
- package/tools/share/serializers/layoutserializer.d.ts +17 -0
- package/tools/share/serializers/layoutserializer.js +44 -0
- package/tools/share/stateserializer.js +3 -0
- package/tools/state/globe.d.ts +0 -1
- package/tools/state/globe.js +0 -1
- package/tools/state/layout.d.ts +62 -0
- package/tools/state/layout.js +67 -0
- package/tools/state/state.d.ts +2 -0
- package/tools/state/state.js +8 -0
- package/tools/state/statemanager.d.ts +1 -0
- package/tools/state/statemanager.js +8 -0
package/api/apigeogirafeapp.js
CHANGED
|
@@ -4,6 +4,7 @@ import proj4 from 'proj4';
|
|
|
4
4
|
import GirafeHTMLElement from '../base/GirafeHTMLElement.js';
|
|
5
5
|
import Map2dComponent from '../components/map-2d/component.js';
|
|
6
6
|
import Map3dComponent from '../components/map-3d/component.js';
|
|
7
|
+
import MapGridComponent from '../components/map-grid/component.js';
|
|
7
8
|
import { register } from 'ol/proj/proj4.js';
|
|
8
9
|
import GirafeApiContext from './apicontext.js';
|
|
9
10
|
import BasemapComponent from '../components/basemap/component.js';
|
|
@@ -35,10 +36,10 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
35
36
|
return uHtml `<style>
|
|
36
37
|
.hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}button,input,select,textarea{font:inherit}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);cursor:pointer;width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
|
|
37
38
|
</style><style>
|
|
38
|
-
:host{position:relative}
|
|
39
|
+
:host{position:relative}girafe-map-grid,girafe-map-2d,girafe-map-3d{width:100%;height:100%;display:block;position:relative;overflow:hidden}girafe-basemap{display:block;position:absolute;bottom:.5rem;left:.5rem}girafe-search{width:50%;height:2.25rem;display:block;position:absolute;top:.5rem;left:.5rem;box-shadow:0 1px 4px #0000004d}girafe-selection-window{z-index:100;width:400px;height:240px;position:absolute;bottom:1rem;right:1rem}
|
|
39
40
|
</style>
|
|
40
41
|
<style>${this.customStyle}</style>
|
|
41
|
-
<
|
|
42
|
+
<girafe-map-grid><girafe-map-2d></girafe-map-2d><girafe-map-3d></girafe-map-3d></girafe-map-grid>
|
|
42
43
|
${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
43
44
|
};
|
|
44
45
|
isInitialized = false;
|
|
@@ -107,6 +108,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
107
108
|
if (!customElements.get('girafe-map-2d')) {
|
|
108
109
|
customElements.define('girafe-map-2d', Map2dComponent);
|
|
109
110
|
customElements.define('girafe-map-3d', Map3dComponent);
|
|
111
|
+
customElements.define('girafe-map-grid', MapGridComponent);
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
manageAttributes() {
|
package/api/style.css
CHANGED
|
@@ -2,27 +2,21 @@
|
|
|
2
2
|
position: relative;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
girafe-map-grid {
|
|
6
|
+
display: block;
|
|
6
7
|
position: relative;
|
|
7
8
|
width: 100%;
|
|
8
9
|
height: 100%;
|
|
9
10
|
overflow: hidden;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
girafe-map-2d
|
|
13
|
+
girafe-map-2d,
|
|
14
|
+
girafe-map-3d {
|
|
13
15
|
display: block;
|
|
14
16
|
position: relative;
|
|
15
17
|
width: 100%;
|
|
16
18
|
height: 100%;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
girafe-map-3d {
|
|
20
|
-
display: none;
|
|
21
|
-
position: absolute;
|
|
22
|
-
top: 0;
|
|
23
|
-
height: 100%;
|
|
24
19
|
overflow: hidden;
|
|
25
|
-
border-left: solid 3px #444;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
girafe-basemap {
|
package/assets/i18n/de.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"de": {
|
|
3
|
+
"(empty)": "(leer)",
|
|
3
4
|
"+{number} more": "+{number} mehr",
|
|
4
5
|
"2D": "2D",
|
|
5
6
|
"2D / 3D": "2D / 3D",
|
|
7
|
+
"2D Map": "2D-Karte",
|
|
6
8
|
"3D": "3D",
|
|
9
|
+
"3D Map": "3D-Karte",
|
|
7
10
|
"About": "About",
|
|
8
11
|
"about-panel": "About",
|
|
9
12
|
"Activate / Deactivate": "Aktivieren / Deaktivieren",
|
|
@@ -126,6 +129,7 @@
|
|
|
126
129
|
"Discard": "Verwerfen",
|
|
127
130
|
"Disk": "Kreis",
|
|
128
131
|
"Display menu": "Menü anzeigen",
|
|
132
|
+
"Displayed components": "Angezeigte Komponenten",
|
|
129
133
|
"Distance": "Entfernung",
|
|
130
134
|
"Do you want to delete this bookmark?": "Möchten Sie dieses Lesezeichen löschen?",
|
|
131
135
|
"Do you want to delete this feature?": "Möchten Sie dieses Objekt löschen?",
|
package/assets/i18n/en.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"en": {
|
|
3
|
+
"(empty)": "(empty)",
|
|
3
4
|
"+{number} more": "+{number} more",
|
|
4
5
|
"2D": "2D",
|
|
5
6
|
"2D / 3D": "2D / 3D",
|
|
7
|
+
"2D Map": "2D Map",
|
|
6
8
|
"3D": "3D",
|
|
9
|
+
"3D Map": "3D Map",
|
|
7
10
|
"About": "About",
|
|
8
11
|
"about-panel": "About",
|
|
9
12
|
"Activate / Deactivate": "Activate / Deactivate",
|
|
@@ -127,6 +130,7 @@
|
|
|
127
130
|
"Discard": "Discard",
|
|
128
131
|
"Disk": "Circle",
|
|
129
132
|
"Display menu": "Display menu",
|
|
133
|
+
"Displayed components": "Displayed components",
|
|
130
134
|
"Distance": "Distance",
|
|
131
135
|
"Do you want to delete this bookmark?": "Do you want to delete this bookmark?",
|
|
132
136
|
"Do you want to delete this feature?": "Do you want to delete this feature?",
|
package/assets/i18n/fr.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"fr": {
|
|
3
|
+
"(empty)": "(vide)",
|
|
3
4
|
"+{number} more": "+{number} de plus",
|
|
4
5
|
"2D": "2D",
|
|
5
6
|
"2D / 3D": "2D / 3D",
|
|
7
|
+
"2D Map": "Carte 2D",
|
|
6
8
|
"3D": "3D",
|
|
9
|
+
"3D Map": "Carte 3D",
|
|
7
10
|
"About": "À propos",
|
|
8
11
|
"about-panel": "À propos",
|
|
9
12
|
"Activate / Deactivate": "Activer / Désactiver",
|
|
@@ -126,6 +129,7 @@
|
|
|
126
129
|
"Discard": "Annuler cette entité",
|
|
127
130
|
"Disk": "Cercle",
|
|
128
131
|
"Display menu": "Afficher le menu",
|
|
132
|
+
"Displayed components": "Composants affichés",
|
|
129
133
|
"Distance": "Distance",
|
|
130
134
|
"Do you want to delete this bookmark?": "Voulez-vous supprimer ce favori ?",
|
|
131
135
|
"Do you want to delete this feature?": "Souhaitez-vous supprimer cette entité?",
|
package/assets/i18n/it.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"it": {
|
|
3
|
+
"(empty)": "(vuoto)",
|
|
3
4
|
"+{number} more": "+{number} in più",
|
|
4
5
|
"2D": "2D",
|
|
5
6
|
"2D / 3D": "2D / 3D",
|
|
7
|
+
"2D Map": "Mappa 2D",
|
|
6
8
|
"3D": "3D",
|
|
9
|
+
"3D Map": "Mappa 3D",
|
|
7
10
|
"About": "Informazioni",
|
|
8
11
|
"about-panel": "Informazioni",
|
|
9
12
|
"Activate / Deactivate": "Attiva / Disattiva",
|
|
@@ -126,6 +129,7 @@
|
|
|
126
129
|
"Discard": "Scartare",
|
|
127
130
|
"Disk": "Cerchio",
|
|
128
131
|
"Display menu": "Mostra menu",
|
|
132
|
+
"Displayed components": "Componenti visualizzati",
|
|
129
133
|
"Distance": "Distanza",
|
|
130
134
|
"Do you want to delete this bookmark?": "Vuoi eliminare questo segnalibro?",
|
|
131
135
|
"Do you want to delete this feature?": "Si desidera eliminare questo elemento?",
|
|
@@ -13,7 +13,7 @@ class BasemapComponent extends GirafeHTMLElement {
|
|
|
13
13
|
.basemap-button{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;box-shadow:var(--bx-shdw);border-width:2px;border-radius:4px;outline:0;margin:0;padding:5px;display:inline-flex}#container{flex-direction:column;width:max-content;display:inline-flex}.basemap-icon{background:var(--svg-legend-bkg);filter:var(--svg-map-filter)}.active-basemap{background-color:var(--bkg-color-grad2)!important}.opacity-slider{flex-direction:row;height:20px;padding:0 5px;display:flex}.opacity-slider img{height:16px;position:relative;top:2px}.opacity-slider input[type=range]{flex-grow:1}.basemap-container{flex-direction:column;display:flex}.basemap-container button{color:var(--text-color);background-color:#0000;border:none;flex-direction:row;flex-grow:1;display:flex}.basemap-container button img{height:2rem;margin:.3rem}.basemap-container button span{height:2rem;margin:.3rem;line-height:2rem}.basemap-container:hover{background-color:var(--bkg-color-grad1)}.basemaps-with-opacity-separator{border-top:1px solid var(--bkg-color-grad2);height:1px;margin:6px 8px}
|
|
14
14
|
</style>
|
|
15
15
|
<style>${this.customStyle}</style>
|
|
16
|
-
<girafe-menu-button direction="up-right" id="basemap-menu-button"><button slot="menu-button" class="basemap-button" tip="Select basemap"><img class="basemap-icon" alt="menu-icon" src="images/button_basemaps.webp"></button><div slot="menu-content" id="container">${Object.values(this.state.basemaps).filter(basemap => basemap.opacity == -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button></div>`)}<div class="basemaps-with-opacity-separator"></div>${Object.values(this.state.basemaps).filter(basemap => basemap.opacity != -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button><div class="opacity-slider"><img alt="Control opacity" src="icons/opacity.svg"> <input type="range" min="0" max="1" step="0.01" class="
|
|
16
|
+
<girafe-menu-button direction="up-right" id="basemap-menu-button"><button slot="menu-button" class="basemap-button" tip="Select basemap"><img class="basemap-icon" alt="menu-icon" src="images/button_basemaps.webp"></button><div slot="menu-content" id="container">${Object.values(this.state.basemaps).filter(basemap => basemap.opacity == -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button></div>`)}<div class="basemaps-with-opacity-separator"></div>${Object.values(this.state.basemaps).filter(basemap => basemap.opacity != -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button><div class="opacity-slider"><img alt="Control opacity" src="icons/opacity.svg"> <input type="range" min="0" max="1" step="0.01" class="gg-range" value="${basemap.opacity}" onkeydown="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onclick="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onchange="${(e) => this.changeBasemapOpacity(basemap, e)}"></div></div>`)}</div></girafe-menu-button>
|
|
17
17
|
${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
18
18
|
};
|
|
19
19
|
constructor() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
|
|
2
2
|
import IGirafePanel from '../../tools/state/igirafepanel.js';
|
|
3
|
+
import { CellContent, LayoutType } from '../../tools/state/layout.js';
|
|
3
4
|
declare class LayoutComponent extends GirafeHTMLElement implements IGirafePanel {
|
|
4
5
|
protected templateUrl: string | null;
|
|
5
6
|
protected styleUrls: string[] | null;
|
|
@@ -7,13 +8,43 @@ declare class LayoutComponent extends GirafeHTMLElement implements IGirafePanel
|
|
|
7
8
|
isPanelVisible: boolean;
|
|
8
9
|
panelTitle: string;
|
|
9
10
|
panelTogglePath: string;
|
|
11
|
+
/** The Components the user can choose between for each Cell of the Grid. */
|
|
12
|
+
availableComponents: readonly [{
|
|
13
|
+
readonly id: "map-2d";
|
|
14
|
+
readonly tagName: "girafe-map-2d";
|
|
15
|
+
readonly label: "2D Map";
|
|
16
|
+
}, {
|
|
17
|
+
readonly id: "map-3d";
|
|
18
|
+
readonly tagName: "girafe-map-3d";
|
|
19
|
+
readonly label: "3D Map";
|
|
20
|
+
}];
|
|
10
21
|
constructor();
|
|
22
|
+
private get layout();
|
|
23
|
+
/** The Layouts the user can choose between, as configured in the application. */
|
|
24
|
+
get allowedLayouts(): LayoutType[];
|
|
25
|
+
/** The Cells of the current Layout, one line of the schema per row of the Grid. */
|
|
26
|
+
get cellRows(): {
|
|
27
|
+
index: number;
|
|
28
|
+
content: CellContent;
|
|
29
|
+
}[][];
|
|
11
30
|
private registerEvents;
|
|
12
31
|
togglePanel(visible: boolean): void;
|
|
13
|
-
private onLayoutSelect;
|
|
14
32
|
private onLayoutChanged;
|
|
15
|
-
|
|
16
|
-
|
|
33
|
+
/**
|
|
34
|
+
* uHtml only updates the <selected> attribute of the options, which the browser ignores
|
|
35
|
+
* as soon as the user has interacted with a select. The values are therefore applied explicitly,
|
|
36
|
+
* so that the panel also follows the changes made outside of it (shared state, other components).
|
|
37
|
+
*/
|
|
38
|
+
private syncSelects;
|
|
39
|
+
private onLayoutSelect;
|
|
40
|
+
/**
|
|
41
|
+
* Places a Component in a Cell of the Grid.
|
|
42
|
+
* A Component can only be displayed once: if it is already displayed in another Cell,
|
|
43
|
+
* both Cells are swapped, so that the Component that was in the target Cell is not lost.
|
|
44
|
+
*/
|
|
45
|
+
onCellSelect(event: Event, cellIndex: number): void;
|
|
46
|
+
/** Whether one of the Cells displays a 3D Map, which the shadows options depend on. */
|
|
47
|
+
get is3dDisplayed(): boolean;
|
|
17
48
|
private onShadowsToggle;
|
|
18
49
|
private setDateTimePicker;
|
|
19
50
|
private update3dMapTimestamp;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html as uHtml } from 'uhtml';
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
|
|
4
|
-
|
|
4
|
+
import { AVAILABLE_CELL_COMPONENTS, distributeCells, getDefaultSizes, getGridSize, isCellComponent, isLayoutType } from '../../tools/state/layout.js';
|
|
5
5
|
class LayoutComponent extends GirafeHTMLElement {
|
|
6
6
|
templateUrl = null;
|
|
7
7
|
styleUrls = null;
|
|
@@ -9,59 +9,96 @@ class LayoutComponent extends GirafeHTMLElement {
|
|
|
9
9
|
return uHtml `<style>
|
|
10
10
|
.hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}button,input,select,textarea{font:inherit}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);cursor:pointer;width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
|
|
11
11
|
</style><style>
|
|
12
|
-
#panel{color:var(--text-color)}#panel>div{padding:1rem}.hidden{display:none}fieldset{margin-top:1rem}.option{margin-top:.5rem;display:flex}.option select,.option input{flex-grow:1}.option input.gg-checkbox{flex-grow:0}.option label{margin-right:.5rem}.option label:after{content:" :"}
|
|
12
|
+
#panel{color:var(--text-color)}#panel>div{padding:1rem}.hidden{display:none}fieldset{margin-top:1rem}.cells-row{gap:.25rem;margin-top:.5rem;display:flex}.cell-select{flex:1 1 0;min-width:0}.option{margin-top:.5rem;display:flex}.option select,.option input{flex-grow:1}.option input.gg-checkbox{flex-grow:0}.option label{margin-right:.5rem}.option label:after{content:" :"}
|
|
13
13
|
</style>
|
|
14
14
|
<style>${this.customStyle}</style>
|
|
15
|
-
<div id="panel"><div><div class="option"><label for="layout" i18n="View" class="gg-label">View</label> <select id="layout" class="gg-select" onchange="${this.onLayoutSelect}"
|
|
15
|
+
<div id="panel"><div><div class="option"><label for="layout" i18n="View" class="gg-label">View</label> <select id="layout" class="gg-select" onchange="${this.onLayoutSelect}">${this.allowedLayouts.map((layout) => uHtml `<option value="${layout}" ?selected="${layout === this.state.layout.type}">${layout}</option>`)}</select></div><fieldset class="cells-group"><legend i18n="Displayed components">Displayed components</legend>${this.cellRows.map((cellRow) => uHtml `<div class="cells-row">${cellRow.map((cell) => uHtml ` <select class="gg-select cell-select" onchange="${(e) => this.onCellSelect(e, cell.index)}"><option i18n="(empty)" value="" ?selected="${cell.content === null}">(empty)</option>${this.availableComponents.map((component) => uHtml `<option i18n="${component.label}" value="${component.id}" ?selected="${cell.content === component.id}">${component.label}</option>`)}</select> `)}</div>`)}</fieldset><fieldset class="${this.is3dDisplayed ? 'shadows-group' : 'shadows-group hidden'}"><legend i18n="Shadows">Shadows</legend><div class="option shadows-option"><label for="shadowsCheckbox" i18n="Enable shadows" class="gg-label">Enable shadows</label> <input id="shadowsCheckbox" type="checkbox" class="gg-checkbox" ?checked="${this.state.globe.shadows}" onchange="${this.onShadowsToggle}"></div><div class="${this.state.globe.shadows ? 'option shadows-date' : 'option shadows-date hidden'}"><label for="shadowsDate" i18n="Date" class="gg-label">Date</label> <input id="shadowsDate" type="datetime-local" class="gg-input"></div></fieldset></div></div>
|
|
16
16
|
${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
17
17
|
};
|
|
18
18
|
isPanelVisible = false;
|
|
19
19
|
panelTitle = 'layout-panel';
|
|
20
20
|
panelTogglePath = 'interface.layoutPanelVisible';
|
|
21
|
+
/** The Components the user can choose between for each Cell of the Grid. */
|
|
22
|
+
availableComponents = AVAILABLE_CELL_COMPONENTS;
|
|
21
23
|
constructor() {
|
|
22
24
|
super('layout');
|
|
23
25
|
this.onLayoutSelect = this.onLayoutSelect.bind(this);
|
|
24
26
|
this.onShadowsToggle = this.onShadowsToggle.bind(this);
|
|
25
27
|
}
|
|
28
|
+
get layout() {
|
|
29
|
+
return this.state.layout;
|
|
30
|
+
}
|
|
31
|
+
/** The Layouts the user can choose between, as configured in the application. */
|
|
32
|
+
get allowedLayouts() {
|
|
33
|
+
return this.context.configManager.Config.interface.layouts;
|
|
34
|
+
}
|
|
35
|
+
/** The Cells of the current Layout, one line of the schema per row of the Grid. */
|
|
36
|
+
get cellRows() {
|
|
37
|
+
const { columns, rows } = getGridSize(this.layout.type);
|
|
38
|
+
const cells = this.layout.cells;
|
|
39
|
+
return Array.from({ length: rows }, (_, row) => Array.from({ length: columns }, (_, column) => {
|
|
40
|
+
const index = row * columns + column;
|
|
41
|
+
return { index: index, content: cells[index] ?? null };
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
26
44
|
registerEvents() {
|
|
27
|
-
this.subscribe('
|
|
45
|
+
this.subscribe('layout.type', () => this.onLayoutChanged());
|
|
46
|
+
this.subscribe('layout.cells', () => this.onLayoutChanged());
|
|
28
47
|
}
|
|
29
48
|
togglePanel(visible) {
|
|
30
49
|
this.isPanelVisible = visible;
|
|
31
50
|
this.render();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.
|
|
51
|
+
}
|
|
52
|
+
onLayoutChanged() {
|
|
53
|
+
if (this.isPanelVisible) {
|
|
54
|
+
this.refreshRender();
|
|
55
|
+
this.syncSelects();
|
|
36
56
|
}
|
|
37
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* uHtml only updates the <selected> attribute of the options, which the browser ignores
|
|
60
|
+
* as soon as the user has interacted with a select. The values are therefore applied explicitly,
|
|
61
|
+
* so that the panel also follows the changes made outside of it (shared state, other components).
|
|
62
|
+
*/
|
|
63
|
+
syncSelects() {
|
|
64
|
+
const layoutSelect = this.getById('layout');
|
|
65
|
+
if (layoutSelect) {
|
|
66
|
+
layoutSelect.value = this.layout.type;
|
|
67
|
+
}
|
|
68
|
+
const cells = this.layout.cells;
|
|
69
|
+
this.shadow.querySelectorAll('.cell-select').forEach((select, index) => {
|
|
70
|
+
select.value = cells[index] ?? '';
|
|
71
|
+
});
|
|
72
|
+
}
|
|
38
73
|
onLayoutSelect(event) {
|
|
39
74
|
const selectedLayout = event.target?.value;
|
|
40
|
-
if (
|
|
41
|
-
|
|
75
|
+
if (!isLayoutType(selectedLayout) || !this.allowedLayouts.includes(selectedLayout)) {
|
|
76
|
+
console.error(`${selectedLayout} is not a valid layout!`);
|
|
42
77
|
return;
|
|
43
78
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
this.syncLayoutSelect(globe);
|
|
48
|
-
if (this.isPanelVisible) {
|
|
49
|
-
this.updateShadowsVisibility(globe);
|
|
50
|
-
}
|
|
79
|
+
this.layout.cells = distributeCells(selectedLayout, this.layout.cells);
|
|
80
|
+
this.layout.sizes = getDefaultSizes(selectedLayout);
|
|
81
|
+
this.layout.type = selectedLayout;
|
|
51
82
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Places a Component in a Cell of the Grid.
|
|
85
|
+
* A Component can only be displayed once: if it is already displayed in another Cell,
|
|
86
|
+
* both Cells are swapped, so that the Component that was in the target Cell is not lost.
|
|
87
|
+
*/
|
|
88
|
+
onCellSelect(event, cellIndex) {
|
|
89
|
+
const value = event.target?.value;
|
|
90
|
+
const component = isCellComponent(value) ? value : null;
|
|
91
|
+
const cells = [...this.layout.cells];
|
|
92
|
+
const previousIndex = component === null ? -1 : cells.indexOf(component);
|
|
93
|
+
if (previousIndex >= 0) {
|
|
94
|
+
cells[previousIndex] = cells[cellIndex];
|
|
56
95
|
}
|
|
96
|
+
cells[cellIndex] = component;
|
|
97
|
+
this.layout.cells = cells;
|
|
57
98
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const shadowsCheckbox = this.shadowRoot?.querySelector('#shadowsCheckbox');
|
|
62
|
-
const has3Dlayout = globe === '2D/3D' || globe === '3D';
|
|
63
|
-
shadowsGroup?.classList.toggle('hidden', !has3Dlayout);
|
|
64
|
-
shadowsDate?.classList.toggle('hidden', !has3Dlayout || !shadowsCheckbox?.checked);
|
|
99
|
+
/** Whether one of the Cells displays a 3D Map, which the shadows options depend on. */
|
|
100
|
+
get is3dDisplayed() {
|
|
101
|
+
return this.layout.cells.includes('map-3d');
|
|
65
102
|
}
|
|
66
103
|
onShadowsToggle(event) {
|
|
67
104
|
const shadowsDate = this.shadowRoot?.querySelector('.shadows-date');
|
|
@@ -93,6 +130,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
93
130
|
render() {
|
|
94
131
|
if (this.isPanelVisible) {
|
|
95
132
|
super.render();
|
|
133
|
+
this.syncSelects();
|
|
96
134
|
}
|
|
97
135
|
else {
|
|
98
136
|
this.hide();
|
|
@@ -15,6 +15,19 @@ fieldset {
|
|
|
15
15
|
margin-top: 1rem;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/* Schema of the Grid: one row per row of the Grid, one select per Cell. */
|
|
19
|
+
.cells-row {
|
|
20
|
+
display: flex;
|
|
21
|
+
gap: 0.25rem;
|
|
22
|
+
margin-top: 0.5rem;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.cell-select {
|
|
26
|
+
flex: 1 1 0;
|
|
27
|
+
/* Prevents the selects from growing over the width of the panel. */
|
|
28
|
+
min-width: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
.option {
|
|
19
32
|
margin-top: 0.5rem;
|
|
20
33
|
display: flex;
|
package/components/main.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export { default as LRPanelComponent } from './lr-panel/component.js';
|
|
|
32
32
|
export { default as Map2dComponent } from './map-2d/component.js';
|
|
33
33
|
export { default as DeprecatedMapComponent } from './map-2d/deprecatedmapcomponent.js';
|
|
34
34
|
export { default as Map3dComponent } from './map-3d/component.js';
|
|
35
|
+
export { default as MapGridComponent } from './map-grid/component.js';
|
|
35
36
|
export { default as MenuMobile } from './menu-mobile/component.js';
|
|
36
37
|
export { default as MenuButtonComponent } from './menubutton/component.js';
|
|
37
38
|
export { default as ModalsComponent } from './modals/component.js';
|
package/components/main.js
CHANGED
|
@@ -31,6 +31,7 @@ export { default as LRPanelComponent } from './lr-panel/component.js';
|
|
|
31
31
|
export { default as Map2dComponent } from './map-2d/component.js';
|
|
32
32
|
export { default as DeprecatedMapComponent } from './map-2d/deprecatedmapcomponent.js';
|
|
33
33
|
export { default as Map3dComponent } from './map-3d/component.js';
|
|
34
|
+
export { default as MapGridComponent } from './map-grid/component.js';
|
|
34
35
|
export { default as MenuMobile } from './menu-mobile/component.js';
|
|
35
36
|
export { default as MenuButtonComponent } from './menubutton/component.js';
|
|
36
37
|
export { default as ModalsComponent } from './modals/component.js';
|
|
@@ -109,12 +109,6 @@ export default class Map2dComponent extends GirafeHTMLElement {
|
|
|
109
109
|
private setSelectLayerStyle;
|
|
110
110
|
private setHighlightLayerStyle;
|
|
111
111
|
private setCrosshairStyle;
|
|
112
|
-
/**
|
|
113
|
-
* Resizes the 2D Map depending on the current globe display mode.
|
|
114
|
-
* In side-by-side mode the 2D Map only takes the left part of the available space,
|
|
115
|
-
* in full 3D mode it is hidden. The 3D Map takes care of its own sizing.
|
|
116
|
-
*/
|
|
117
|
-
onGlobeDisplayChanged(display: string): void;
|
|
118
112
|
onFeaturesSelected(features: Feature[]): void;
|
|
119
113
|
onFeatureHighlighted(features: Feature[]): void;
|
|
120
114
|
zoomToExtent(extent: Extent): void;
|
|
@@ -158,7 +158,6 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
158
158
|
this.addMarker(marker);
|
|
159
159
|
}
|
|
160
160
|
});
|
|
161
|
-
this.subscribe('globe.display', (_oldDisplay, newDisplay) => this.onGlobeDisplayChanged(newDisplay));
|
|
162
161
|
this.subscribe(/layers\.layersList\..*\.activeState/, async (_oldActive, _newActive, layer) => {
|
|
163
162
|
await this.onLayerToggled(layer);
|
|
164
163
|
if (layer.active) {
|
|
@@ -352,6 +351,9 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
352
351
|
this.olMap.updateSize();
|
|
353
352
|
}, 1000);
|
|
354
353
|
this.mapTargetResizeObserver = new ResizeObserver(() => {
|
|
354
|
+
// The size of the Map is defined by the Cell of the Grid it is displayed in,
|
|
355
|
+
// and the user can change it at any time by dragging a splitter.
|
|
356
|
+
this.olMap.updateSize();
|
|
355
357
|
this.updateCloseSwiperPosition();
|
|
356
358
|
});
|
|
357
359
|
this.mapTargetResizeObserver.observe(this.mapTarget);
|
|
@@ -481,7 +483,6 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
481
483
|
this.render();
|
|
482
484
|
this.listenOpenLayersEvents();
|
|
483
485
|
this.registerEvents();
|
|
484
|
-
this.onGlobeDisplayChanged(this.state.globe.display);
|
|
485
486
|
}
|
|
486
487
|
onCustomGirafeEvent(details) {
|
|
487
488
|
if (details.action === GeoEvents.zoomToExtent) {
|
|
@@ -549,26 +550,6 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
549
550
|
})
|
|
550
551
|
}));
|
|
551
552
|
}
|
|
552
|
-
/**
|
|
553
|
-
* Resizes the 2D Map depending on the current globe display mode.
|
|
554
|
-
* In side-by-side mode the 2D Map only takes the left part of the available space,
|
|
555
|
-
* in full 3D mode it is hidden. The 3D Map takes care of its own sizing.
|
|
556
|
-
*/
|
|
557
|
-
onGlobeDisplayChanged(display) {
|
|
558
|
-
if (display === '3D') {
|
|
559
|
-
this.style.display = 'none';
|
|
560
|
-
}
|
|
561
|
-
else if (display === '2D/3D') {
|
|
562
|
-
this.style.display = 'block';
|
|
563
|
-
this.style.width = '45%';
|
|
564
|
-
this.olMap.updateSize();
|
|
565
|
-
}
|
|
566
|
-
else {
|
|
567
|
-
this.style.display = 'block';
|
|
568
|
-
this.style.width = '100%';
|
|
569
|
-
this.olMap.updateSize();
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
553
|
onFeaturesSelected(features) {
|
|
573
554
|
this.selectedFeaturesCollection.clear();
|
|
574
555
|
if (features) {
|
|
@@ -43,8 +43,10 @@ export default class Map3dComponent extends GirafeHTMLElement {
|
|
|
43
43
|
*/
|
|
44
44
|
private createGlobe;
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
46
|
+
* Creates and enables the globe when the 3D Map is displayed in a Cell of the Grid,
|
|
47
|
+
* and disables it when it is not displayed anymore.
|
|
48
|
+
* The size and the position of the Map are managed by the Grid, OLCesium takes care
|
|
49
|
+
* of following the size of its container.
|
|
48
50
|
*/
|
|
49
51
|
onGlobeToggled(): Promise<void>;
|
|
50
52
|
}
|
|
@@ -61,7 +61,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
61
61
|
this.map3dTarget = this.shadow.getElementById('cs-map');
|
|
62
62
|
}
|
|
63
63
|
registerEvents() {
|
|
64
|
-
this.subscribe('
|
|
64
|
+
this.subscribe('layout.cells', async () => {
|
|
65
65
|
await this.onGlobeToggled();
|
|
66
66
|
this.globe?.setCamera(this.state.globe.camera);
|
|
67
67
|
});
|
|
@@ -109,30 +109,19 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
109
109
|
return this.globeCreation;
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
112
|
+
* Creates and enables the globe when the 3D Map is displayed in a Cell of the Grid,
|
|
113
|
+
* and disables it when it is not displayed anymore.
|
|
114
|
+
* The size and the position of the Map are managed by the Grid, OLCesium takes care
|
|
115
|
+
* of following the size of its container.
|
|
114
116
|
*/
|
|
115
117
|
async onGlobeToggled() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.style.display = 'block';
|
|
119
|
-
this.style.left = '0';
|
|
120
|
-
this.style.width = '100%';
|
|
121
|
-
await this.createGlobe();
|
|
122
|
-
this.globe?.setEnabled(true);
|
|
123
|
-
}
|
|
124
|
-
else if (this.state.globe.display === '2D/3D') {
|
|
125
|
-
// Side by side has been enabled
|
|
126
|
-
this.style.display = 'block';
|
|
127
|
-
this.style.left = '45%';
|
|
128
|
-
this.style.width = '55%';
|
|
118
|
+
const isDisplayed = this.state.layout.cells.includes('map-3d');
|
|
119
|
+
if (isDisplayed) {
|
|
129
120
|
await this.createGlobe();
|
|
130
121
|
this.globe?.setEnabled(true);
|
|
131
122
|
}
|
|
132
123
|
else {
|
|
133
|
-
// 3d map is not visible
|
|
134
124
|
this.globe?.setEnabled(false);
|
|
135
|
-
this.style.display = 'none';
|
|
136
125
|
this.unregisterInteractionListeners('globe.select');
|
|
137
126
|
}
|
|
138
127
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
|
|
2
|
+
/** A splitter, placed on the boundary between two columns or two rows of the Grid. */
|
|
3
|
+
type Splitter = {
|
|
4
|
+
/** Whether the splitter is dragged left/right (vertical) or up/down (horizontal). */
|
|
5
|
+
orientation: 'vertical' | 'horizontal';
|
|
6
|
+
/** Index of the column (vertical) or of the row (horizontal) placed before the splitter. */
|
|
7
|
+
index: number;
|
|
8
|
+
/** Position of the splitter, in percent of the Grid. */
|
|
9
|
+
position: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* The Grid in which the Map Components are displayed.
|
|
13
|
+
*
|
|
14
|
+
* The Components are written as children of this Element in the HTML of the application
|
|
15
|
+
* and are moved into the Cells of the Grid, depending on <code>state.layout</code>.
|
|
16
|
+
* A Component that is not placed in any Cell is not slotted, and therefore not displayed.
|
|
17
|
+
*/
|
|
18
|
+
declare class MapGridComponent extends GirafeHTMLElement {
|
|
19
|
+
protected templateUrl: string | null;
|
|
20
|
+
protected styleUrls: string[] | null;
|
|
21
|
+
template: () => import("uhtml").Hole;
|
|
22
|
+
/** Index of each Cell of the current Layout, used to render the Cells and their slots. */
|
|
23
|
+
cellIndexes: number[];
|
|
24
|
+
/** The splitters between the Cells of the current Layout. */
|
|
25
|
+
splitters: Splitter[];
|
|
26
|
+
/** The splitter that is currently dragged, if any. */
|
|
27
|
+
private draggedSplitter;
|
|
28
|
+
constructor();
|
|
29
|
+
private get layout();
|
|
30
|
+
private get grid();
|
|
31
|
+
protected connectedCallback(): void;
|
|
32
|
+
private registerEvents;
|
|
33
|
+
/**
|
|
34
|
+
* Rebuilds the Cells and the splitters of the Grid for the current Layout,
|
|
35
|
+
* then places the Components and applies the sizes.
|
|
36
|
+
*/
|
|
37
|
+
private applyLayout;
|
|
38
|
+
/**
|
|
39
|
+
* Creates one splitter for each boundary between two columns and between two rows.
|
|
40
|
+
* The splitters go through the whole Grid, so that the columns and the rows keep
|
|
41
|
+
* the same sizes in every Cell of the Grid.
|
|
42
|
+
*/
|
|
43
|
+
private createSplitters;
|
|
44
|
+
/**
|
|
45
|
+
* Moves each Component into the Cell it is configured for, by setting the name of the slot
|
|
46
|
+
* it must be displayed in. Components that are not placed in any Cell get no slot,
|
|
47
|
+
* which means that they are not displayed at all.
|
|
48
|
+
*/
|
|
49
|
+
private applyCells;
|
|
50
|
+
/** Applies the sizes of the columns and of the rows to the Grid and to the splitters. */
|
|
51
|
+
private applySizes;
|
|
52
|
+
private applySplitterPosition;
|
|
53
|
+
getSplitterId(splitter: Splitter): string;
|
|
54
|
+
onSplitterPointerDown(event: PointerEvent, splitter: Splitter): void;
|
|
55
|
+
/**
|
|
56
|
+
* Resizes the two columns (or the two rows) around the dragged splitter.
|
|
57
|
+
* While dragging, the new sizes are only applied to the DOM: the state is updated
|
|
58
|
+
* at the end of the drag, to prevent flooding it with intermediate values.
|
|
59
|
+
*/
|
|
60
|
+
onSplitterPointerMove(event: PointerEvent, splitter: Splitter): void;
|
|
61
|
+
onSplitterPointerUp(event: PointerEvent, splitter: Splitter): void;
|
|
62
|
+
/**
|
|
63
|
+
* Computes the new sizes of the columns (or of the rows) when the splitter is moved
|
|
64
|
+
* to the given position, in percent of the Grid. The two resized columns (or rows) are
|
|
65
|
+
* kept between MIN_CELL_SIZE and MAX_CELL_SIZE, the other ones keep their size.
|
|
66
|
+
*/
|
|
67
|
+
private getResizedSizes;
|
|
68
|
+
render(): void;
|
|
69
|
+
}
|
|
70
|
+
export default MapGridComponent;
|