17
17
:z-index =" index + startingZIndexForVisibleLayers"
18
18
/>
19
19
<CesiumInternalLayer
20
- v-for =" (layer, index) in visiblePrimitiveLayers "
20
+ v-for =" (layer, index) in visibleGeoJsonLayers "
21
21
:key =" layer.getID()"
22
22
:layer-config =" layer"
23
23
:preview-year =" previewYear"
31
31
:z-index =" index"
32
32
/>
33
33
</div >
34
+ <CesiumPopover
35
+ v-if =" showFeaturesPopover"
36
+ :coordinates =" popoverCoordinates"
37
+ authorize-print
38
+ @close =" onPopupClose"
39
+ :use-content-padding =" !!editFeature"
40
+ >
41
+ <template #extra-buttons >
42
+ <button
43
+ class =" btn btn-sm btn-light d-flex align-items-center"
44
+ data-cy =" toggle-floating-off"
45
+ @click =" toggleFloatingTooltip"
46
+ >
47
+ <FontAwesomeIcon icon =" caret-down" />
48
+ </button >
49
+ </template >
50
+ <FeatureEdit v-if =" editFeature" :read-only =" true" :feature =" editFeature" />
51
+ <FeatureList direction =" column" />
52
+ </CesiumPopover >
34
53
</div >
35
54
<cesium-compass v-show =" isDesktopMode" ref =" compass" ></cesium-compass >
36
55
<slot />
@@ -51,10 +70,13 @@ import '@geoblocks/cesium-compass'
51
70
import * as cesium from ' cesium'
52
71
import {
53
72
Cartesian3 ,
73
+ Cartographic ,
54
74
CesiumTerrainProvider ,
55
75
Color ,
56
76
Math as CesiumMath ,
57
77
RequestScheduler ,
78
+ ScreenSpaceEventHandler ,
79
+ ScreenSpaceEventType ,
58
80
Viewer ,
59
81
} from ' cesium'
60
82
import { mapActions , mapGetters , mapState } from ' vuex'
@@ -70,9 +92,29 @@ import { calculateHeight, limitCameraCenter, limitCameraPitchRoll } from './util
70
92
import GeoAdminWMSLayer from ' @/api/layers/GeoAdminWMSLayer.class'
71
93
import GeoAdminGeoJsonLayer from ' @/api/layers/GeoAdminGeoJsonLayer.class'
72
94
import KMLLayer from ' @/api/layers/KMLLayer.class'
95
+ import CesiumPopover from ' @/modules/map/components/cesium/CesiumPopover.vue'
96
+ import { ClickInfo , ClickType } from ' @/store/modules/map.store'
97
+ import proj4 from ' proj4'
98
+ import { LV95 , WEBMERCATOR , WGS84 } from ' @/utils/coordinateSystems'
99
+ import FeatureList from ' @/modules/infobox/components/FeatureList.vue'
100
+ import {
101
+ highlightGroup ,
102
+ unhighlightGroup ,
103
+ } from ' @/modules/map/components/cesium/utils/highlightUtils'
104
+ import { createGeoJSONFeature } from ' @/utils/layerUtils'
105
+ import {
106
+ isInBounds ,
107
+ LV95_BOUNDS ,
108
+ reprojectUnknownSrsCoordsToWebMercator ,
109
+ } from ' @/utils/coordinateUtils'
110
+ import { extractOlFeatureGeodesicCoordinates } from ' @/modules/drawing/lib/drawingUtils'
111
+ import log from ' @/utils/logging'
112
+ import { LineString , Point , Polygon } from ' ol/geom'
113
+ import FeatureEdit from ' @/modules/infobox/components/FeatureEdit.vue'
114
+ import OpenLayersPopover from ' @/modules/map/components/openlayers/OpenLayersPopover.vue'
73
115
74
116
export default {
75
- components: { CesiumInternalLayer },
117
+ components: { OpenLayersPopover, FeatureEdit, FeatureList, CesiumPopover, CesiumInternalLayer },
76
118
provide () {
77
119
return {
78
120
// sharing cesium viewer object with children components
@@ -97,6 +139,7 @@ export default {
97
139
false ,
98
140
[]
99
141
),
142
+ popoverCoordinates: [],
100
143
}
101
144
},
102
145
computed: {
@@ -106,6 +149,8 @@ export default {
106
149
camera : (state ) => state .position .camera ,
107
150
uiMode : (state ) => state .ui .mode ,
108
151
previewYear : (state ) => state .layers .previewYear ,
152
+ isFeatureTooltipInFooter : (state ) => ! state .ui .floatingTooltip ,
153
+ selectedFeatures : (state ) => state .features .selectedFeatures ,
109
154
}),
110
155
... mapGetters ([' centerEpsg4326' , ' resolution' , ' hasDevSiteWarning' , ' visibleLayers' ]),
111
156
isDesktopMode () {
@@ -119,12 +164,64 @@ export default {
119
164
(l ) => l instanceof GeoAdminWMTSLayer || l instanceof GeoAdminWMSLayer
120
165
)
121
166
},
122
- visiblePrimitiveLayers () {
167
+ visibleGeoJsonLayers () {
123
168
return this .visibleLayers .filter ((l ) => l instanceof GeoAdminGeoJsonLayer)
124
169
},
125
170
visibleKMLLayers () {
126
171
return this .visibleLayers .filter ((l ) => l instanceof KMLLayer)
127
172
},
173
+ showFeaturesPopover () {
174
+ return ! this .isFeatureTooltipInFooter && this .selectedFeatures .length > 0
175
+ },
176
+ editFeature () {
177
+ return this .selectedFeatures .find ((feature ) => feature .isEditable )
178
+ },
179
+ },
180
+ watch: {
181
+ selectedFeatures: {
182
+ // we need to deep watch this as otherwise we aren't triggered when
183
+ // coordinates are changed (but only when one feature is added/removed)
184
+ handler (newSelectedFeatures ) {
185
+ if (newSelectedFeatures .length > 0 ) {
186
+ const [firstFeature ] = newSelectedFeatures
187
+ const geometries = newSelectedFeatures .map ((f ) => {
188
+ // GeoJSON and KML layers have different geometry structure
189
+ if (! f .geometry .type ) {
190
+ let type = undefined
191
+ if (f .geometry instanceof Polygon) {
192
+ type = ' Polygon'
193
+ } else if (f .geometry instanceof LineString) {
194
+ type = ' LineString'
195
+ } else if (f .geometry instanceof Point ) {
196
+ type = ' Point'
197
+ }
198
+ const coordinates = f .geometry .getCoordinates ()
199
+ const getCoordinates = (c ) =>
200
+ isInBounds (c[0 ], c[1 ], LV95_BOUNDS )
201
+ ? proj4 (LV95 .epsg , WEBMERCATOR .epsg , c)
202
+ : c
203
+ return {
204
+ type,
205
+ coordinates:
206
+ typeof coordinates[0 ] === ' number'
207
+ ? getCoordinates (coordinates)
208
+ : coordinates .map (getCoordinates),
209
+ }
210
+ }
211
+ return f .geometry
212
+ })
213
+ highlightGroup (this .viewer , geometries)
214
+ const featureCoords = Array .isArray (firstFeature .coordinates [0 ])
215
+ ? firstFeature .coordinates [firstFeature .coordinates .length - 1 ]
216
+ : firstFeature .coordinates
217
+ this .popoverCoordinates = reprojectUnknownSrsCoordsToWebMercator (
218
+ featureCoords[0 ],
219
+ featureCoords[1 ]
220
+ )
221
+ }
222
+ },
223
+ deep: true ,
224
+ },
128
225
},
129
226
beforeCreate () {
130
227
// Global variable required for Cesium and point to the URL where four static directories (see vite.config) are served
@@ -203,6 +300,11 @@ export default {
203
300
this .viewer .scene .postRender .addEventListener (
204
301
limitCameraPitchRoll (CAMERA_MIN_PITCH , CAMERA_MAX_PITCH , 0.0 , 0.0 )
205
302
)
303
+ this .eventHandler = new ScreenSpaceEventHandler (this .viewer .canvas )
304
+ this .eventHandler .setInputAction (
305
+ (event ) => this .onSingleClick (event ),
306
+ ScreenSpaceEventType .LEFT_CLICK
307
+ )
206
308
207
309
this .flyToPosition ()
208
310
@@ -212,13 +314,21 @@ export default {
212
314
globe .maximumScreenSpaceError = 30
213
315
}
214
316
},
317
+ beforeUnmount () {
318
+ this .clearAllSelectedFeatures ()
319
+ },
215
320
unmounted () {
216
321
this .setCameraPosition (null )
217
322
this .viewer .destroy ()
218
323
delete this .viewer
219
324
},
220
325
methods: {
221
- ... mapActions ([' setCameraPosition' ]),
326
+ ... mapActions ([
327
+ ' setCameraPosition' ,
328
+ ' clearAllSelectedFeatures' ,
329
+ ' click' ,
330
+ ' toggleFloatingTooltip' ,
331
+ ]),
222
332
flyToPosition () {
223
333
const x = this .camera ? this .camera .x : this .centerEpsg4326 [0 ]
224
334
const y = this .camera ? this .camera .y : this .centerEpsg4326 [1 ]
@@ -252,6 +362,80 @@ export default {
252
362
roll: CesiumMath .toDegrees (camera .roll ).toFixed (0 ),
253
363
})
254
364
},
365
+ onSingleClick (event ) {
366
+ this .clearAllSelectedFeatures ()
367
+ unhighlightGroup (this .viewer )
368
+ const features = []
369
+ let coordinates = []
370
+ const cartesian = this .viewer .scene .pickPosition (event .position )
371
+ if (cartesian) {
372
+ const cartCoords = Cartographic .fromCartesian (cartesian)
373
+ coordinates = proj4 (WGS84 .epsg , WEBMERCATOR .epsg , [
374
+ (cartCoords .longitude * 180 ) / Math .PI ,
375
+ (cartCoords .latitude * 180 ) / Math .PI ,
376
+ ])
377
+ }
378
+
379
+ let objects = this .viewer .scene .drillPick (event .position )
380
+ const geoJsonFeatures = {}
381
+ const kmlFeatures = {}
382
+ // if there is a GeoJSON layer currently visible, we will find it and search for features under the mouse cursor
383
+ this .visibleGeoJsonLayers .forEach ((geoJSonLayer ) => {
384
+ objects
385
+ .filter ((obj ) => obj .primitive ? .olLayer ? .get (' id' ) === geoJSonLayer .getID ())
386
+ .forEach ((obj ) => {
387
+ const feature = obj .primitive .olFeature
388
+ if (! geoJsonFeatures[feature .getId ()]) {
389
+ geoJsonFeatures[feature .getId ()] = createGeoJSONFeature (
390
+ obj .primitive .olFeature ,
391
+ geoJSonLayer,
392
+ feature .getGeometry ()
393
+ )
394
+ }
395
+ })
396
+ features .push (... Object .values (geoJsonFeatures))
397
+ })
398
+ this .visibleKMLLayers .forEach ((KMLLayer ) => {
399
+ objects
400
+ .filter ((obj ) => obj .primitive ? .olLayer ? .get (' id' ) === KMLLayer .getID ())
401
+ .forEach ((obj ) => {
402
+ const feature = obj .primitive .olFeature
403
+ if (! kmlFeatures[feature .getId ()]) {
404
+ const editableFeature = feature .get (' editableFeature' )
405
+ if (editableFeature) {
406
+ editableFeature .geodesicCoordinates =
407
+ extractOlFeatureGeodesicCoordinates (feature)
408
+ editableFeature .geometry = feature .getGeometry ()
409
+ kmlFeatures[feature .getId ()] = editableFeature
410
+ } else {
411
+ log .debug (
412
+ ' KMLs which are not editable Features are not supported for selection'
413
+ )
414
+ }
415
+ }
416
+ })
417
+ features .push (... Object .values (kmlFeatures))
418
+ })
419
+ // Cesium can't pick position when click on primitive
420
+ if (! coordinates .length && features .length ) {
421
+ const featureCoords = Array .isArray (features[0 ].coordinates [0 ])
422
+ ? features[0 ].coordinates [0 ]
423
+ : features[0 ].coordinates
424
+ coordinates = proj4 (LV95 .epsg , WEBMERCATOR .epsg , featureCoords)
425
+ }
426
+ this .click (
427
+ new ClickInfo (
428
+ coordinates,
429
+ [event .position .x , event .position .y ],
430
+ features,
431
+ ClickType .LEFT_SINGLECLICK
432
+ )
433
+ )
434
+ },
435
+ onPopupClose () {
436
+ this .clearAllSelectedFeatures ()
437
+ unhighlightGroup (this .viewer )
438
+ },
255
439
},
256
440
}
257
441
< / script>
0 commit comments