Skip to content

Commit 1992755

Browse files
chore: wip
1 parent 15d9c68 commit 1992755

File tree

25 files changed

+1074
-337
lines changed

25 files changed

+1074
-337
lines changed

docs/.vitepress/components.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,27 @@ declare module 'vue' {
1010
export interface GlobalComponents {
1111
AnalyticsDemo: typeof import('./theme/components/AnalyticsDemo.vue')['default']
1212
Canada: typeof import('./theme/components/maps/Canada.vue')['default']
13+
CanadaDemo: typeof import('./theme/components/maps/CanadaDemo.vue')['default']
1314
DataVisualizationDemo: typeof import('./theme/components/DataVisualizationDemo.vue')['default']
1415
HeatmapDemo: typeof import('./theme/components/HeatmapDemo.vue')['default']
1516
Home: typeof import('./theme/components/Home.vue')['default']
1617
HomeContributors: typeof import('./theme/components/HomeContributors.vue')['default']
1718
HomeSponsors: typeof import('./theme/components/HomeSponsors.vue')['default']
1819
HomeTeam: typeof import('./theme/components/HomeTeam.vue')['default']
20+
Iraq: typeof import('./theme/components/maps/Iraq.vue')['default']
21+
IraqDemo: typeof import('./theme/components/maps/IraqDemo.vue')['default']
22+
Italy: typeof import('./theme/components/maps/Italy.vue')['default']
23+
ItalyDemlo: typeof import('./theme/components/maps/ItalyDemlo.vue')['default']
24+
ItalyDemo: typeof import('./theme/components/maps/ItalyDemo.vue')['default']
1925
MarkersMapDemo: typeof import('./theme/components/MarkersMapDemo.vue')['default']
2026
RegionMapDemo: typeof import('./theme/components/RegionMapDemo.vue')['default']
2127
RouterLink: typeof import('vue-router')['RouterLink']
2228
RouterView: typeof import('vue-router')['RouterView']
2329
TeamMember: typeof import('./theme/components/TeamMember.vue')['default']
2430
UnitedStates: typeof import('./theme/components/maps/UnitedStates.vue')['default']
31+
UnitedStatesDemo: typeof import('./theme/components/maps/UnitedStatesDemo.vue')['default']
2532
VectorMapDemo: typeof import('./theme/components/VectorMapDemo.vue')['default']
2633
WorldMap: typeof import('./theme/components/maps/WorldMap.vue')['default']
34+
WorldMapDemo: typeof import('./theme/components/maps/WorldMapDemo.vue')['default']
2735
}
2836
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

docs/.vitepress/theme/components/maps/UnitedStatesDemo.vue

Whitespace-only changes.

docs/.vitepress/theme/components/maps/WorldMapDemo.vue

Whitespace-only changes.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<script setup lang="ts">
2+
import type { MapOptions } from 'ts-maps'
3+
import { computed, watch } from 'vue'
4+
import VectorMap from '../VectorMap.vue'
5+
6+
// Props interface
7+
interface Props {
8+
options: Omit<MapOptions, 'selector'>
9+
height?: string
10+
mapKey?: string | number // Optional key for forcing re-renders
11+
}
12+
13+
// Events interface
14+
interface Emits {
15+
(e: 'regionClick', event: MouseEvent, code: string): void
16+
(e: 'markerClick', event: MouseEvent, index: string): void
17+
(e: 'loaded'): void
18+
(e: 'viewportChange', x: number, y: number, z: number): void
19+
(e: 'regionSelected', event: MouseEvent, code: string, isSelected: boolean, selectedRegions: string[]): void
20+
(e: 'markerSelected', event: MouseEvent, index: string, isSelected: boolean, selectedMarkers: string[]): void
21+
(e: 'regionTooltipShow', event: Event, tooltip: any, code: string): void
22+
(e: 'markerTooltipShow', event: Event, tooltip: any, index: string): void
23+
}
24+
25+
// Props with defaults
26+
const props = withDefaults(defineProps<Props>(), {
27+
height: '500px',
28+
mapKey: undefined,
29+
})
30+
31+
// Emit events
32+
const emit = defineEmits<Emits>()
33+
34+
// Computed map key - use provided key or generate one based on options
35+
const mapKey = computed(() => {
36+
if (props.mapKey !== undefined)
37+
return props.mapKey
38+
39+
// Generate a key based on options to force re-render when options change significantly
40+
const optionsHash = JSON.stringify({
41+
backgroundColor: props.options.backgroundColor,
42+
zoomOnScroll: props.options.zoomOnScroll,
43+
regionsSelectable: props.options.regionsSelectable,
44+
markersSelectable: props.options.markersSelectable,
45+
visualizeData: props.options.visualizeData,
46+
markers: props.options.markers?.length,
47+
})
48+
49+
return `world-map-${optionsHash.length}-${Date.now()}`
50+
})
51+
52+
// Create options without projection to avoid overriding map-name
53+
const mapOptions = computed(() => {
54+
const { projection, ...rest } = props.options
55+
return rest
56+
})
57+
58+
// Watch for options changes to update the map if needed
59+
watch(() => props.options, () => {
60+
// The mapKey computed will automatically update, forcing a re-render
61+
}, { deep: true })
62+
</script>
63+
64+
<template>
65+
<VectorMap
66+
:key="mapKey"
67+
:options="mapOptions"
68+
map-name="world"
69+
:height="height"
70+
@region-click="(event: MouseEvent, code: string) => emit('regionClick', event, code)"
71+
@marker-click="(event: MouseEvent, index: string) => emit('markerClick', event, index)"
72+
@loaded="() => emit('loaded')"
73+
@viewport-change="(x: number, y: number, z: number) => emit('viewportChange', x, y, z)"
74+
@region-selected="(event: MouseEvent, code: string, isSelected: boolean, selectedRegions: string[]) => emit('regionSelected', event, code, isSelected, selectedRegions)"
75+
@marker-selected="(event: MouseEvent, index: string, isSelected: boolean, selectedMarkers: string[]) => emit('markerSelected', event, index, isSelected, selectedMarkers)"
76+
@region-tooltip-show="(event: Event, tooltip: any, code: string) => emit('regionTooltipShow', event, tooltip, code)"
77+
@marker-tooltip-show="(event: Event, tooltip: any, index: string) => emit('markerTooltipShow', event, tooltip, index)"
78+
>
79+
<template #loading>
80+
<slot name="loading">
81+
<div class="world-map-loading">
82+
Loading World map...
83+
</div>
84+
</slot>
85+
</template>
86+
</VectorMap>
87+
</template>
88+
89+
<style scoped>
90+
.world-map-loading {
91+
display: flex;
92+
align-items: center;
93+
justify-content: center;
94+
height: 100%;
95+
background: rgba(255, 255, 255, 0.9);
96+
font-size: 1.2em;
97+
color: #666;
98+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
99+
}
100+
</style>

packages/react/src/components/WorldMap.tsx

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { MapOptions } from 'ts-maps'
22
import { useEffect, useMemo, useRef } from 'react'
33
import { VectorMap as TSVectorMap } from 'ts-maps'
4-
import worldMap from 'ts-maps/maps/world'
4+
import worldMap from 'ts-maps/world'
55
import './map-components.css'
66

77
export interface WorldMapProps extends Omit<React.HTMLProps<HTMLDivElement>, 'ref'> {
@@ -69,62 +69,13 @@ export function WorldMap({
6969
...options,
7070
})
7171

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-
}
72+
// Note: Event handling is managed by ts-maps internally
73+
// The library handles events based on the options passed
9774

9875
mapRef.current = map
9976

10077
return () => {
10178
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-
12879
mapRef.current = null
12980
}
13081
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<script setup lang="ts">
2+
import type { MapOptions } from 'ts-maps'
3+
import { computed, watch } from 'vue'
4+
import VectorMap from '../VectorMap.vue'
5+
6+
// Props interface
7+
interface Props {
8+
options: Omit<MapOptions, 'selector'>
9+
height?: string
10+
mapKey?: string | number // Optional key for forcing re-renders
11+
}
12+
13+
// Events interface
14+
interface Emits {
15+
(e: 'regionClick', event: MouseEvent, code: string): void
16+
(e: 'markerClick', event: MouseEvent, index: string): void
17+
(e: 'loaded'): void
18+
(e: 'viewportChange', x: number, y: number, z: number): void
19+
(e: 'regionSelected', event: MouseEvent, code: string, isSelected: boolean, selectedRegions: string[]): void
20+
(e: 'markerSelected', event: MouseEvent, index: string, isSelected: boolean, selectedMarkers: string[]): void
21+
(e: 'regionTooltipShow', event: Event, tooltip: any, code: string): void
22+
(e: 'markerTooltipShow', event: Event, tooltip: any, index: string): void
23+
}
24+
25+
// Props with defaults
26+
const props = withDefaults(defineProps<Props>(), {
27+
height: '500px',
28+
mapKey: undefined,
29+
})
30+
31+
// Emit events
32+
const emit = defineEmits<Emits>()
33+
34+
// Computed map key - use provided key or generate one based on options
35+
const mapKey = computed(() => {
36+
if (props.mapKey !== undefined)
37+
return props.mapKey
38+
39+
// Generate a key based on options to force re-render when options change significantly
40+
const optionsHash = JSON.stringify({
41+
backgroundColor: props.options.backgroundColor,
42+
zoomOnScroll: props.options.zoomOnScroll,
43+
regionsSelectable: props.options.regionsSelectable,
44+
markersSelectable: props.options.markersSelectable,
45+
visualizeData: props.options.visualizeData,
46+
markers: props.options.markers?.length,
47+
})
48+
49+
return `world-map-${optionsHash.length}-${Date.now()}`
50+
})
51+
52+
// Create options without projection to avoid overriding map-name
53+
const mapOptions = computed(() => {
54+
const { projection, ...rest } = props.options
55+
return rest
56+
})
57+
58+
// Watch for options changes to update the map if needed
59+
watch(() => props.options, () => {
60+
// The mapKey computed will automatically update, forcing a re-render
61+
}, { deep: true })
62+
</script>
63+
64+
<template>
65+
<VectorMap
66+
:key="mapKey"
67+
:options="mapOptions"
68+
map-name="world"
69+
:height="height"
70+
@region-click="(event: MouseEvent, code: string) => emit('regionClick', event, code)"
71+
@marker-click="(event: MouseEvent, index: string) => emit('markerClick', event, index)"
72+
@loaded="() => emit('loaded')"
73+
@viewport-change="(x: number, y: number, z: number) => emit('viewportChange', x, y, z)"
74+
@region-selected="(event: MouseEvent, code: string, isSelected: boolean, selectedRegions: string[]) => emit('regionSelected', event, code, isSelected, selectedRegions)"
75+
@marker-selected="(event: MouseEvent, index: string, isSelected: boolean, selectedMarkers: string[]) => emit('markerSelected', event, index, isSelected, selectedMarkers)"
76+
@region-tooltip-show="(event: Event, tooltip: any, code: string) => emit('regionTooltipShow', event, tooltip, code)"
77+
@marker-tooltip-show="(event: Event, tooltip: any, index: string) => emit('markerTooltipShow', event, tooltip, index)"
78+
>
79+
<template #loading>
80+
<slot name="loading">
81+
<div class="world-map-loading">
82+
Loading World map...
83+
</div>
84+
</slot>
85+
</template>
86+
</VectorMap>
87+
</template>
88+
89+
<style scoped>
90+
.world-map-loading {
91+
display: flex;
92+
align-items: center;
93+
justify-content: center;
94+
height: 100%;
95+
background: rgba(255, 255, 255, 0.9);
96+
font-size: 1.2em;
97+
color: #666;
98+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
99+
}
100+
</style>

playground/vue-samples/bun.lock

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"@types/google.maps": "^3.58.1",
88
"ts-maps-vue": "../../packages/vue",
99
"vue": "^3.5.18",
10+
"vue-router": "4",
1011
},
1112
"devDependencies": {
1213
"@vitejs/plugin-vue": "^6.0.1",
@@ -699,7 +700,7 @@
699700

700701
"@vue/compiler-vue2": ["@vue/[email protected]", "", { "dependencies": { "de-indent": "^1.0.2", "he": "^1.2.0" } }, "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A=="],
701702

702-
"@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="],
703+
"@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
703704

704705
"@vue/devtools-kit": ["@vue/[email protected]", "", { "dependencies": { "@vue/devtools-shared": "^7.7.7", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA=="],
705706

@@ -1787,6 +1788,8 @@
17871788

17881789
"vue-resize": ["[email protected]", "", { "peerDependencies": { "vue": "^3.0.0" } }, "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg=="],
17891790

1791+
"vue-router": ["[email protected]", "", { "dependencies": { "@vue/devtools-api": "^6.6.4" }, "peerDependencies": { "vue": "^3.2.0" } }, "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw=="],
1792+
17901793
"vue-tsc": ["[email protected]", "", { "dependencies": { "@volar/typescript": "2.4.23", "@vue/language-core": "3.0.6" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-Tbs8Whd43R2e2nxez4WXPvvdjGbW24rOSgRhLOHXzWiT4pcP4G7KeWh0YCn18rF4bVwv7tggLLZ6MJnO6jXPBg=="],
17911794

17921795
"webidl-conversions": ["[email protected]", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="],
@@ -2041,6 +2044,8 @@
20412044

20422045
"vitepress/@vitejs/plugin-vue": ["@vitejs/[email protected]", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="],
20432046

2047+
"vitepress/@vue/devtools-api": ["@vue/[email protected]", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="],
2048+
20442049
"vitepress/shiki": ["[email protected]", "", { "dependencies": { "@shikijs/core": "2.5.0", "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/langs": "2.5.0", "@shikijs/themes": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ=="],
20452050

20462051
"vitepress/vite": ["[email protected]", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA=="],

0 commit comments

Comments
 (0)