Skip to content

Commit

Permalink
Merge pull request #9 from phanhh-98/map-summary
Browse files Browse the repository at this point in the history
create map summary
  • Loading branch information
caohv authored Aug 10, 2024
2 parents a14d4a7 + 9329625 commit db7aa99
Showing 1 changed file with 129 additions and 14 deletions.
143 changes: 129 additions & 14 deletions apps/console/src/app/(summary)/screen.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
'use client'

import { sumBy } from 'lodash'
import { useEffect, useState } from 'react'
import { Map } from 'react-map-gl'
import { forEach, sumBy } from 'lodash'
import mapboxgl from 'mapbox-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import { useEffect, useRef, useState } from 'react'
import { Card, CardContent, CardHeader, CardTitle } from '@packages/ui/components/index'
import { Hash } from '@packages/ui/icons/index'
import { useTheme } from '@packages/ui/providers/index'
import { Layout } from '@/components'
import { useZonesQuery } from '@/hooks'

const MAPBOX_TOKEN = 'pk.eyJ1IjoiY2FvaGF2YW4iLCJhIjoiY2x5anNkcDBzMGw2bTJqcGF4OTNjbTk1dCJ9.quX_1lfj-fPC8hNzpwUWiA'

type Feature = {
type: string
properties: { id: number }
geometry: { type: string; coordinates: [number, number, number] }
}
export const Summary = () => {
const { theme } = useTheme()
const [detectTheme, setDetectTheme] = useState<string>('light')
Expand All @@ -30,6 +35,125 @@ export const Summary = () => {
setDetectTheme(theme || 'light')
}
}, [theme])
const mapContainerRef = useRef<any>(null)
const mapRef = useRef<any>(null)
useEffect(() => {
if (!zones) return
mapboxgl.accessToken = MAPBOX_TOKEN
mapRef.current = new mapboxgl.Map({
container: mapContainerRef.current,
style: `mapbox://styles/mapbox/${detectTheme}-v10`,
center: [105.8342, 21.0278],
zoom: 6,
})

let arrayFeature: Feature[] = []
forEach(zones?.data, (item) => {
const data: Feature = {
type: 'Feature',
properties: { id: item.zone_id, ...zones },
geometry: { type: 'Point', coordinates: [item.lon, item.lat, 0.0] },
}
arrayFeature = [...(arrayFeature || []), data]
})
const temp = {
type: 'FeatureCollection',
crs: { type: 'name' },
features: arrayFeature,
}
mapRef.current.on('load', () => {
mapRef.current.addSource('zones', {
type: 'geojson',
data: temp,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50,
})
// cricle big
mapRef.current.addLayer({
id: 'clusters',
type: 'circle',
source: 'zones',
filter: ['has', 'point_count'],
paint: {
'circle-color': ['step', ['get', 'point_count'], '#51bbd6', 100, '#f1f075', 750, '#f28cb1'],
'circle-radius': ['step', ['get', 'point_count'], 20, 100, 30, 750, 40],
},
})
// number
mapRef.current.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'zones',
filter: ['has', 'point_count'],
layout: {
'text-field': ['get', 'point_count_abbreviated'],
'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
'text-size': 12,
},
})
// cricle small
mapRef.current.addLayer({
id: 'unclustered-point',
type: 'circle',
source: 'zones',
filter: ['!', ['has', 'point_count']],
paint: {
'circle-color': '#11b4da',
'circle-radius': 4,
'circle-stroke-width': 1,
'circle-stroke-color': '#fff',
},
})
// inspect a cluster on click
mapRef.current.on('click', 'clusters', (e: any) => {
const features = mapRef.current.queryRenderedFeatures(e.point, {
layers: ['clusters'],
})
const clusterId = features[0].properties.cluster_id
mapRef.current.getSource('zones').getClusterExpansionZoom(clusterId, (err: any, zoom: any) => {
if (err) return

mapRef.current.easeTo({
center: features[0].geometry.coordinates,
zoom: zoom,
})
})
})

// When a click event occurs on a feature in
// the unclustered-point layer, open a popup at
// the location of the feature, with
// description HTML from its properties.
mapRef.current.on('click', 'unclustered-point', (e: any) => {
const coordinates = e.features[0].geometry.coordinates.slice()
const consoles = sumBy(e.features[0].properties.zones?.data, 'consoles')
const gateways = sumBy(zones?.data, 'gateways')
const medias = sumBy(zones?.data, 'medias')
const connectors = sumBy(zones?.data, 'connectors')
// Ensure that if the map is zoomed out such that
// multiple copies of the feature are visible, the
// popup appears over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360
}

new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(`<span style=\"color:#000;\">Consoles: ${consoles}</span><br><span style=\"color:#000;\">Gateways: ${gateways}</span><br><span style=\"color:#000;\">Medias: ${medias}</span><br><span style=\"color:#000;\">Connectors: ${connectors}</span>`)
.addTo(mapRef.current)
})

mapRef.current.on('mouseenter', 'clusters', () => {
mapRef.current.getCanvas().style.cursor = 'pointer'
})
mapRef.current.on('mouseleave', 'clusters', () => {
mapRef.current.getCanvas().style.cursor = ''
})
})

return () => mapRef.current.remove()
}, [detectTheme, zones])

return (
<Layout
Expand Down Expand Up @@ -93,16 +217,7 @@ export const Summary = () => {
</Card>
</div>
<div className="rounded-lg overflow-hidden">
<Map
mapStyle={`mapbox://styles/mapbox/${detectTheme}-v10`}
mapboxAccessToken={MAPBOX_TOKEN}
style={{
height: 500,
}}
initialViewState={{
zoom: 2,
}}
/>
<div id="map" ref={mapContainerRef} style={{ height: '70vh', width: '100%' }} className="absolute top-0" />
</div>
</div>
</Layout>
Expand Down

0 comments on commit db7aa99

Please sign in to comment.