feat: add server-side clustering to CatalogPage for hubs
All checks were successful
Build Docker Image / build (push) Successful in 5m8s

This commit is contained in:
Ruslan Bakiev
2026-01-14 11:16:26 +07:00
parent b75459c8be
commit 46f8e97ee9
2 changed files with 23 additions and 3 deletions

View File

@@ -52,10 +52,13 @@
<CatalogMap <CatalogMap
ref="mapRef" ref="mapRef"
:map-id="mapId" :map-id="mapId"
:items="itemsWithCoords" :items="useServerClustering ? [] : itemsWithCoords"
:clustered-points="useServerClustering ? clusteredNodes : []"
:use-server-clustering="useServerClustering"
:point-color="pointColor" :point-color="pointColor"
:hovered-item-id="hoveredId" :hovered-item-id="hoveredId"
@select-item="onMapSelect" @select-item="onMapSelect"
@bounds-change="onBoundsChange"
/> />
</ClientOnly> </ClientOnly>
</div> </div>
@@ -97,10 +100,13 @@
<CatalogMap <CatalogMap
ref="mobileMapRef" ref="mobileMapRef"
:map-id="`${mapId}-mobile`" :map-id="`${mapId}-mobile`"
:items="itemsWithCoords" :items="useServerClustering ? [] : itemsWithCoords"
:clustered-points="useServerClustering ? clusteredNodes : []"
:use-server-clustering="useServerClustering"
:point-color="pointColor" :point-color="pointColor"
:hovered-item-id="hoveredId" :hovered-item-id="hoveredId"
@select-item="onMapSelect" @select-item="onMapSelect"
@bounds-change="onBoundsChange"
/> />
</ClientOnly> </ClientOnly>
</div> </div>
@@ -157,6 +163,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
interface MapItem { interface MapItem {
uuid: string uuid: string
latitude?: number | null latitude?: number | null
@@ -171,6 +179,7 @@ const props = withDefaults(defineProps<{
mapItems?: MapItem[] // Optional separate items for map (if different from list items) mapItems?: MapItem[] // Optional separate items for map (if different from list items)
loading?: boolean loading?: boolean
withMap?: boolean withMap?: boolean
useServerClustering?: boolean // Use server-side h3 clustering for ALL points
mapId?: string mapId?: string
pointColor?: string pointColor?: string
selectedId?: string selectedId?: string
@@ -179,6 +188,7 @@ const props = withDefaults(defineProps<{
}>(), { }>(), {
loading: false, loading: false,
withMap: true, withMap: true,
useServerClustering: false,
mapId: 'catalog-map', mapId: 'catalog-map',
pointColor: '#3b82f6', pointColor: '#3b82f6',
hasSubNav: true hasSubNav: true
@@ -194,10 +204,19 @@ const emit = defineEmits<{
'update:hoveredId': [uuid: string | undefined] 'update:hoveredId': [uuid: string | undefined]
}>() }>()
// Server-side clustering
const { clusteredNodes, fetchClusters } = useClusteredNodes()
const onBoundsChange = (bounds: MapBounds) => {
if (props.useServerClustering) {
fetchClusters(bounds)
}
}
// Use mapItems if provided, otherwise fall back to items // Use mapItems if provided, otherwise fall back to items
const itemsForMap = computed(() => props.mapItems || props.items) const itemsForMap = computed(() => props.mapItems || props.items)
// Filter items with valid coordinates for map // Filter items with valid coordinates for map (client-side mode only)
const itemsWithCoords = computed(() => const itemsWithCoords = computed(() =>
itemsForMap.value.filter(item => itemsForMap.value.filter(item =>
item.latitude != null && item.latitude != null &&

View File

@@ -4,6 +4,7 @@
:loading="isLoading" :loading="isLoading"
map-id="hubs-map" map-id="hubs-map"
point-color="#10b981" point-color="#10b981"
use-server-clustering
:selected-id="selectedHubId" :selected-id="selectedHubId"
v-model:hovered-id="hoveredHubId" v-model:hovered-id="hoveredHubId"
@select="onSelectHub" @select="onSelectHub"