Skip to content

Commit f8ec533

Browse files
authored
Merge pull request #28 from OpenGeoscience/vector-metadata-searching
VectorFeature Search
2 parents 6aaa74f + 7eeafd0 commit f8ec533

23 files changed

+1413
-54
lines changed

client/src/MapStore.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
NetCDFData,
1212
NetCDFLayer,
1313
RasterMapLayer,
14+
SearchableVectorData,
1415
VectorFeatureTableGraph,
1516
VectorMapLayer,
1617
} from './types';
@@ -23,7 +24,7 @@ async function isVectorBaseMapAvailable(vectorMapUrl: string) {
2324
return Number(resp.headers.get('content-length') ?? 0) > 0 && resp.status === 200;
2425
}
2526

26-
type SideBarCard = 'indicators' | 'charts';
27+
type SideBarCard = 'indicators' | 'charts' | 'searchableVectors';
2728

2829
export default class MapStore {
2930
public static osmBaseMap = ref<'none' | 'osm-raster' | 'osm-vector'>('osm-raster');
@@ -127,6 +128,22 @@ export default class MapStore {
127128
MapStore.mapLayerFeatureColorMapping.value = {};
128129
};
129130

131+
// Searchable Vector Features
132+
133+
public static mapLayerVectorSearchable = computed(() => {
134+
const foundMapLayerSearchable: { name: string, id: number; searchSettings: SearchableVectorData }[] = [];
135+
MapStore.selectedVectorMapLayers.value.forEach((item) => {
136+
if (item.default_style.searchableVectorFeatureData) {
137+
foundMapLayerSearchable.push({
138+
name: item.name,
139+
id: item.id,
140+
searchSettings: item.default_style.searchableVectorFeatureData,
141+
});
142+
}
143+
});
144+
return foundMapLayerSearchable;
145+
});
146+
130147
// ToolTips
131148
public static toolTipMenuOpen = ref(false);
132149

@@ -203,9 +220,6 @@ export default class MapStore {
203220
};
204221
};
205222

206-
// Charts
207-
public static chartsOpen = ref(false);
208-
209223
// SideBar Cards
210224
public static activeSideBarCard: Ref<undefined | SideBarCard> = ref(undefined);
211225

@@ -218,6 +232,10 @@ export default class MapStore {
218232
charts: {
219233
name: 'Chart', width: 650, icon: 'mdi-chart-bar', enabled: false, key: 'charts',
220234
},
235+
searchableVectors: {
236+
name: 'Search Vector Features', width: 300, icon: 'mdi-map-search-outline', enabled: false, key: 'searchableVectors',
237+
},
238+
221239
},
222240
);
223241

client/src/api/UVDATApi.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import {
2121
PropertySummary,
2222
RasterData,
2323
RasterMapLayer,
24+
SearchableVectorDataRequest,
25+
SearchableVectorFeatureResponse,
2426
SimulationType,
2527
TableSummary,
2628
VectorMapLayer,
@@ -568,8 +570,9 @@ export default class UVdatApi {
568570
public static async filterOnMetadata(
569571
metdataFilters: Record<string, string[]>,
570572
search?: string,
573+
bbox?: string,
571574
): Promise<{ id: number, type: AbstractMapLayer['type'], matches: string[], name: string }[]> {
572-
return (await UVdatApi.apiClient.post('metadata-filters/filter_layers/', { filters: metdataFilters, search })).data;
575+
return (await UVdatApi.apiClient.post('metadata-filters/filter_layers/', { filters: metdataFilters, search, bbox })).data;
573576
}
574577

575578
public static async getMapLayerList(
@@ -583,4 +586,8 @@ export default class UVdatApi {
583586

584587
return (await UVdatApi.apiClient.get('/map-layers/', { params })).data;
585588
}
589+
590+
public static async searchVectorFeatures(requestData: SearchableVectorDataRequest): Promise<SearchableVectorFeatureResponse[]> {
591+
return (await UVdatApi.apiClient.post('/map-layers/search-features/', requestData)).data;
592+
}
586593
}

client/src/components/Charts/Charts.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ export default defineComponent({
3838
);
3939
const enabledMapPanels: Ref<number[]> = ref([]);
4040
const enabledChartPanels: Ref<Record<number, number[]>> = ref({});
41-
const chartVisible = computed(() => MapStore.chartsOpen.value);
4241
const addingEditingChart = ref(false);
4342
const editingChart: Ref<CustomChart | null> = ref(null);
4443
const editingChartIndex = ref(-1);
@@ -119,7 +118,6 @@ export default defineComponent({
119118
}
120119
};
121120
return {
122-
chartVisible,
123121
proMode: MapStore.proMode,
124122
configuredChartsByMap,
125123
addingEditingChart,

client/src/components/LayerConfig.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export default defineComponent({
113113
</v-col>
114114

115115
<v-col
116-
v-if="proMode"
117116
title="Deselect"
118117
cols="1"
119118
>

client/src/components/Map.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export default defineComponent({
237237
watch(
238238
MapStore.hoveredFeatures,
239239
() => {
240-
if (map.value && MapStore.mapLayerFeatureGraphsVisible.value) {
240+
if (map.value && (MapStore.mapLayerFeatureGraphsVisible.value || MapStore.activeSideBarCard.value === 'searchableVectors')) {
241241
updateSelected(map.value);
242242
}
243243
},

client/src/components/MetadataLayerFilter/MetadataLayerFilter.vue

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<script lang="ts">
22
import {
3-
defineComponent, onMounted, ref, watch,
3+
defineComponent, onMounted, onUnmounted, ref, watch,
44
} from 'vue';
55
import * as d3 from 'd3';
66
import UVdatApi from '../../api/UVDATApi';
77
import MapStore from '../../MapStore';
88
import { AbstractMapLayer } from '../../types';
9-
import { toggleLayerSelection } from '../../map/mapLayers';
9+
import { getStringBBox, internalMap, toggleLayerSelection } from '../../map/mapLayers';
1010
1111
export default defineComponent({
1212
name: 'MetadataLayerFilter',
@@ -17,6 +17,7 @@ export default defineComponent({
1717
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
1818
const search = ref('');
1919
const showFilters = ref(false); // Toggle filter visibility
20+
const filterBBox = ref(false);
2021
2122
onMounted(async () => {
2223
metadataFilters.value = await UVdatApi.getMetadataFilters();
@@ -25,11 +26,48 @@ export default defineComponent({
2526
});
2627
});
2728
29+
const updateFilter = async () => {
30+
let bbox: string | undefined;
31+
if (filterBBox.value) {
32+
bbox = getStringBBox();
33+
}
34+
const result = await UVdatApi.filterOnMetadata(selectedFilters.value, search.value, bbox);
35+
filteredLayers.value = result;
36+
};
37+
38+
let movementTimeout: NodeJS.Timeout | null = null;
39+
const onMapMoveEnd = () => {
40+
if (movementTimeout) clearTimeout(movementTimeout);
41+
movementTimeout = setTimeout(updateFilter, 500);
42+
};
43+
44+
const onMapMove = () => {
45+
if (movementTimeout) {
46+
clearTimeout(movementTimeout);
47+
}
48+
};
49+
50+
watch(filterBBox, () => {
51+
if (filterBBox.value && internalMap.value) {
52+
internalMap.value.on('moveend', onMapMoveEnd);
53+
internalMap.value.on('move', onMapMove);
54+
} else if (internalMap.value) {
55+
internalMap.value.off('moveend', onMapMoveEnd);
56+
internalMap.value.off('move', onMapMove);
57+
}
58+
updateFilter();
59+
});
60+
61+
onUnmounted(() => {
62+
if (internalMap.value) {
63+
internalMap.value.off('moveend', onMapMoveEnd);
64+
internalMap.value.off('move', onMapMove);
65+
}
66+
});
2867
watch(
2968
[selectedFilters, search],
3069
async () => {
31-
const result = await UVdatApi.filterOnMetadata(selectedFilters.value, search.value);
32-
filteredLayers.value = result;
70+
updateFilter();
3371
},
3472
{ deep: true },
3573
);
@@ -71,6 +109,7 @@ export default defineComponent({
71109
toggleFilterLayerSelection,
72110
search,
73111
showFilters,
112+
filterBBox,
74113
};
75114
},
76115
});
@@ -88,9 +127,20 @@ export default defineComponent({
88127
clearable
89128
prepend-inner-icon="mdi-magnify"
90129
/>
91-
<v-icon icon :color="showFilters ? 'primary' : ''" @click="showFilters = !showFilters">
92-
{{ showFilters ? 'mdi-filter' : 'mdi-filter' }}
93-
</v-icon>
130+
<v-tooltip text="Filter by current Map View">
131+
<template #activator="{ props }">
132+
<v-icon :color="filterBBox ? 'primary' : ''" v-bind="props" @click="filterBBox = !filterBBox">
133+
mdi-vector-square
134+
</v-icon>
135+
</template>
136+
</v-tooltip>
137+
<v-tooltip text="View metadata filters">
138+
<template #activator="{ props }">
139+
<v-icon :color="showFilters ? 'primary' : ''" v-bind="props" @click="showFilters = !showFilters">
140+
mdi-filter
141+
</v-icon>
142+
</template>
143+
</v-tooltip>
94144
</v-row>
95145

96146
<!-- Selected Filters as Chips (Shown when filters are hidden) -->

client/src/components/PropertiesConfig.vue

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import AvailableProperties from './Metadata/AvailableProperties.vue';
66
import MetadataSettings from './Metadata/MetadataSettings.vue';
77
import SelectedFeatureChartCard from './Metadata/SelectedFeatureChartCard.vue';
88
import TableSummary from './TabularData/TableSummary.vue';
9+
import VectorFeatureSearch from './VectorFeatureSearch/Editor/VectorFeatureSearchEditor.vue';
910
1011
export default defineComponent({
1112
components: {
1213
AvailableProperties,
1314
MetadataSettings,
1415
SelectedFeatureChartCard,
1516
TableSummary,
17+
VectorFeatureSearch,
1618
},
1719
props: {
1820
layerId: {
@@ -21,7 +23,9 @@ export default defineComponent({
2123
},
2224
},
2325
setup() {
24-
const tab: Ref<'availableProperties' | 'settings' | 'charts' | 'tabularData'> = ref('availableProperties');
26+
const tab: Ref<
27+
'availableProperties' | 'settings' | 'charts' | 'tabularData' | 'SearchableVectorData'
28+
> = ref('availableProperties');
2529
2630
return {
2731
tab,
@@ -88,13 +92,28 @@ export default defineComponent({
8892
</v-icon>
8993
</template>
9094
</v-tooltip>
95+
<v-tooltip text="Searchable Vector Data">
96+
<template #activator="{ props }">
97+
<v-icon
98+
class="icon-center"
99+
:class="{ 'selected-tab': tab === 'SearchableVectorData' }"
100+
v-bind="props"
101+
color="primary"
102+
size="x-small"
103+
@click="tab = 'SearchableVectorData'"
104+
>
105+
mdi-map-search-outline
106+
</v-icon>
107+
</template>
108+
</v-tooltip>
91109

92110
<v-spacer />
93111
</v-row>
94112
<AvailableProperties v-if="tab === 'availableProperties'" :layer-id="layerId" />
95113
<MetadataSettings v-else-if="tab === 'settings'" :layer-id="layerId" />
96114
<SelectedFeatureChartCard v-else-if="tab === 'charts'" :layer-id="layerId" />
97115
<TableSummary v-else-if="tab === 'tabularData'" :layer-id="layerId" />
116+
<VectorFeatureSearch v-else-if="tab === 'SearchableVectorData'" :layer-id="layerId" />
98117
</template>
99118

100119
<style scoped>

0 commit comments

Comments
 (0)