Skip to content

Commit 8c164a4

Browse files
chore: wip
1 parent a982f76 commit 8c164a4

File tree

4 files changed

+317
-0
lines changed

4 files changed

+317
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import type { MapOptions } from 'ts-maps'
2+
import { useEffect, useRef, useMemo } from 'react'
3+
import { VectorMap as TSVectorMap } from 'ts-maps'
4+
import canadaMap from 'ts-maps/maps/canada'
5+
import './map-components.css'
6+
7+
export interface CanadaProps extends Omit<React.HTMLProps<HTMLDivElement>, 'ref'> {
8+
options: Omit<MapOptions, 'selector'>
9+
height?: string
10+
mapKey?: string | number // Optional key for forcing re-renders
11+
onRegionClick?: (event: MouseEvent, code: string) => void
12+
onMarkerClick?: (event: MouseEvent, index: string) => void
13+
onLoaded?: () => void
14+
onViewportChange?: (x: number, y: number, z: number) => void
15+
onRegionSelected?: (event: MouseEvent, code: string, isSelected: boolean, selectedRegions: string[]) => void
16+
onMarkerSelected?: (event: MouseEvent, index: string, isSelected: boolean, selectedMarkers: string[]) => void
17+
onRegionTooltipShow?: (event: Event, tooltip: any, code: string) => void
18+
onMarkerTooltipShow?: (event: Event, tooltip: any, index: string) => void
19+
}
20+
21+
export function Canada({
22+
options,
23+
height = '500px',
24+
mapKey,
25+
onRegionClick,
26+
onMarkerClick,
27+
onLoaded,
28+
onViewportChange,
29+
onRegionSelected,
30+
onMarkerSelected,
31+
onRegionTooltipShow,
32+
onMarkerTooltipShow,
33+
style,
34+
...props
35+
}: CanadaProps) {
36+
const containerRef = useRef<HTMLDivElement>(null)
37+
const mapRef = useRef<TSVectorMap | null>(null)
38+
39+
// Generate a key based on options to force re-render when options change significantly
40+
const computedMapKey = useMemo(() => {
41+
if (mapKey !== undefined)
42+
return mapKey
43+
44+
const optionsHash = JSON.stringify({
45+
backgroundColor: options.backgroundColor,
46+
zoomOnScroll: options.zoomOnScroll,
47+
regionsSelectable: options.regionsSelectable,
48+
markersSelectable: options.markersSelectable,
49+
visualizeData: options.visualizeData,
50+
markers: options.markers?.length,
51+
})
52+
53+
return `canada-map-${optionsHash.length}-${Date.now()}`
54+
}, [mapKey, options])
55+
56+
useEffect(() => {
57+
if (!containerRef.current)
58+
return
59+
60+
// Add Canada map
61+
TSVectorMap.addMap('canada', canadaMap)
62+
63+
const map = new TSVectorMap({
64+
selector: `#${containerRef.current.id}`,
65+
map: {
66+
name: 'canada',
67+
...options.map,
68+
},
69+
...options,
70+
})
71+
72+
// Set up event listeners
73+
if (onRegionClick) {
74+
map.on('regionClick', onRegionClick)
75+
}
76+
if (onMarkerClick) {
77+
map.on('markerClick', onMarkerClick)
78+
}
79+
if (onLoaded) {
80+
map.on('loaded', onLoaded)
81+
}
82+
if (onViewportChange) {
83+
map.on('viewportChange', onViewportChange)
84+
}
85+
if (onRegionSelected) {
86+
map.on('regionSelected', onRegionSelected)
87+
}
88+
if (onMarkerSelected) {
89+
map.on('markerSelected', onMarkerSelected)
90+
}
91+
if (onRegionTooltipShow) {
92+
map.on('regionTooltipShow', onRegionTooltipShow)
93+
}
94+
if (onMarkerTooltipShow) {
95+
map.on('markerTooltipShow', onMarkerTooltipShow)
96+
}
97+
98+
mapRef.current = map
99+
100+
return () => {
101+
if (mapRef.current) {
102+
// Clean up event listeners
103+
if (onRegionClick) {
104+
mapRef.current.off('regionClick', onRegionClick)
105+
}
106+
if (onMarkerClick) {
107+
mapRef.current.off('markerClick', onMarkerClick)
108+
}
109+
if (onLoaded) {
110+
mapRef.current.off('loaded', onLoaded)
111+
}
112+
if (onViewportChange) {
113+
mapRef.current.off('viewportChange', onViewportChange)
114+
}
115+
if (onRegionSelected) {
116+
mapRef.current.off('regionSelected', onRegionSelected)
117+
}
118+
if (onMarkerSelected) {
119+
mapRef.current.off('markerSelected', onMarkerSelected)
120+
}
121+
if (onRegionTooltipShow) {
122+
mapRef.current.off('regionTooltipShow', onRegionTooltipShow)
123+
}
124+
if (onMarkerTooltipShow) {
125+
mapRef.current.off('markerTooltipShow', onMarkerTooltipShow)
126+
}
127+
128+
mapRef.current = null
129+
}
130+
}
131+
}, [computedMapKey, options, onRegionClick, onMarkerClick, onLoaded, onViewportChange, onRegionSelected, onMarkerSelected, onRegionTooltipShow, onMarkerTooltipShow])
132+
133+
const containerStyle: React.CSSProperties = {
134+
height,
135+
...style,
136+
}
137+
138+
return (
139+
<div
140+
{...props}
141+
ref={containerRef}
142+
id={`canada-map-${Math.random().toString(36).slice(2, 11)}`}
143+
style={containerStyle}
144+
>
145+
<div className="canada-map-loading">
146+
Loading Canada map...
147+
</div>
148+
</div>
149+
)
150+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import type { MapOptions } from 'ts-maps'
2+
import { useEffect, useRef, useMemo } from 'react'
3+
import { VectorMap as TSVectorMap } from 'ts-maps'
4+
import usMap from 'ts-maps/maps/us-aea-en'
5+
import './map-components.css'
6+
7+
export interface UnitedStatesProps extends Omit<React.HTMLProps<HTMLDivElement>, 'ref'> {
8+
options: Omit<MapOptions, 'selector'>
9+
height?: string
10+
mapKey?: string | number // Optional key for forcing re-renders
11+
onRegionClick?: (event: MouseEvent, code: string) => void
12+
onMarkerClick?: (event: MouseEvent, index: string) => void
13+
onLoaded?: () => void
14+
onViewportChange?: (x: number, y: number, z: number) => void
15+
onRegionSelected?: (event: MouseEvent, code: string, isSelected: boolean, selectedRegions: string[]) => void
16+
onMarkerSelected?: (event: MouseEvent, index: string, isSelected: boolean, selectedMarkers: string[]) => void
17+
onRegionTooltipShow?: (event: Event, tooltip: any, code: string) => void
18+
onMarkerTooltipShow?: (event: Event, tooltip: any, index: string) => void
19+
}
20+
21+
export function UnitedStates({
22+
options,
23+
height = '500px',
24+
mapKey,
25+
onRegionClick,
26+
onMarkerClick,
27+
onLoaded,
28+
onViewportChange,
29+
onRegionSelected,
30+
onMarkerSelected,
31+
onRegionTooltipShow,
32+
onMarkerTooltipShow,
33+
style,
34+
...props
35+
}: UnitedStatesProps) {
36+
const containerRef = useRef<HTMLDivElement>(null)
37+
const mapRef = useRef<TSVectorMap | null>(null)
38+
39+
// Generate a key based on options to force re-render when options change significantly
40+
const computedMapKey = useMemo(() => {
41+
if (mapKey !== undefined)
42+
return mapKey
43+
44+
const optionsHash = JSON.stringify({
45+
backgroundColor: options.backgroundColor,
46+
zoomOnScroll: options.zoomOnScroll,
47+
regionsSelectable: options.regionsSelectable,
48+
markersSelectable: options.markersSelectable,
49+
visualizeData: options.visualizeData,
50+
markers: options.markers?.length,
51+
})
52+
53+
return `us-map-${optionsHash.length}-${Date.now()}`
54+
}, [mapKey, options])
55+
56+
useEffect(() => {
57+
if (!containerRef.current)
58+
return
59+
60+
// Add US map
61+
TSVectorMap.addMap('us-aea', usMap)
62+
63+
const map = new TSVectorMap({
64+
selector: `#${containerRef.current.id}`,
65+
map: {
66+
name: 'us-aea',
67+
...options.map,
68+
},
69+
...options,
70+
})
71+
72+
// Set up event listeners
73+
if (onRegionClick) {
74+
map.on('regionClick', onRegionClick)
75+
}
76+
if (onMarkerClick) {
77+
map.on('markerClick', onMarkerClick)
78+
}
79+
if (onLoaded) {
80+
map.on('loaded', onLoaded)
81+
}
82+
if (onViewportChange) {
83+
map.on('viewportChange', onViewportChange)
84+
}
85+
if (onRegionSelected) {
86+
map.on('regionSelected', onRegionSelected)
87+
}
88+
if (onMarkerSelected) {
89+
map.on('markerSelected', onMarkerSelected)
90+
}
91+
if (onRegionTooltipShow) {
92+
map.on('regionTooltipShow', onRegionTooltipShow)
93+
}
94+
if (onMarkerTooltipShow) {
95+
map.on('markerTooltipShow', onMarkerTooltipShow)
96+
}
97+
98+
mapRef.current = map
99+
100+
return () => {
101+
if (mapRef.current) {
102+
// Clean up event listeners
103+
if (onRegionClick) {
104+
mapRef.current.off('regionClick', onRegionClick)
105+
}
106+
if (onMarkerClick) {
107+
mapRef.current.off('markerClick', onMarkerClick)
108+
}
109+
if (onLoaded) {
110+
mapRef.current.off('loaded', onLoaded)
111+
}
112+
if (onViewportChange) {
113+
mapRef.current.off('viewportChange', onViewportChange)
114+
}
115+
if (onRegionSelected) {
116+
mapRef.current.off('regionSelected', onRegionSelected)
117+
}
118+
if (onMarkerSelected) {
119+
mapRef.current.off('markerSelected', onMarkerSelected)
120+
}
121+
if (onRegionTooltipShow) {
122+
mapRef.current.off('regionTooltipShow', onRegionTooltipShow)
123+
}
124+
if (onMarkerTooltipShow) {
125+
mapRef.current.off('markerTooltipShow', onMarkerTooltipShow)
126+
}
127+
128+
mapRef.current = null
129+
}
130+
}
131+
}, [computedMapKey, options, onRegionClick, onMarkerClick, onLoaded, onViewportChange, onRegionSelected, onMarkerSelected, onRegionTooltipShow, onMarkerTooltipShow])
132+
133+
const containerStyle: React.CSSProperties = {
134+
height,
135+
...style,
136+
}
137+
138+
return (
139+
<div
140+
{...props}
141+
ref={containerRef}
142+
id={`us-map-${Math.random().toString(36).slice(2, 11)}`}
143+
style={containerStyle}
144+
>
145+
<div className="us-map-loading">
146+
Loading United States map...
147+
</div>
148+
</div>
149+
)
150+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.us-map-loading,
2+
.canada-map-loading {
3+
display: flex;
4+
align-items: center;
5+
justify-content: center;
6+
height: 100%;
7+
background: rgba(255, 255, 255, 0.9);
8+
font-size: 1.2em;
9+
color: #666;
10+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
11+
}

packages/react/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
export { VectorMap } from './components/VectorMap'
22
export type { VectorMapProps } from './components/VectorMap'
3+
4+
export { UnitedStates } from './components/UnitedStates'
5+
export type { UnitedStatesProps } from './components/UnitedStates'
6+
7+
export { Canada } from './components/Canada'
8+
export type { CanadaProps } from './components/Canada'

0 commit comments

Comments
 (0)