@geogirafe/lib-geoportal 1.2.0-dev.2813242211 → 1.2.0-dev.2829121016
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/apicontext.d.ts +4 -0
- package/api/apicontext.js +8 -0
- package/api/apigeogirafeapp.js +7 -5
- package/api/style.css +18 -1
- package/assets/i18n/de.json +1 -0
- package/assets/i18n/en.json +1 -0
- package/assets/i18n/fr.json +1 -0
- package/assets/i18n/it.json +1 -0
- package/assets/icons/theme-checked.svg +1 -0
- package/components/drawing/component.d.ts +9 -2
- package/components/drawing/component.js +27 -10
- package/components/drawing-toolbar/component.js +2 -2
- package/components/extlayers/component.d.ts +0 -1
- package/components/extlayers/component.js +1 -6
- package/components/main.d.ts +3 -1
- package/components/main.js +3 -1
- package/components/{map → map-2d}/component.d.ts +9 -24
- package/components/{map → map-2d}/component.js +28 -260
- package/components/map-2d/deprecatedmapcomponent.d.ts +15 -0
- package/components/map-2d/deprecatedmapcomponent.js +24 -0
- package/components/{map → map-2d}/style.css +0 -30
- package/components/{map → map-2d}/tools/swipemanager.d.ts +1 -1
- package/components/map-3d/component.d.ts +50 -0
- package/components/map-3d/component.js +139 -0
- package/components/map-3d/style.css +34 -0
- package/components/map-3d/tools/globe.d.ts +42 -0
- package/components/map-3d/tools/globe.js +198 -0
- package/components/search/component.d.ts +5 -0
- package/components/search/component.js +71 -19
- package/components/search/style.css +36 -9
- package/components/selectiontool/component.d.ts +2 -2
- package/components/selectiontool/component.js +2 -2
- package/components/treeview/style.css +4 -0
- package/components/treeview/treeviewgroup/component.js +1 -1
- package/components/treeview/treeviewitem/component.js +1 -1
- package/components/treeview/treeviewtheme/component.d.ts +2 -0
- package/components/treeview/treeviewtheme/component.js +18 -3
- package/package.json +1 -1
- package/styles/iframe.css +18 -1
- package/styles/index.css +18 -1
- package/styles/mobile.css +18 -1
- package/templates/iframe.html +4 -1
- package/templates/index.html +4 -1
- package/templates/mobile.html +4 -1
- package/templates/public/about.json +1 -1
- package/templates/vite.config.js +43 -25
- package/tools/app/geogirafeapp-mobile.js +7 -2
- package/tools/app/geogirafeapp.js +7 -2
- package/tools/context/context.d.ts +4 -0
- package/tools/context/context.js +8 -0
- package/tools/context/icontext.d.ts +4 -0
- package/tools/drawing/cesiumDrawing.d.ts +9 -5
- package/tools/drawing/cesiumDrawing.js +8 -8
- package/tools/drawing/olDrawing.d.ts +2 -2
- package/tools/drawing/olDrawing.js +1 -1
- package/tools/main.d.ts +2 -0
- package/tools/main.js +2 -0
- package/tools/selection/selectionmanager.d.ts +19 -0
- package/tools/selection/selectionmanager.js +80 -0
- package/tools/state/componentManager.d.ts +1 -1
- package/tools/tests/mockcontext.d.ts +4 -0
- package/tools/tests/mockcontext.js +8 -0
- package/tools/themes/themeshelper.d.ts +44 -1
- package/tools/themes/themeshelper.js +149 -16
- package/{components/map/tools → tools/wmts}/wmtsmanager.d.ts +4 -7
- package/{components/map/tools → tools/wmts}/wmtsmanager.js +7 -10
- /package/components/{map → map-2d}/tools/cogmanager.d.ts +0 -0
- /package/components/{map → map-2d}/tools/cogmanager.js +0 -0
- /package/components/{map → map-2d}/tools/contextmenu.d.ts +0 -0
- /package/components/{map → map-2d}/tools/contextmenu.js +0 -0
- /package/components/{map → map-2d}/tools/drawingmanager.d.ts +0 -0
- /package/components/{map → map-2d}/tools/drawingmanager.js +0 -0
- /package/components/{map → map-2d}/tools/focusfeature.d.ts +0 -0
- /package/components/{map → map-2d}/tools/focusfeature.js +0 -0
- /package/components/{map → map-2d}/tools/osmmanager.d.ts +0 -0
- /package/components/{map → map-2d}/tools/osmmanager.js +0 -0
- /package/components/{map → map-2d}/tools/swipemanager.js +0 -0
- /package/components/{map → map-2d}/tools/vectortilesmanager.d.ts +0 -0
- /package/components/{map → map-2d}/tools/vectortilesmanager.js +0 -0
- /package/components/{map → map-2d}/tools/viewmanager.d.ts +0 -0
- /package/components/{map → map-2d}/tools/viewmanager.js +0 -0
- /package/components/{map → map-2d}/tools/xyzmanager.d.ts +0 -0
- /package/components/{map → map-2d}/tools/xyzmanager.js +0 -0
- /package/components/{map → map-3d}/tools/wmsmanager3d.d.ts +0 -0
- /package/components/{map → map-3d}/tools/wmsmanager3d.js +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { html as uHtml } from 'uhtml';
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
|
|
4
|
+
import LayerWms from '../../models/layers/layerwms.js';
|
|
5
|
+
/**
|
|
6
|
+
* The 3D Map.
|
|
7
|
+
*
|
|
8
|
+
* The Component itself stays lightweight: Cesium and OLCesium are only imported when the 3D Map
|
|
9
|
+
* is displayed for the first time. Everything that needs those libraries lives in ./tools/globe.
|
|
10
|
+
* The synchronization with the 2D Map is done by OLCesium, through the OpenLayers map of the
|
|
11
|
+
* MapManager. There is therefore no direct dependency to the map-2d Component.
|
|
12
|
+
*/
|
|
13
|
+
export default class Map3dComponent extends GirafeHTMLElement {
|
|
14
|
+
templateUrl = null;
|
|
15
|
+
styleUrls = null;
|
|
16
|
+
template = () => {
|
|
17
|
+
return uHtml `<style>
|
|
18
|
+
.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);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}}
|
|
19
|
+
</style><style>
|
|
20
|
+
#cs-map{background-color:var(--bkg-color);width:100%;height:100%;position:absolute;top:0;overflow:hidden}.hidden{display:none}.center{text-align:center;margin:10px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.loading span{color:var(--text-color);margin-top:1rem;font-weight:600;display:block}.loading span.quote{font-style:italic;font-weight:300}
|
|
21
|
+
</style>
|
|
22
|
+
<style>${this.customStyle}</style>
|
|
23
|
+
<div id="cs-map"><div class="${this.loading ? 'loading center' : 'loading hidden'}"><img alt="loading-icon" src="icons/loading.svg" class="gg-spin"> <span i18n="Loading cesium...">Loading cesium...</span> <span class="quote" i18n="cesium-loading-quote">Please be patient, like a giraffe reaching for the tastiest leaves.</span></div></div>
|
|
24
|
+
${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
25
|
+
};
|
|
26
|
+
globe = null;
|
|
27
|
+
map3dTarget;
|
|
28
|
+
loading = false;
|
|
29
|
+
pixelTolerance = 10;
|
|
30
|
+
/** Promise of the currently running globe creation, to prevent creating it twice. */
|
|
31
|
+
globeCreation = null;
|
|
32
|
+
/** The OLCesium instance, once the globe has been created. */
|
|
33
|
+
get map3d() {
|
|
34
|
+
return this.globe?.olCesium;
|
|
35
|
+
}
|
|
36
|
+
get config() {
|
|
37
|
+
return this.context.configManager.Config;
|
|
38
|
+
}
|
|
39
|
+
constructor() {
|
|
40
|
+
super('map-3d');
|
|
41
|
+
}
|
|
42
|
+
subscribe(path, callback) {
|
|
43
|
+
// @ts-expect-error The call would have succeeded against this implementation,
|
|
44
|
+
// but implementation signatures of overloads are not externally visible.
|
|
45
|
+
return super.subscribe(path, callback);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The Map needs to be displayed in Fullscreen Mode.
|
|
49
|
+
*/
|
|
50
|
+
get isFullscreenComponent() {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
connectedCallback() {
|
|
54
|
+
super.connectedCallback();
|
|
55
|
+
this.render();
|
|
56
|
+
this.registerEvents();
|
|
57
|
+
this.onGlobeToggled();
|
|
58
|
+
}
|
|
59
|
+
render() {
|
|
60
|
+
super.render();
|
|
61
|
+
this.map3dTarget = this.shadow.getElementById('cs-map');
|
|
62
|
+
}
|
|
63
|
+
registerEvents() {
|
|
64
|
+
this.subscribe('globe.display', async () => {
|
|
65
|
+
await this.onGlobeToggled();
|
|
66
|
+
this.globe?.setCamera(this.state.globe.camera);
|
|
67
|
+
});
|
|
68
|
+
this.subscribe('globe.shadows', (_oldShadows, newShadows) => this.globe?.setShadows(newShadows));
|
|
69
|
+
this.subscribe('globe.camera', async (_oldCamera, newCamera) => {
|
|
70
|
+
await this.onGlobeToggled();
|
|
71
|
+
this.globe?.setCamera(newCamera);
|
|
72
|
+
});
|
|
73
|
+
this.subscribe('activeBasemaps', (_, newBasemaps) => this.globe?.onChangeBasemaps(newBasemaps));
|
|
74
|
+
this.subscribe(/activeBasemaps\.\d\.opacity/, (_oldOpacity, _newOpacity, basemap) => this.globe?.changeBasemapOpacity(basemap));
|
|
75
|
+
this.subscribe(/layers\.layersList\..*\.activeState/, (_oldActive, _newActive, layer) => {
|
|
76
|
+
if (layer instanceof LayerWms) {
|
|
77
|
+
this.globe?.onLayerToggled(layer);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
this.subscribe(/layers\.layersList\..*\.opacity/, (_oldOpacity, _newOpacity, layer) => this.globe?.changeOpacity(layer));
|
|
81
|
+
this.subscribe(/layers\.layersList\..*\.filter/, (_oldFilter, _newFilter, layer) => this.globe?.changeFilter(layer));
|
|
82
|
+
this.subscribe('application.isReady', (_, isLoaded) => {
|
|
83
|
+
if (isLoaded) {
|
|
84
|
+
// The globe may not be ready when the rest of the application is initialized.
|
|
85
|
+
// The camera of a shared state can only be applied once everything is loaded.
|
|
86
|
+
this.globe?.setCamera(this.state.globe.camera);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Lazily loads Cesium/OLCesium and creates the globe. Does nothing if no 3D configuration
|
|
92
|
+
* is available or if the globe has already been created.
|
|
93
|
+
*/
|
|
94
|
+
async createGlobe() {
|
|
95
|
+
if (this.globe || !this.config.map3d) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.globeCreation ??= (async () => {
|
|
99
|
+
this.loading = true;
|
|
100
|
+
this.refreshRender();
|
|
101
|
+
const { default: Globe } = await import('./tools/globe');
|
|
102
|
+
const globe = new Globe(this.context, this.name, this.pixelTolerance);
|
|
103
|
+
await globe.initialize(this.map3dTarget);
|
|
104
|
+
this.globe = globe;
|
|
105
|
+
this.loading = false;
|
|
106
|
+
this.refreshRender();
|
|
107
|
+
this.state.globe.loaded = true;
|
|
108
|
+
})();
|
|
109
|
+
return this.globeCreation;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Shows or hides the 3D Map and sizes it depending on the current display mode.
|
|
113
|
+
* The 2D Map takes care of its own sizing.
|
|
114
|
+
*/
|
|
115
|
+
async onGlobeToggled() {
|
|
116
|
+
if (this.state.globe.display === '3D') {
|
|
117
|
+
// Full screen globe has been enabled
|
|
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%';
|
|
129
|
+
await this.createGlobe();
|
|
130
|
+
this.globe?.setEnabled(true);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// 3d map is not visible
|
|
134
|
+
this.globe?.setEnabled(false);
|
|
135
|
+
this.style.display = 'none';
|
|
136
|
+
this.unregisterInteractionListeners('globe.select');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: Apache-2.0 */
|
|
2
|
+
#cs-map {
|
|
3
|
+
background-color: var(--bkg-color);
|
|
4
|
+
position: absolute;
|
|
5
|
+
top: 0;
|
|
6
|
+
height: 100%;
|
|
7
|
+
width: 100%;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.hidden {
|
|
12
|
+
display: none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.center {
|
|
16
|
+
position: absolute;
|
|
17
|
+
top: 50%;
|
|
18
|
+
left: 50%;
|
|
19
|
+
transform: translate(-50%, -50%);
|
|
20
|
+
margin: 10px;
|
|
21
|
+
text-align: center;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.loading span {
|
|
25
|
+
color: var(--text-color);
|
|
26
|
+
display: block;
|
|
27
|
+
margin-top: 1rem;
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.loading span.quote {
|
|
32
|
+
font-style: italic;
|
|
33
|
+
font-weight: 300;
|
|
34
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import IGirafeContext from '../../../tools/context/icontext.js';
|
|
2
|
+
import BaseLayer from '../../../models/layers/baselayer.js';
|
|
3
|
+
import LayerWms from '../../../models/layers/layerwms.js';
|
|
4
|
+
import Basemap from '../../../models/basemaps/basemap.js';
|
|
5
|
+
import { CameraConfig } from '../../../tools/state/globe.js';
|
|
6
|
+
declare global {
|
|
7
|
+
interface Window {
|
|
8
|
+
Cesium: unknown;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The 3D Globe, based on Cesium and synchronized with the OpenLayers map by OLCesium.
|
|
13
|
+
*
|
|
14
|
+
* This module is the only place where Cesium and OLCesium are used. It is loaded on demand
|
|
15
|
+
* by the map-3d Component, so that those (heavy) libraries stay out of the initial bundle
|
|
16
|
+
* as long as the 3D Map is not displayed.
|
|
17
|
+
*/
|
|
18
|
+
export default class Globe {
|
|
19
|
+
private readonly context;
|
|
20
|
+
private readonly toolName;
|
|
21
|
+
private readonly pixelTolerance;
|
|
22
|
+
olCesium: any;
|
|
23
|
+
private scene;
|
|
24
|
+
private wmsManager3d;
|
|
25
|
+
private get state();
|
|
26
|
+
private get config();
|
|
27
|
+
constructor(context: IGirafeContext, toolName: string, pixelTolerance: number);
|
|
28
|
+
/**
|
|
29
|
+
* Loads Cesium and OLCesium and initializes the globe on the given target element.
|
|
30
|
+
*/
|
|
31
|
+
initialize(target: HTMLDivElement): Promise<void>;
|
|
32
|
+
private registerSelection;
|
|
33
|
+
setEnabled(enabled: boolean): void;
|
|
34
|
+
setShadows(shadows: boolean): void;
|
|
35
|
+
setCamera(camera: CameraConfig | null): void;
|
|
36
|
+
private addAllActiveLayers;
|
|
37
|
+
onLayerToggled(layer: LayerWms): void;
|
|
38
|
+
changeOpacity(layer: BaseLayer): void;
|
|
39
|
+
changeBasemapOpacity(basemap: Basemap): void;
|
|
40
|
+
changeFilter(layer: LayerWms): void;
|
|
41
|
+
onChangeBasemaps(basemaps: Basemap[]): void;
|
|
42
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import * as Cesium from 'cesium';
|
|
2
|
+
import proj4 from 'proj4';
|
|
3
|
+
import WmsManager3d from './wmsmanager3d.js';
|
|
4
|
+
import GroupLayer from '../../../models/layers/grouplayer.js';
|
|
5
|
+
import LayerWms from '../../../models/layers/layerwms.js';
|
|
6
|
+
import { applyOpacityToLayers } from '../../../tools/utils/utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* The 3D Globe, based on Cesium and synchronized with the OpenLayers map by OLCesium.
|
|
9
|
+
*
|
|
10
|
+
* This module is the only place where Cesium and OLCesium are used. It is loaded on demand
|
|
11
|
+
* by the map-3d Component, so that those (heavy) libraries stay out of the initial bundle
|
|
12
|
+
* as long as the 3D Map is not displayed.
|
|
13
|
+
*/
|
|
14
|
+
export default class Globe {
|
|
15
|
+
context;
|
|
16
|
+
toolName;
|
|
17
|
+
pixelTolerance;
|
|
18
|
+
// TODO REG : Howto use the right type here without importing the whole library (it needs to be imported only on demand) ?
|
|
19
|
+
// This works but needs the library: type OLCesiumType = typeof OLCesium;
|
|
20
|
+
olCesium;
|
|
21
|
+
scene;
|
|
22
|
+
wmsManager3d;
|
|
23
|
+
get state() {
|
|
24
|
+
return this.context.stateManager.state;
|
|
25
|
+
}
|
|
26
|
+
get config() {
|
|
27
|
+
return this.context.configManager.Config.map3d;
|
|
28
|
+
}
|
|
29
|
+
constructor(context, toolName, pixelTolerance) {
|
|
30
|
+
this.context = context;
|
|
31
|
+
this.toolName = toolName;
|
|
32
|
+
this.pixelTolerance = pixelTolerance;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Loads Cesium and OLCesium and initializes the globe on the given target element.
|
|
36
|
+
*/
|
|
37
|
+
async initialize(target) {
|
|
38
|
+
window.Cesium = Cesium;
|
|
39
|
+
const olcs = await import('olcs');
|
|
40
|
+
this.olCesium = new olcs.default({
|
|
41
|
+
map: this.context.mapManager.getMap(),
|
|
42
|
+
target: target,
|
|
43
|
+
time: () => {
|
|
44
|
+
const date = new Date(this.state.globe.shadowsTimestamp);
|
|
45
|
+
return Number.isNaN(date.getTime()) ? Cesium.JulianDate.now() : Cesium.JulianDate.fromDate(date);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const scene = this.olCesium.getCesiumScene();
|
|
49
|
+
this.scene = scene;
|
|
50
|
+
const config = this.config;
|
|
51
|
+
scene.screenSpaceCameraController.maximumZoomDistance = config.maximumZoomDistance ?? 30000;
|
|
52
|
+
// Add terrain
|
|
53
|
+
if (config.terrainUrl) {
|
|
54
|
+
scene.terrainProvider = await Cesium.CesiumTerrainProvider.fromUrl(config.terrainUrl);
|
|
55
|
+
}
|
|
56
|
+
// Add terrain imagery
|
|
57
|
+
let coverage = Cesium.Rectangle.MAX_VALUE;
|
|
58
|
+
if (config.terrainImagery) {
|
|
59
|
+
if (config.terrainImagery.coverageArea) {
|
|
60
|
+
coverage = Cesium.Rectangle.fromDegrees(...config.terrainImagery.coverageArea);
|
|
61
|
+
}
|
|
62
|
+
scene.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
|
|
63
|
+
url: config.terrainImagery.url,
|
|
64
|
+
minimumLevel: config.terrainImagery.minLoD ?? 0,
|
|
65
|
+
maximumLevel: config.terrainImagery.maxLoD,
|
|
66
|
+
tilingScheme: config.terrainImagery.srid === 3857
|
|
67
|
+
? new Cesium.WebMercatorTilingScheme()
|
|
68
|
+
: new Cesium.GeographicTilingScheme(),
|
|
69
|
+
rectangle: coverage
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
// Add 3D-Tiles layers
|
|
73
|
+
const tilesetOptions = {
|
|
74
|
+
// If the error of the model is higher than this, we increase the resolution
|
|
75
|
+
maximumScreenSpaceError: 0.5,
|
|
76
|
+
// Enable different level of details based on the distance from the camera
|
|
77
|
+
dynamicScreenSpaceError: true,
|
|
78
|
+
// Model error at the max distance from the camera (higher = distant models are of lower quality)
|
|
79
|
+
dynamicScreenSpaceErrorFactor: config.tilesetsMaxError ?? 7
|
|
80
|
+
};
|
|
81
|
+
config.tilesetsUrls.forEach((tilesetUrl) => {
|
|
82
|
+
Cesium.Cesium3DTileset.fromUrl(tilesetUrl, tilesetOptions).then((t) => scene.primitives.add(t));
|
|
83
|
+
});
|
|
84
|
+
// REG: ambientOcclusion was temporary deactivated because of performance impact and horizontal lines artefacts
|
|
85
|
+
// const ambientOcclusion = scene.postProcessStages.ambientOcclusion;
|
|
86
|
+
// ambientOcclusion.enabled = true;
|
|
87
|
+
// ambientOcclusion.uniforms.bias = 0.5;
|
|
88
|
+
// ambientOcclusion.uniforms.stepSize = 1;
|
|
89
|
+
// ambientOcclusion.uniforms.blurStepSize = 1;
|
|
90
|
+
// REG: Adding the following line solves the problem, but it remains a log less performatn with ambiant occlusion.
|
|
91
|
+
// So I don't know what we want to do with it.
|
|
92
|
+
// See https://github.com/CesiumGS/cesium/issues/13039#issuecomment-3583233494
|
|
93
|
+
// viewer.camera.frustum.near = 1.0;
|
|
94
|
+
this.registerSelection();
|
|
95
|
+
this.wmsManager3d = new WmsManager3d(scene, this.context);
|
|
96
|
+
this.state.layers.layersList.forEach((l) => this.addAllActiveLayers(l));
|
|
97
|
+
const camera = scene.camera;
|
|
98
|
+
camera.changed.addEventListener(() => {
|
|
99
|
+
console.debug('Cesium camera moved');
|
|
100
|
+
this.state.globe.camera = {
|
|
101
|
+
heading: camera.heading,
|
|
102
|
+
pitch: camera.pitch,
|
|
103
|
+
roll: camera.roll
|
|
104
|
+
};
|
|
105
|
+
}, 1);
|
|
106
|
+
}
|
|
107
|
+
registerSelection() {
|
|
108
|
+
const scene = this.scene;
|
|
109
|
+
const pickOnGlobe = (position) => {
|
|
110
|
+
const ray = scene.camera.getPickRay(position);
|
|
111
|
+
return ray == undefined ? undefined : scene.globe.pick(ray, scene);
|
|
112
|
+
};
|
|
113
|
+
const cesiumScreenToLocalCoord = (position) => {
|
|
114
|
+
const cart = Cesium.Cartographic.fromCartesian(pickOnGlobe(position));
|
|
115
|
+
const longLat = [Cesium.Math.toDegrees(cart.longitude), Cesium.Math.toDegrees(cart.latitude)];
|
|
116
|
+
return proj4('EPSG:4326', this.context.configManager.Config.map.srid, longLat);
|
|
117
|
+
};
|
|
118
|
+
this.context.userInteractionManager.registerListener('globe.select', true, this.toolName);
|
|
119
|
+
const eventHandler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
|
|
120
|
+
eventHandler.setInputAction((event) => {
|
|
121
|
+
// If the click is on the map and selection is allowed
|
|
122
|
+
if (Cesium.defined(event.position) &&
|
|
123
|
+
this.context.userInteractionManager.canListenerExecute('globe.select', this.toolName)) {
|
|
124
|
+
const topLeftScreen = event.position.clone();
|
|
125
|
+
topLeftScreen.x -= this.pixelTolerance;
|
|
126
|
+
topLeftScreen.y -= this.pixelTolerance;
|
|
127
|
+
const bottomRightScreen = event.position.clone();
|
|
128
|
+
bottomRightScreen.x += this.pixelTolerance;
|
|
129
|
+
bottomRightScreen.y += this.pixelTolerance;
|
|
130
|
+
const topLeft = cesiumScreenToLocalCoord(topLeftScreen);
|
|
131
|
+
const bottomRight = cesiumScreenToLocalCoord(bottomRightScreen);
|
|
132
|
+
this.context.selectionManager.select([topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]]);
|
|
133
|
+
}
|
|
134
|
+
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
|
135
|
+
}
|
|
136
|
+
setEnabled(enabled) {
|
|
137
|
+
this.olCesium.setEnabled(enabled);
|
|
138
|
+
}
|
|
139
|
+
setShadows(shadows) {
|
|
140
|
+
this.scene.shadowMap.enabled = this.scene.globe.enableLighting = shadows;
|
|
141
|
+
}
|
|
142
|
+
setCamera(camera) {
|
|
143
|
+
if (!camera) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this.scene.camera.setView({
|
|
147
|
+
destination: this.scene.camera.position, // Keep current position
|
|
148
|
+
orientation: {
|
|
149
|
+
heading: camera.heading,
|
|
150
|
+
pitch: camera.pitch,
|
|
151
|
+
roll: camera.roll
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
addAllActiveLayers(layer) {
|
|
156
|
+
if (layer instanceof LayerWms) {
|
|
157
|
+
if (layer.active) {
|
|
158
|
+
this.wmsManager3d.addLayer(layer);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (layer instanceof GroupLayer) {
|
|
162
|
+
layer.children.forEach((l) => this.addAllActiveLayers(l));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
onLayerToggled(layer) {
|
|
166
|
+
if (layer.active) {
|
|
167
|
+
this.wmsManager3d.addLayer(layer);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
this.wmsManager3d.removeLayer(layer);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
changeOpacity(layer) {
|
|
174
|
+
if (layer instanceof LayerWms) {
|
|
175
|
+
this.wmsManager3d.changeOpacity(layer);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
changeBasemapOpacity(basemap) {
|
|
179
|
+
applyOpacityToLayers(basemap.opacity, basemap.layersList, (layer) => this.changeOpacity(layer));
|
|
180
|
+
}
|
|
181
|
+
changeFilter(layer) {
|
|
182
|
+
this.wmsManager3d.changeFilter(layer);
|
|
183
|
+
}
|
|
184
|
+
onChangeBasemaps(basemaps) {
|
|
185
|
+
this.wmsManager3d.removeAllBasemapLayers();
|
|
186
|
+
for (const layer of basemaps.flatMap((basemap) => basemap.layersList)) {
|
|
187
|
+
if (layer instanceof LayerWms) {
|
|
188
|
+
this.wmsManager3d.addBasemapLayer(layer);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Apply default opacity
|
|
192
|
+
for (const basemap of basemaps) {
|
|
193
|
+
if (!basemap.opacityDisabled) {
|
|
194
|
+
this.changeBasemapOpacity(basemap);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -44,10 +44,12 @@ declare class SearchComponent extends GirafeHTMLElement {
|
|
|
44
44
|
* @param e
|
|
45
45
|
*/
|
|
46
46
|
doSearchDebounced(e: Event): Promise<void>;
|
|
47
|
+
addFullThemeIfNotPresent(feature: Feature): void;
|
|
47
48
|
getGroupIcon(searchGroup: string): any;
|
|
48
49
|
getProviderClass(provider: string): "hidden" | "provider entry";
|
|
49
50
|
getGroupClass(group: string): "hidden" | "group entry";
|
|
50
51
|
getLabel(result: Feature): unknown;
|
|
52
|
+
isFeatureActionThemeRelated(feature: Feature): boolean;
|
|
51
53
|
onMouseOver(result: Feature): void;
|
|
52
54
|
onMouseLeave(): void;
|
|
53
55
|
private focusResultFromIndex;
|
|
@@ -56,6 +58,9 @@ declare class SearchComponent extends GirafeHTMLElement {
|
|
|
56
58
|
private addFeatureToPreview;
|
|
57
59
|
clearPreview(): void;
|
|
58
60
|
onSelect(feature: Feature): void;
|
|
61
|
+
private closeDropdown;
|
|
62
|
+
private updateSearchboxWithResult;
|
|
63
|
+
private getFeatureFirstAction;
|
|
59
64
|
private addResultToTreeView;
|
|
60
65
|
private zoomTo;
|
|
61
66
|
onMouseMove(): void;
|
|
@@ -28,10 +28,10 @@ class SearchComponent extends GirafeHTMLElement {
|
|
|
28
28
|
return uHtml `<style>
|
|
29
29
|
.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);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}}
|
|
30
30
|
</style><style>
|
|
31
|
-
.hidden{display:none}#searchbox{background-color:var(--bkg-color);border:1px solid #cfd6dd;border-radius:4px;flex-direction:row;width:100%;height:2.25rem;display:flex;& slot[name=search-tooltip]{display:none}}#search{-webkit-appearance:none;width:auto;height:2.25rem;color:var(--text-color);background:0 0;border:0;outline:none;-webkit-flex:auto;-ms-flex:auto;flex:auto;margin:0 0 0 .5rem;padding-left:.8rem;font-size:1rem}.search-icon,.close-icon,.select-color-icon{width:14px;color:var(--text-color);padding:0 1rem}.close-button,.select-color-button{cursor:pointer;background-color:#0000;border:none;padding:0}#results{z-index:1000;background-color:var(--bkg-color);scrollbar-width:thin;width:36rem;max-height:31rem;margin-top:.1rem;margin-bottom:.5rem;position:absolute;top:3.5rem;overflow-x:hidden}.entry{width:34rem;color:var(--text-color);padding:.3rem 1rem;line-height:1.3rem;display:inline-block}.provider,.group{font-size:1.2rem;font-weight:600;line-height:3rem}.provider{background-color:color-mix(in srgb, var(--bkg-color-grad1) 75%, transparent);margin-top:1rem;font-size:1.5rem}#results>.provider:first-child{margin-top:0}.result{
|
|
31
|
+
.hidden{display:none}#searchbox{background-color:var(--bkg-color);border:1px solid #cfd6dd;border-radius:4px;flex-direction:row;width:100%;height:2.25rem;display:flex;& slot[name=search-tooltip]{display:none}}#search{-webkit-appearance:none;width:auto;height:2.25rem;color:var(--text-color);background:0 0;border:0;outline:none;-webkit-flex:auto;-ms-flex:auto;flex:auto;margin:0 0 0 .5rem;padding-left:.8rem;font-size:1rem}.search-icon,.close-icon,.theme-icon,.select-color-icon{width:14px;color:var(--text-color);padding:0 1rem}.close-button,.select-color-button{cursor:pointer;background-color:#0000;border:none;padding:0}#results{z-index:1000;background-color:var(--bkg-color);scrollbar-width:thin;width:36rem;max-height:31rem;margin-top:.1rem;margin-bottom:.5rem;position:absolute;top:3.5rem;overflow-x:hidden}.entry{width:34rem;color:var(--text-color);padding:.3rem 1rem;line-height:1.3rem;display:inline-block}.entry img{width:.8em;margin-right:1rem}.entry span{text-transform:uppercase}.provider,.group{font-size:1.2rem;font-weight:600;line-height:3rem}.provider{background-color:color-mix(in srgb, var(--bkg-color-grad1) 75%, transparent);margin-top:1rem;font-size:1.5rem}#results>.provider:first-child{margin-top:0}.result{background:0 0;border-top:1px solid #ccc;align-items:stretch;width:100%;padding:0;display:flex}.result button{cursor:pointer;text-align:left;width:100%;color:var(--text-color);background:0 0;border:none;padding:.3rem 1rem}.result button:hover{color:var(--text-color);background-color:var(--bkg-color-grad2)!important}.result .tools{width:1.3rem;margin:0}.result .tools button{height:-webkit-fill-available;margin:0;padding:0 .3rem}.result .tools button img{margin:0;padding:0}#no-result{background:var(--warning-color);opacity:.75;visibility:hidden;pointer-events:none;border-radius:6px;width:fit-content;margin:auto;padding:.5rem 0;font-size:1rem;position:absolute;top:3.5rem;left:0;right:0}#no-result>span{padding:1.3rem}@keyframes fadeOut{0%{opacity:1}80%{opacity:1}to{opacity:0}}.shown-then-fadeout{animation:2s ease-in-out forwards fadeOut;visibility:visible!important}
|
|
32
32
|
</style>
|
|
33
33
|
<style>${this.customStyle}</style>
|
|
34
|
-
<link rel="stylesheet" href="lib/vanilla-picker/vanilla-picker.csp.css"><link rel="stylesheet" href="styles/girafecolorpicker.css"><div id="searchbox"><slot name="search-tooltip"></slot><input id="search" class="gg-input" length="20" maxlength="1000" autocomplete="off" autocorrect="off" i18n="Search..." placeholder="Search..." aria-label="Search" oninput="${(e) => this.doSearchDebounced(e)}" onfocusin="${() => this.onFocusIn()}" onfocusout="${() => this.onFocusOut()}" onkeydown="${(e) => this.onKeyDown(e)}"> <img class="${this.allResults.length > 0 ? 'hidden' : 'search-icon'}" alt="search-icon" src="${this.searchIcon}"> <button class="${this.allResults.length > 0 ? 'close-button' : 'hidden'}" onclick="${() => this.clearSearch(true)}"><img class="close-icon" alt="close-icon" src="icons/close.svg"></button> <button tip="change_search_result_color" id="colorPickerBtn" class="${this.paintSearchResults ? 'select-color-button' : 'hidden'}"><img class="select-color-icon" alt="select-color-icon" src="${this.paintbrushIcon}"></button><div id="results" class="${!this.allResults.length || this.forceHide ? 'hidden' : ''}" onmousemove="${() => this.onMouseMove()}">${(Object.keys(this.groupedResults) ?? []).map(provider => uHtml `<div class="${this.getProviderClass(provider)}"><img alt="provider icon" src="${this.searchIcon}"> <span i18n="${provider}">${provider}</span></div>${(Object.keys(this.groupedResults[provider]) ?? []).map(group => uHtml `<div class="${this.getGroupClass(group)}"><img alt="result icon" src="${this.getGroupIcon(group)}"> <span i18n="${group}">${group}</span></div>${(this.groupedResults[provider][group] ?? []).map(result => uHtml
|
|
34
|
+
<link rel="stylesheet" href="lib/vanilla-picker/vanilla-picker.csp.css"><link rel="stylesheet" href="styles/girafecolorpicker.css"><div id="searchbox"><slot name="search-tooltip"></slot><input id="search" class="gg-input" length="20" maxlength="1000" autocomplete="off" autocorrect="off" i18n="Search..." placeholder="Search..." aria-label="Search" oninput="${(e) => this.doSearchDebounced(e)}" onfocusin="${() => this.onFocusIn()}" onfocusout="${() => this.onFocusOut()}" onkeydown="${(e) => this.onKeyDown(e)}"> <img class="${this.allResults.length > 0 ? 'hidden' : 'search-icon'}" alt="search-icon" src="${this.searchIcon}"> <button class="${this.allResults.length > 0 ? 'close-button' : 'hidden'}" onclick="${() => this.clearSearch(true)}"><img class="close-icon" alt="close-icon" src="icons/close.svg"></button> <button tip="change_search_result_color" id="colorPickerBtn" class="${this.paintSearchResults ? 'select-color-button' : 'hidden'}"><img class="select-color-icon" alt="select-color-icon" src="${this.paintbrushIcon}"></button><div id="results" class="${!this.allResults.length || this.forceHide ? 'hidden' : ''}" onmousemove="${() => this.onMouseMove()}">${(Object.keys(this.groupedResults) ?? []).map(provider => uHtml `<div class="${this.getProviderClass(provider)}"><img alt="provider icon" src="${this.searchIcon}"> <span i18n="${provider}">${provider}</span></div>${(Object.keys(this.groupedResults[provider]) ?? []).map(group => uHtml `<div class="${this.getGroupClass(group)}"><img alt="result icon" src="${this.getGroupIcon(group)}"> <span i18n="${group}">${group}</span></div>${(this.groupedResults[provider][group] ?? []).map(result => uHtml `<div class="${result.get('selected') ? 'result entry selected' : 'result entry'}"><button onmouseover="${() => this.onMouseOver(result)}" onmouseleave="${() => this.onMouseLeave()}" onmousedown="${() => this.onMouseDown()}" onclick="${() => this.onSelect(result)}">${this.getLabel(result)}</button><div class="${this.isFeatureActionThemeRelated(result) ? 'tools' : 'hidden'}"><button class="addFullTree" onclick="${() => this.addFullThemeIfNotPresent(result)}"><img class="theme-icon" alt="theme-icon" src="icons/theme-checked.svg" tip="Complete the theme"></button></div></div>`)} `)} `)}</div><div id="no-result" class="${this.showNoResultWarning ? 'shown-then-fadeout' : ''}"><span i18n="${'No match found'}"></span></div></div>
|
|
35
35
|
${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
36
36
|
};
|
|
37
37
|
searchIcon = SearchIcon;
|
|
@@ -205,6 +205,33 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
205
205
|
this.doSearch(syntheticEvent);
|
|
206
206
|
}, 300);
|
|
207
207
|
}
|
|
208
|
+
addFullThemeIfNotPresent(feature) {
|
|
209
|
+
this.clearPreview();
|
|
210
|
+
const action = this.getFeatureFirstAction(feature);
|
|
211
|
+
if (!action) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const layer = this.context.themesHelper.findLayerByName(action.data);
|
|
215
|
+
if (!layer) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const theme = this.context.themesHelper.getOriginalTheme(layer);
|
|
219
|
+
if (!theme) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const added = this.context.themesHelper.addThemeIfNotPresent(theme);
|
|
223
|
+
if (!added) {
|
|
224
|
+
// If it's not added because it's already in the tree, complete the theme.
|
|
225
|
+
this.context.themesHelper.completeTheme(theme);
|
|
226
|
+
}
|
|
227
|
+
const insertedLayer = this.context.themesHelper.findBaseLayerRecursiveById(this.state.layers.layersList, layer.id);
|
|
228
|
+
if (insertedLayer) {
|
|
229
|
+
insertedLayer.activeState = 'on';
|
|
230
|
+
}
|
|
231
|
+
this.closeDropdown(feature);
|
|
232
|
+
this.onFocusOut();
|
|
233
|
+
this.updateSearchboxWithResult(feature);
|
|
234
|
+
}
|
|
208
235
|
getGroupIcon(searchGroup) {
|
|
209
236
|
switch (searchGroup) {
|
|
210
237
|
case 'Group':
|
|
@@ -230,6 +257,16 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
230
257
|
getLabel(result) {
|
|
231
258
|
return result.get('label_html') ? this.htmlUnsafe(result.get('label_html')) : result.get('label');
|
|
232
259
|
}
|
|
260
|
+
isFeatureActionThemeRelated(feature) {
|
|
261
|
+
const action = this.getFeatureFirstAction(feature);
|
|
262
|
+
const kind = action?.action;
|
|
263
|
+
const hasThemeRelatedAction = kind?.startsWith('add_layer') || kind?.startsWith('add_group') || kind?.startsWith('add_theme') || false;
|
|
264
|
+
if (!hasThemeRelatedAction || !action) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
const layer = this.context.themesHelper.findLayerByName(action.data);
|
|
268
|
+
return !!layer;
|
|
269
|
+
}
|
|
233
270
|
onMouseOver(result) {
|
|
234
271
|
this.focusResult(result);
|
|
235
272
|
}
|
|
@@ -249,7 +286,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
249
286
|
if (this.focusedResult) {
|
|
250
287
|
this.focusedResult.set('selected', false);
|
|
251
288
|
}
|
|
252
|
-
// Set
|
|
289
|
+
// Set the newly selected object and activate a preview.
|
|
253
290
|
this.focusedResultIndex = this.allResults.indexOf(result);
|
|
254
291
|
this.focusedResult = this.allResults[this.focusedResultIndex];
|
|
255
292
|
this.focusedResult.set('selected', true);
|
|
@@ -265,7 +302,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
265
302
|
this.addFeatureToPreview(result);
|
|
266
303
|
this.updatePreviewLayerStyle();
|
|
267
304
|
}
|
|
268
|
-
const firstAction =
|
|
305
|
+
const firstAction = this.getFeatureFirstAction(result);
|
|
269
306
|
if (firstAction?.action.startsWith('add_layer') && this.context.configManager.Config.search?.layerPreview) {
|
|
270
307
|
const layer = this.context.themesHelper.findLayerByName(firstAction.data);
|
|
271
308
|
if (layer) {
|
|
@@ -294,11 +331,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
294
331
|
}
|
|
295
332
|
}
|
|
296
333
|
onSelect(feature) {
|
|
297
|
-
this.
|
|
298
|
-
this.ignoreBlur = false;
|
|
299
|
-
this.forceHide = true;
|
|
300
|
-
this.previewLayers = undefined;
|
|
301
|
-
super.render();
|
|
334
|
+
this.closeDropdown(feature);
|
|
302
335
|
// If the result has a specific zoom-to extent defined or contains a geometry, zoom to it
|
|
303
336
|
const zoomBbox = this.context.searchManager.getZoomToBbox(feature);
|
|
304
337
|
if (zoomBbox) {
|
|
@@ -308,33 +341,46 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
308
341
|
this.addResultToTreeView(feature);
|
|
309
342
|
}
|
|
310
343
|
this.onFocusOut();
|
|
311
|
-
|
|
344
|
+
this.updateSearchboxWithResult(feature);
|
|
345
|
+
}
|
|
346
|
+
closeDropdown(feature) {
|
|
347
|
+
this.selectedResult = feature;
|
|
348
|
+
this.ignoreBlur = false;
|
|
349
|
+
this.forceHide = true;
|
|
350
|
+
this.previewLayers = undefined;
|
|
351
|
+
super.render();
|
|
352
|
+
}
|
|
353
|
+
updateSearchboxWithResult(feature) {
|
|
312
354
|
if (this.searchInput && feature.get('label')) {
|
|
313
355
|
this.searchInput.value = feature.get('label');
|
|
314
356
|
}
|
|
315
357
|
}
|
|
316
|
-
|
|
317
|
-
let clonedTheme;
|
|
358
|
+
getFeatureFirstAction(feature) {
|
|
318
359
|
const actions = feature.get('actions');
|
|
319
|
-
|
|
360
|
+
return actions?.length ? actions[0] : undefined;
|
|
361
|
+
}
|
|
362
|
+
addResultToTreeView(feature) {
|
|
363
|
+
const action = this.getFeatureFirstAction(feature);
|
|
364
|
+
if (!action) {
|
|
320
365
|
// Nothing to add
|
|
321
366
|
return;
|
|
322
367
|
}
|
|
368
|
+
let clonedTheme;
|
|
323
369
|
let activate = false;
|
|
324
|
-
if (
|
|
325
|
-
const theme = this.context.themesHelper.findThemeByName(
|
|
370
|
+
if (action.action.startsWith('add_theme')) {
|
|
371
|
+
const theme = this.context.themesHelper.findThemeByName(action.data);
|
|
326
372
|
if (theme) {
|
|
327
373
|
clonedTheme = theme.clone();
|
|
328
374
|
}
|
|
329
375
|
}
|
|
330
|
-
else if (
|
|
331
|
-
const group = this.context.themesHelper.findGroupByName(
|
|
376
|
+
else if (action.action.startsWith('add_group')) {
|
|
377
|
+
const group = this.context.themesHelper.findGroupByName(action.data);
|
|
332
378
|
if (group) {
|
|
333
379
|
clonedTheme = this.context.themesHelper.getMinimalClonedThemeForLayer(group);
|
|
334
380
|
}
|
|
335
381
|
}
|
|
336
|
-
else if (
|
|
337
|
-
const layer = this.context.themesHelper.findLayerByName(
|
|
382
|
+
else if (action.action.startsWith('add_layer')) {
|
|
383
|
+
const layer = this.context.themesHelper.findLayerByName(action.data);
|
|
338
384
|
if (layer) {
|
|
339
385
|
clonedTheme = this.context.themesHelper.getMinimalClonedThemeForLayer(layer);
|
|
340
386
|
activate = true;
|
|
@@ -516,6 +562,9 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
|
|
|
516
562
|
return `data:image/svg+xml;utf8,${encodeURIComponent(pin)}`;
|
|
517
563
|
}
|
|
518
564
|
}
|
|
565
|
+
__decorate([
|
|
566
|
+
UsedInTemplateOnly()
|
|
567
|
+
], SearchComponent.prototype, "addFullThemeIfNotPresent", null);
|
|
519
568
|
__decorate([
|
|
520
569
|
UsedInTemplateOnly()
|
|
521
570
|
], SearchComponent.prototype, "getGroupIcon", null);
|
|
@@ -528,4 +577,7 @@ __decorate([
|
|
|
528
577
|
__decorate([
|
|
529
578
|
UsedInTemplateOnly()
|
|
530
579
|
], SearchComponent.prototype, "getLabel", null);
|
|
580
|
+
__decorate([
|
|
581
|
+
UsedInTemplateOnly()
|
|
582
|
+
], SearchComponent.prototype, "isFeatureActionThemeRelated", null);
|
|
531
583
|
export default SearchComponent;
|