Skip to content

Commit 6a3129e

Browse files
chore: wip
1 parent 5803c01 commit 6a3129e

10 files changed

Lines changed: 628 additions & 24 deletions

File tree

examples/snowbox/index.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -329,15 +329,10 @@ addPlugin(
329329
'kat_text',
330330
'skat_text',
331331
],
332-
exportProperty: 'filename',
332+
exportProperty: 'pic',
333333
showTooltip: (feature) => feature.get('beschr'),
334334
},
335335
},
336-
coordinateSources: [
337-
{
338-
key: 'selectedCoordinates',
339-
},
340-
],
341336
afterLoadFunction: (featuresByLayerId) => {
342337
Object.values(featuresByLayerId).forEach((featureList) => {
343338
featureList.forEach((feature) => {
@@ -360,6 +355,7 @@ addPlugin(
360355
key: 'activeMaskIds',
361356
},
362357
mode: 'visible',
358+
bindWithCoreHoverSelect: true,
363359
pageLength: 5,
364360
text: {
365361
title: (feature) =>

src/core/stores/index.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
*/
55
/* eslint-enable tsdoc/syntax */
66

7+
import type { Feature } from 'ol'
8+
79
import { acceptHMRUpdate, defineStore, storeToRefs } from 'pinia'
810
import { computed } from 'vue'
911

12+
import { updateSelection } from '../utils/map/setupMarkers'
1013
import { useMainStore } from './main'
1114
import { useMarkerStore } from './marker'
1215
import { useMoveHandleStore } from './moveHandle'
@@ -22,11 +25,13 @@ import { usePluginStore } from './plugin'
2225
export const useCoreStore = defineStore('core', () => {
2326
const mainStore = useMainStore()
2427
const mainStoreRefs = storeToRefs(mainStore)
28+
2529
const moveHandleStore = useMoveHandleStore()
2630

2731
const pluginStore = usePluginStore()
2832

2933
const markerStore = useMarkerStore()
34+
const markerStoreRefs = storeToRefs(markerStore)
3035

3136
return {
3237
/**
@@ -115,6 +120,14 @@ export const useCoreStore = defineStore('core', () => {
115120
*/
116121
language: mainStoreRefs.language,
117122

123+
/**
124+
* Returns the layer with the given ID.
125+
*
126+
* @param layerId - ID of the layer
127+
* @alpha
128+
*/
129+
getLayer: mainStore.getLayer,
130+
118131
/**
119132
* Before instantiating the map, all required plugins have to be added. Depending on how you use POLAR, this may
120133
* already have been done. Ready-made clients (that is, packages prefixed `@polar/client-`) come with plugins prepared.
@@ -168,7 +181,7 @@ export const useCoreStore = defineStore('core', () => {
168181
/**
169182
* Allows reading or setting the OIDC token used for service accesses.
170183
*/
171-
oidcToken: mainStore.oidcToken,
184+
oidcToken: mainStoreRefs.oidcToken,
172185

173186
/**
174187
* Allows accessing the POLAR DOM element (`<polar-map>`).
@@ -204,6 +217,26 @@ export const useCoreStore = defineStore('core', () => {
204217
*/
205218
moveHandleTop: computed(() => moveHandleStore.top),
206219

220+
/**
221+
* Feature that is hovered by the user with a marker.
222+
* NOTE: Set _polarLayerId!
223+
*
224+
* @alpha
225+
*/
226+
hoveredFeature: markerStoreRefs.hovered,
227+
228+
/**
229+
* Feature that was selected by the user with a marker.
230+
*
231+
* @alpha
232+
*/
233+
selectedFeature: computed({
234+
get: () => markerStore.selected,
235+
set: (feature) => {
236+
updateSelection(mainStore.map, feature as Feature)
237+
},
238+
}),
239+
207240
/**
208241
* Coordinates that were selected by the user with a marker.
209242
*

src/core/stores/main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ export const useMainStore = defineStore('main', () => {
7979
center.value = (feature.getGeometry() as Point).getCoordinates()
8080
}
8181

82+
function getLayer(layerId: string) {
83+
return map.value.getAllLayers().find((layer) => layer.get('id') === layerId)
84+
}
85+
8286
function setup() {
8387
addEventListener('resize', updateHasSmallDisplay)
8488
updateHasSmallDisplay()
@@ -112,6 +116,7 @@ export const useMainStore = defineStore('main', () => {
112116
deviceIsHorizontal,
113117
// Actions
114118
centerOnFeature,
119+
getLayer,
115120
updateHasSmallDisplay,
116121
setup,
117122
teardown,

src/core/utils/map/setupMarkers.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,14 @@ function resolveClusterClick(map: Map, feature: Feature) {
8989
})
9090
}
9191

92-
function updateSelection(
92+
/**
93+
* Update the selected marker in the map.
94+
*
95+
* @param map - Map
96+
* @param feature - Feature to select
97+
* @param centerOnFeature - Should the map center on the feature?
98+
*/
99+
export function updateSelection(
93100
map: Map,
94101
feature: Feature | null,
95102
centerOnFeature = false
@@ -207,10 +214,9 @@ export function setupMarkers(map: Map) {
207214

208215
watch(
209216
() => store.hovered,
210-
(feature) => {
211-
if (feature !== null && feature !== toRaw(store.selected)) {
212-
store.hovered?.setStyle(undefined)
213-
store.hovered = null
217+
(feature, oldFeature) => {
218+
if (oldFeature !== null && oldFeature !== toRaw(store.selected)) {
219+
oldFeature.setStyle(undefined)
214220
}
215221
if (feature !== null && feature !== toRaw(store.selected)) {
216222
store.hovered = markRaw(feature)
@@ -220,7 +226,7 @@ export function setupMarkers(map: Map) {
220226
.hoverStyle,
221227
isMultiFeature
222228
)
223-
store.hovered.setStyle(style)
229+
feature.setStyle(style)
224230
}
225231
}
226232
)

src/plugins/gfi/components/GfiFeature.ce.vue

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
<template>
2-
<PolarIconButton
3-
:hint="$t(($) => $.header.close, { ns: 'gfi' })"
4-
icon="kern-icon--close"
5-
@click="gfiStore.featureInformation = {}"
6-
/>
2+
<div style="display: flex; gap: var(--kern-metric-space-default)">
3+
<PolarIconButton
4+
:hint="$t(($) => $.header.close, { ns: 'gfi' })"
5+
icon="kern-icon--close"
6+
@click="gfiStore.selectedFeatures = {}"
7+
/>
8+
<PolarIconButton
9+
:hint="$t(($) => $.property.export, { ns: 'gfi' })"
10+
icon="kern-icon--download"
11+
/>
12+
<pre>{{ typeof exportProperty }} -- {{ exportProperty }}</pre>
13+
</div>
714
<table class="kern-table kern-table--striped">
815
<thead class="kern-table__head">
916
<tr class="kern-table__row">
@@ -102,6 +109,12 @@ const filteredProperties = computed(() =>
102109
.map(([key, value]) => [key, value])
103110
)
104111
)
112+
113+
const exportProperty = computed(() =>
114+
layerConfiguration.value.exportProperty
115+
? props.feature.properties?.[layerConfiguration.value.exportProperty]
116+
: null
117+
)
105118
</script>
106119

107120
<style scoped>

src/plugins/gfi/components/GfiFeatureList.ce.vue

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,20 @@
1717
:page-size="gfiStore.configuration.featureList.pageLength"
1818
/>
1919
<section
20-
v-for="({ layerId, feature }, idx) of paginatedFlatFeatureList"
20+
v-for="({ layerId, feature, hovered }, idx) of paginatedFlatFeatureList"
2121
:key="idx"
2222
tabindex="0"
23+
:class="{
24+
hovered,
25+
}"
2326
@click="
24-
gfiStore.featureInformation[layerId] = [serializeFeature(feature)]
27+
(() => {
28+
gfiStore.selectedFeatures = { [layerId]: [feature] }
29+
gfiStore.hoveredFeatures = {}
30+
})()
2531
"
32+
@mouseenter="gfiStore.hoveredFeatures = { [layerId]: [feature] }"
33+
@mouseleave="gfiStore.hoveredFeatures = {}"
2634
>
2735
<h2 class="kern-title kern-title--small">
2836
{{ getText(feature, 'title') }}
@@ -44,15 +52,14 @@ import KernPagination from '@/components/kern/KernPagination.ce.vue'
4452
import type { FeatureList } from '../types'
4553
4654
import { useGfiStore } from '../store'
47-
import { serializeFeature } from '../utils/serializeFeature'
4855
4956
const gfiStore = useGfiStore()
5057
5158
const flatFeatureList = computed(() =>
5259
Object.entries(gfiStore.listFeatures).flatMap(([layerId, features]) =>
5360
features.map((feature) => ({
5461
layerId,
55-
feature,
62+
...feature,
5663
}))
5764
)
5865
)
@@ -93,6 +100,7 @@ section {
93100
border-style: dashed;
94101
border-color: transparent;
95102
103+
&.hovered,
96104
&:hover {
97105
border-radius: var(--kern-metric-border-radius-default);
98106
border-color: var(--kern-color-action-default);

src/plugins/gfi/store.ts

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,32 @@ export const useGfiStore = defineStore('plugins/gfi', () => {
3636

3737
const watchHandles = ref<WatchHandle[]>([])
3838

39+
const hoveredFeatures = ref<Record<string, Feature[]>>({})
40+
const selectedFeatures = ref<Record<string, Feature[]>>({})
41+
3942
const featureInformation = ref<Record<string, GeoJsonFeature[]>>({})
4043

44+
watch(
45+
selectedFeatures,
46+
(features) => {
47+
featureInformation.value = Object.fromEntries(
48+
Object.entries(features).map(([layerId, features]) => [
49+
layerId,
50+
features.map((feature) => serializeFeature(feature)),
51+
])
52+
)
53+
},
54+
{ immediate: true, deep: true }
55+
)
56+
4157
const listFeatures = computed(() => {
4258
// We want to re-calculate on extent changes, as the features change then.
4359
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
4460
coreStore.extent
4561

62+
// TODO: We also want to re-calculate when the features are actually loaded.
63+
// Currently, we need an extent change to reload the list.
64+
4665
if (!configuration.value.featureList) {
4766
return {}
4867
}
@@ -85,13 +104,92 @@ export const useGfiStore = defineStore('plugins/gfi', () => {
85104
(feature) =>
86105
!layerConfiguration.isSelectable ||
87106
layerConfiguration.isSelectable(serializeFeature(feature))
88-
),
107+
)
108+
.map((feature) => ({
109+
feature,
110+
...(configuration.value.featureList?.bindWithCoreHoverSelect
111+
? {
112+
hovered:
113+
coreStore.hoveredFeature === feature ||
114+
coreStore.hoveredFeature
115+
?.get('features')
116+
?.includes(feature),
117+
}
118+
: {}),
119+
})),
89120
]
90121
})
91-
.filter((layer): layer is [string, Feature[]] => Boolean(layer))
122+
.filter(
123+
(
124+
layer
125+
): layer is [string, { feature: Feature; hovered?: boolean }[]] =>
126+
Boolean(layer)
127+
)
92128
)
93129
})
94130

131+
watch(
132+
[
133+
() => configuration.value.featureList?.bindWithCoreHoverSelect,
134+
() => coreStore.selectedFeature,
135+
],
136+
([bindMarkers, feature]) => {
137+
if (bindMarkers && feature) {
138+
featureInformation.value[feature.get('_polarLayerId')] = feature.get(
139+
'features'
140+
)
141+
? feature.get('features').map((feature) => serializeFeature(feature))
142+
: [serializeFeature(feature as Feature)]
143+
}
144+
},
145+
{ immediate: true, deep: true }
146+
)
147+
148+
watch(
149+
[
150+
() => configuration.value.featureList?.bindWithCoreHoverSelect,
151+
() => hoveredFeatures.value,
152+
],
153+
([bindMarkers, featureMap]) => {
154+
if (bindMarkers) {
155+
const features = Object.entries(featureMap).flatMap(
156+
([layerId, features]) =>
157+
features.map((feature) => ({ layerId, feature }))
158+
)
159+
160+
// The second condition is necessary for TypeScript checks.
161+
if (features.length <= 0 || !features[0]) {
162+
coreStore.hoveredFeature = null
163+
return
164+
}
165+
166+
features[0].feature.set('_polarLayerId', features[0].layerId)
167+
coreStore.hoveredFeature = features[0].feature
168+
}
169+
},
170+
{ immediate: true, deep: true }
171+
)
172+
173+
watch(
174+
[
175+
() => configuration.value.featureList?.bindWithCoreHoverSelect,
176+
() => selectedFeatures.value,
177+
],
178+
([bindMarkers, featureMap]) => {
179+
if (bindMarkers) {
180+
const features = Object.values(featureMap).flat()
181+
182+
if (features.length <= 0) {
183+
coreStore.selectedFeature = null
184+
return
185+
}
186+
187+
coreStore.selectedFeature = features[0] as Feature
188+
}
189+
},
190+
{ immediate: true, deep: true }
191+
)
192+
95193
async function getFeatureInfo(coordinate: [number, number]) {
96194
let result = Object.fromEntries(
97195
(
@@ -182,6 +280,12 @@ export const useGfiStore = defineStore('plugins/gfi', () => {
182280
/** @alpha */
183281
configuration,
184282

283+
/** @alpha */
284+
hoveredFeatures,
285+
286+
/** @alpha */
287+
selectedFeatures,
288+
185289
/** @alpha */
186290
featureInformation,
187291

0 commit comments

Comments
 (0)