mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 16:03:02 +00:00
feat(roadtrip): share trip preferences and improve service stops
This commit is contained in:
@@ -18,7 +18,7 @@ export default function ClusteredPois({ pois, enabled, onPoiClick, children }: {
|
||||
map.on('zoomend', update)
|
||||
return () => { map.off('zoomend', update) }
|
||||
}, [map])
|
||||
const groups = useMemo(() => enabled ? clusterPois(pois, poi => map.latLngToContainerPoint([poi.lat, poi.lng])) : [], [pois, enabled, map, zoom])
|
||||
const groups = useMemo(() => enabled ? clusterPois(pois, poi => map.latLngToContainerPoint([poi.lat, poi.lng]), zoom) : [], [pois, enabled, map, zoom])
|
||||
const markers = new Map(pois.map((poi, index) => [poi.osm_id, children[index]]))
|
||||
if (!enabled) return <>{children}</>
|
||||
return <>{groups.map(group => {
|
||||
|
||||
@@ -1391,6 +1391,7 @@ describe('MapViewGL', () => {
|
||||
|
||||
it('clusters roadtrip stations and zooms before offering overlapping stations individually', async () => {
|
||||
loadOnAttach()
|
||||
vi.mocked(glMap.getZoom).mockReturnValue(8)
|
||||
const poi: Poi = {
|
||||
osm_id: 'n1', name: 'Station A', lat: 48.854, lng: 2.332, category: 'charging_station',
|
||||
poi_type: 'charging_station', address: null, website: null, phone: null,
|
||||
@@ -1411,6 +1412,7 @@ describe('MapViewGL', () => {
|
||||
const list = calls[calls.length - 1][0]
|
||||
act(() => { list.querySelectorAll('button')[1].click() })
|
||||
expect(onPoiClick).toHaveBeenCalledWith(other)
|
||||
vi.mocked(glMap.getZoom).mockReturnValue(10)
|
||||
})
|
||||
|
||||
it('FE-COMP-MAPVIEWGL-043: plugin markers render as tone dots with a text-only popup', async () => {
|
||||
|
||||
@@ -1840,7 +1840,7 @@ export function MapViewGL({
|
||||
poiMarkersRef.current = []
|
||||
poiCleanupRef.current.forEach(off => off())
|
||||
poiCleanupRef.current = []
|
||||
const groups = clusterLoosely ? clusterPois(pois, poi => map.project([poi.lng, poi.lat])) : pois.map(poi => ({ pois: [poi], lat: poi.lat, lng: poi.lng }))
|
||||
const groups = clusterLoosely ? clusterPois(pois, poi => map.project([poi.lng, poi.lat]), map.getZoom()) : pois.map(poi => ({ pois: [poi], lat: poi.lat, lng: poi.lng }))
|
||||
for (const group of groups) {
|
||||
if (group.pois.length > 1) {
|
||||
const el = document.createElement('button')
|
||||
|
||||
@@ -10,6 +10,12 @@ const station = (id: string, lng: number): Poi => ({
|
||||
const project = (poi: Poi) => ({ x: poi.lng, y: poi.lat })
|
||||
|
||||
describe('station clusters', () => {
|
||||
it('only clusters in the distant overview, even for coincident stations', () => {
|
||||
const pois = [station('a', 1), station('b', 1)]
|
||||
expect(clusterPois(pois, project, 8)).toHaveLength(1)
|
||||
expect(clusterPois(pois, project, 9)).toHaveLength(2)
|
||||
expect(clusterPois(pois, project, 14)).toHaveLength(2)
|
||||
})
|
||||
it('groups across grid edges, counts unique stations and preserves the originals', () => {
|
||||
const a = station('a', 47), b = station('b', 49), c = station('c', 150)
|
||||
const groups = clusterPois([c, b, a, a], project)
|
||||
@@ -41,3 +47,9 @@ describe('station clusters', () => {
|
||||
expect(select).toHaveBeenCalledWith(poi)
|
||||
})
|
||||
})
|
||||
|
||||
it('combines nearby small groups into one overview cluster', () => {
|
||||
const pois = [station('a', 0), station('b', 3), station('c', 20), station('d', 23), station('e', 40), station('f', 43)]
|
||||
expect(clusterPois(pois, project, 8).map(group => group.pois.length)).toEqual([6])
|
||||
expect(clusterPois(pois, project, 9)).toHaveLength(6)
|
||||
})
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { Poi } from './poiCategories'
|
||||
|
||||
export const POI_CLUSTER_RADIUS = 48
|
||||
export const POI_CLUSTER_MAX_ZOOM = 8
|
||||
export const POI_CLUSTER_DETAIL_ZOOM = 18
|
||||
export interface PoiCluster { pois: Poi[]; lat: number; lng: number }
|
||||
|
||||
export function clusterPois(pois: Poi[], project: (poi: Poi) => { x: number; y: number }): PoiCluster[] {
|
||||
export function clusterPois(pois: Poi[], project: (poi: Poi) => { x: number; y: number }, zoom = 0): PoiCluster[] {
|
||||
const groups: (PoiCluster & { x: number; y: number })[] = []
|
||||
const cells = new Map<string, number[]>()
|
||||
const unique = new Map(pois.map(poi => [poi.osm_id, poi]))
|
||||
if (zoom > POI_CLUSTER_MAX_ZOOM) return [...unique.values()].map(poi => ({ pois: [poi], lat: poi.lat, lng: poi.lng }))
|
||||
for (const poi of [...unique.values()].sort((a, b) => a.osm_id.localeCompare(b.osm_id))) {
|
||||
const point = project(poi)
|
||||
const cx = Math.floor(point.x / POI_CLUSTER_RADIUS), cy = Math.floor(point.y / POI_CLUSTER_RADIUS)
|
||||
|
||||
Reference in New Issue
Block a user