Skip to content

Commit

Permalink
feat: show superposed POIs #226
Browse files Browse the repository at this point in the history
  • Loading branch information
wazolab committed Jun 26, 2024
1 parent c783b6e commit da9f97f
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 48 deletions.
13 changes: 8 additions & 5 deletions components/Map/MapBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ export default defineNuxtComponent({
.filter(feature => !!feature)
.map((feature, index) => {
feature.id = index
return feature
})
},
Expand Down Expand Up @@ -352,11 +353,7 @@ export default defineNuxtComponent({
| 'mapZoomEnd',
event: any,
) {
if (
this.map
&& this.map.getSource(POI_SOURCE)
&& this.map.isSourceLoaded(POI_SOURCE)
) {
if (this.map && this.map.getSource(POI_SOURCE) && this.map.isSourceLoaded(POI_SOURCE)) {
this.markers = updateMarkers(
this.map as maplibregl.Map,
this.markers,
Expand Down Expand Up @@ -419,6 +416,12 @@ export default defineNuxtComponent({
cursor: pointer;
}
:deep(.cluster-declusterized) {
border: 1px solid red;
display: flex;
gap: 4px;
}
:deep(.cluster-donut) {
@apply tw-text-sm tw-leading-none tw-font-medium tw-block tw-text-zinc-800;
}
Expand Down
23 changes: 23 additions & 0 deletions lib/clusters.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { createApp, h } from 'vue'

Check failure on line 1 in lib/clusters.ts

View workflow job for this annotation

GitHub Actions / Lint code base (ubuntu-latest, 20)

'h' is defined but never used
import TeritorioIconBadge from '~/components/UI/TeritorioIconBadge.vue'

function getMarkerDonutSegment(start: number, end: number, r: number, r0: number, colorFill: string): string {
if (end - start === 1)
end -= 0.00001
Expand Down Expand Up @@ -39,6 +42,26 @@ function getMarkerDonutSegment(start: number, end: number, r: number, r0: number
].join(' ')
}

export function createDeclusterizedCluster(features: GeoJSON.Feature[]): HTMLElement {
const clusterWrapper = document.createElement('div')
features.forEach((feature) => {
const el = document.createElement('div')
el.id = `m${feature.id}`

createApp(TeritorioIconBadge, {
colorFill: feature.properties?.display.color_fill,
picto: feature.properties?.display.icon,
image: feature.properties!['image:thumbnail'],
size: null,
text: feature.properties?.display.text,
}).mount(el)

clusterWrapper.append(el)
})
clusterWrapper.classList.add('cluster-item', 'cluster-declusterized')
return clusterWrapper
}

export function createMarkerDonutChart(countPerColor: Record<string, number>, totalCount: number): HTMLElement {
const r
= totalCount >= 1000
Expand Down
97 changes: 54 additions & 43 deletions lib/markerLayerFactory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {
FitBoundsOptions,
GeoJSONSource,
LayerSpecification,
LngLatBounds,
Map,
Expand All @@ -10,8 +11,7 @@ import { createApp } from 'vue'

import type { ApiPoi } from './apiPois'
import { getBBoxFeatures } from './bbox'
import { createMarkerDonutChart } from './clusters'

import { createDeclusterizedCluster, createMarkerDonutChart } from './clusters'
import TeritorioIconBadge from '~/components/UI/TeritorioIconBadge.vue'
import type { TupleLatLng } from '~/utils/types'

Expand Down Expand Up @@ -123,46 +123,58 @@ export function updateMarkers(
number,
number,
]

const props = feature.properties
if (props?.cluster) {
const id = `c${props.cluster_id}`
markerIdcurrent.push(id)
if (!markers[id]) {
const {
cluster: _a,
cluster_id: _b,
point_count,
_c: _d,
point_count_abbreviated: _e,
...countPercolor
} = props
const el = createMarkerDonutChart(countPercolor, point_count)
el.classList.add('cluster-item')
markers[id] = new Marker({
element: el,
}).setLngLat(coords)
el.addEventListener('click', (e) => {
e.stopPropagation()
const source = map.getSource(src)

if (source && 'getClusterLeaves' in source) {
// @ts-expect-error: getClusterLeaves is for GeoJSONSource but source is Source type
source.getClusterLeaves(
props.cluster_id,
100,
0,
(error: any, features: GeoJSON.Feature[]) => {
if (!error && map) {
const bounds = getBBoxFeatures(features)
if (bounds)
fitBounds(bounds, {})
}
},
)
const source = map.getSource(src) as GeoJSONSource

if (props.cluster) {
source.getClusterLeaves(props.cluster_id, 100, 0, (error, features) => {
if (error) {
console.error('ERROR:', error)
}

const id = `c${props.cluster_id}`
markerIdcurrent.push(id)

if (!markers[id] && features && features.length <= 5) {
const el = createDeclusterizedCluster(features)
const cluster = new Marker({
element: el,
}).setLngLat(coords)
cluster.addTo(map)
}
else {
if (!markers[id]) {
const {
cluster: _a,
cluster_id: _b,
point_count,
_c: _d,
point_count_abbreviated: _e,
...countPercolor
} = props
const el = createMarkerDonutChart(countPercolor, point_count)
el.classList.add('cluster-item')
markers[id] = new Marker({
element: el,
}).setLngLat(coords)
el.addEventListener('click', (e) => {
e.stopPropagation()

if (source && 'getClusterLeaves' in source) {
source.getClusterLeaves(props.cluster_id, 100, 0, (error, features) => {
if (!error && map) {
const bounds = getBBoxFeatures(features as GeoJSON.Feature[])
if (bounds)
fitBounds(bounds, {})
}
})
}
})
markers[id].addTo(map)
}
})
markers[id].addTo(map)
}
}
})
}
else if (props?.metadata) {
if (typeof props.metadata === 'string')
Expand All @@ -176,9 +188,8 @@ export function updateMarkers(
if (markers[id])
markers[id].remove()

const markerCoords
= feature.geometry.type === 'Point'
&& (feature.geometry.coordinates as TupleLatLng)
const markerCoords = feature.geometry.type === 'Point' && (feature.geometry.coordinates as TupleLatLng)

if (markerCoords) {
if (typeof props.display === 'string')
props.display = JSON.parse(props.display)
Expand Down

0 comments on commit da9f97f

Please sign in to comment.