[go: up one dir, main page]

Skip to content

Commit

Permalink
feat(map): support markerClusterer
Browse files Browse the repository at this point in the history
  • Loading branch information
CofCat456 committed Aug 8, 2023
1 parent 3557c20 commit 9037a8d
Show file tree
Hide file tree
Showing 19 changed files with 202 additions and 111 deletions.
4 changes: 2 additions & 2 deletions build/build-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export default defineConfig({
fileName: format => `index.${format}.js`,
},
rollupOptions: {
external: ['vue'],
external: ['vue', /^@googlemaps.*/],
output: {
globals: {
'vue': 'Vue',
'@googlemaps/js-api-loader': 'jsApiLoader',
'@googlemaps/js-api-loader': 'JsApiLoader',
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions build/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export default defineConfig({
fileName: format => `index.${format}.js`,
},
rollupOptions: {
// NOTE: Consider installing @voomap/core as an external dependency once the project is finalized.
// external: ['vue', /^@voomap.*/],
external: ['vue'],
external: ['vue', /^@googlemaps.*/],
output: {
globals: {
'vue': 'Vue',
'@voomap/core': 'VoomapCore',
'@googlemaps/markerclusterer': 'Markerclusterer',
'@googlemaps/js-api-loader': 'JsApiLoader',
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion changelog.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"maxMessageLength": "64",
"minMessageLength": "3",
"questions": ["type", "scope", "subject", "body", "breaking", "issues", "lerna"],
"scopes": ["", "core", "types", "map", "playground"],
"scopes": ["", "core", "map", "playground"],
"types": {
"chore": {
"description": "Build process or auxiliary tool changes",
Expand Down
3 changes: 3 additions & 0 deletions packages/map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
"peerDependencies": {
"vue": "^3.3.4"
},
"dependencies": {
"@googlemaps/markerclusterer": "^2.4.0"
},
"devDependencies": {
"@voomap/core": "workspace:*"
}
Expand Down
14 changes: 7 additions & 7 deletions packages/map/src/components/GoogleMap/src/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { mapEvents } from '@/utlis/events';
import type { FullscreenControlOptions, IconMouseEvent, LatLng, LatLngLiteral, Map, MapMouseEvent, MapRestriction, MapTypeControlOptions, MapTypeStyle, PanControlOptions, RotateControlOptions, ScaleControlOptions, StreetViewControlOptions, StreetViewPanorama, ZoomControlOptions } from '@/types';
interface CofMap {
cGoogle: typeof google | null
cApi: typeof google.maps | null
cMap: Map | null
cGoogle: typeof google | undefined
cApi: typeof google.maps | undefined
cMap: Map | undefined
}
// FIXME: Cannot use betterDefine, need detailed testing.
Expand Down Expand Up @@ -100,11 +100,11 @@ const emit = defineEmits<{
(e: 'rightclick'): void
}>();
const mapRef = ref<HTMLElement | null>(null);
const mapRef = ref<HTMLElement>();
const cofMap: CofMap = reactive({
cGoogle: null,
cApi: null,
cMap: null,
cGoogle: undefined,
cApi: undefined,
cMap: undefined,
});
provide(apiSymbol, toRef(() => cofMap.cApi));
Expand Down
6 changes: 3 additions & 3 deletions packages/map/src/components/InfoWindow/src/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const emit = defineEmits<{
(e: 'zindex_changed'): void
}>();
const infoWindow = ref<InfoWindow | null>(null);
const infoWindowRef = ref<HTMLElement | null>(null);
const infoWindow = ref<InfoWindow>();
const infoWindowRef = ref<HTMLElement>();
const map = inject(mapSymbol, ref());
const api = inject(apiSymbol, ref());
Expand All @@ -38,7 +38,7 @@ function open(opts?: InfoWindowOpenOptions) {
const close = () => infoWindow.value?.close();
onMounted(() => {
watch(map, (_) => {
watch(map, () => {
if (map.value && api.value) {
if (infoWindow.value) {
infoWindow.value.setOptions({
Expand Down
3 changes: 3 additions & 0 deletions packages/map/src/components/MarkerClusterer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Marker from './src/index.vue';

export default Marker;
55 changes: 55 additions & 0 deletions packages/map/src/components/MarkerClusterer/src/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<script setup lang="ts">
import { inject, markRaw, onBeforeUnmount, onMounted, provide, ref, unref, watch } from 'vue';
import type { MarkerClustererOptions } from '@googlemaps/markerclusterer';
import { MarkerClusterer, MarkerClustererEvents } from '@googlemaps/markerclusterer';
import { apiSymbol, mapSymbol, markerClustererSymbol } from '@/utlis/symbol';
const props = defineProps<MarkerClustererOptions>();
const emit = defineEmits<{
(e: 'clusteringbegin'): void
(e: 'clusteringend'): void
(e: 'click'): void
}>();
const map = inject(mapSymbol, ref());
const api = inject(apiSymbol, ref());
const markerClusterer = ref<MarkerClusterer>();
const markerClustererEvents = Object.values(MarkerClustererEvents);
provide(markerClustererSymbol, markerClusterer);
onMounted(() => {
watch(map, () => {
if (map.value)
markerClusterer.value = markRaw(new MarkerClusterer({ ...unref(props), map: map.value }));
markerClustererEvents.forEach((event: any) => {
markerClusterer.value?.addListener(event, () => emit(event));
});
markerClusterer.value?.render();
},
{
immediate: true,
});
});
onBeforeUnmount(() => {
if (markerClusterer.value) {
api.value?.event.clearInstanceListeners(markerClusterer.value);
markerClusterer.value.clearMarkers();
}
});
defineExpose({
markerClusterer,
});
</script>

<template>
<div class="marker-clusterer">
<slot />
</div>
</template>
2 changes: 2 additions & 0 deletions packages/map/src/components/components.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import GoogleMap from './GoogleMap';
import MarkerClusterer from './MarkerClusterer';
import Marker from './Marker';
import InfoWindow from './InfoWindow';

export {
GoogleMap,
MarkerClusterer,
Marker,
InfoWindow,
};
59 changes: 17 additions & 42 deletions packages/map/src/composables/useMap.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,8 @@
import type { Ref } from 'vue';
import { inject, onBeforeUnmount, ref, unref, watch } from 'vue';
import { apiSymbol, mapSymbol } from '../utlis/symbol';
import { computed, inject, onBeforeUnmount, ref, unref, watch } from 'vue';
import { apiSymbol, mapSymbol, markerClustererSymbol } from '../utlis/symbol';
import { hasChanged } from '../utlis';
import type { Marker, MarkerOptions } from '@/types';
import type { MarkerEvent } from '@/utlis/events';

type GoogleComponentsKey = 'Marker' | 'Polyline' | 'Polygon' | 'Rectangle' | 'Circle';

type GoogleMapComponentType<T> = T extends 'Marker'
? Marker
: T extends 'Polyline'
? google.maps.Polyline
: T extends 'Polygon'
? google.maps.Polygon
: T extends 'Rectangle'
? google.maps.Rectangle
: T extends 'Circle'
? google.maps.Circle
: never;

type GoogleMapComponentEvents<T> = T extends 'Marker'
? MarkerEvent
: T extends 'Polyline'
? MarkerEvent
: T extends 'Polygon'
? MarkerEvent
: T extends 'Rectangle'
? MarkerEvent
: T extends 'Circle'
? MarkerEvent
: never;

type GoogleMapComponentOptions<T> = T extends 'Marker'
? MarkerOptions
: T extends 'Polyline'
? google.maps.PolylineOptions
: T extends 'Polygon'
? google.maps.PolygonOptions
: T extends 'Rectangle'
? google.maps.RectangleOptions
: T extends 'Circle'
? google.maps.CircleOptions
: never;
import type { GoogleComponentsKey, GoogleMapComponentEvents, GoogleMapComponentOptions, GoogleMapComponentType, Marker, MarkerOptions } from '@/types';

export function useMap<T extends GoogleComponentsKey>(
key: T,
Expand All @@ -52,6 +13,9 @@ export function useMap<T extends GoogleComponentsKey>(
const component = ref<GoogleMapComponentType<T>>();
const map = inject(mapSymbol, ref());
const api = inject(apiSymbol, ref());
const markerClusterer = inject(markerClustererSymbol, ref());

const hasMarkerInCluster = computed(() => !!markerClusterer.value);

// NOTE: avoiding redundant rendering.
watch([map, options], (_, [oldMap, oldOptions]) => {
Expand All @@ -72,10 +36,18 @@ export function useMap<T extends GoogleComponentsKey>(
& google.maps.RectangleOptions
& google.maps.CircleOptions
) | null);

if (hasMarkerInCluster.value) {
markerClusterer.value?.removeMarker(component.value as Marker);
markerClusterer.value?.addMarker(component.value as Marker);
}
}
else {
component.value = marker as GoogleMapComponentType<typeof key>;

if (hasMarkerInCluster.value)
markerClusterer.value?.addMarker(component.value as Marker);

events.forEach((event) => {
component.value?.addListener(event, (e: any) => emit(event, e));
});
Expand All @@ -88,6 +60,9 @@ export function useMap<T extends GoogleComponentsKey>(
onBeforeUnmount(() => {
if (component.value)
api.value?.event.clearInstanceListeners(component.value);

if (hasMarkerInCluster.value)
markerClusterer.value?.removeMarker(component.value as Marker);
});

return component;
Expand Down
42 changes: 42 additions & 0 deletions packages/map/src/types/google.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { MarkerEvent } from "@/utlis/events";
import { MarkerOptions } from ".";

// Map
export type Map = google.maps.Map;
export type Marker = google.maps.Marker;
Expand All @@ -24,3 +27,42 @@ export type LatLngLiteral = google.maps.LatLngLiteral;
// Events
export type MapMouseEvent = google.maps.MapMouseEvent;
export type IconMouseEvent = google.maps.IconMouseEvent;


export type GoogleComponentsKey = 'Marker' | 'Polyline' | 'Polygon' | 'Rectangle' | 'Circle';

export type GoogleMapComponentType<T> = T extends 'Marker'
? Marker
: T extends 'Polyline'
? google.maps.Polyline
: T extends 'Polygon'
? google.maps.Polygon
: T extends 'Rectangle'
? google.maps.Rectangle
: T extends 'Circle'
? google.maps.Circle
: unknown;

export type GoogleMapComponentEvents<T> = T extends 'Marker'
? MarkerEvent
: T extends 'Polyline'
? MarkerEvent
: T extends 'Polygon'
? MarkerEvent
: T extends 'Rectangle'
? MarkerEvent
: T extends 'Circle'
? MarkerEvent
: unknown;

export type GoogleMapComponentOptions<T> = T extends 'Marker'
? MarkerOptions
: T extends 'Polyline'
? google.maps.PolylineOptions
: T extends 'Polygon'
? google.maps.PolygonOptions
: T extends 'Rectangle'
? google.maps.RectangleOptions
: T extends 'Circle'
? google.maps.CircleOptions
: unknown;
6 changes: 4 additions & 2 deletions packages/map/src/utlis/symbol.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { InjectionKey, Ref } from 'vue';
import type { MarkerClusterer } from '@googlemaps/markerclusterer';
import type { Map, Marker } from '../types';

export const mapSymbol: InjectionKey<Ref<Map | null>> = Symbol('map');
export const apiSymbol: InjectionKey<Ref<typeof google.maps | null>> = Symbol('api');
export const mapSymbol: InjectionKey<Ref<Map | undefined>> = Symbol('map');
export const apiSymbol: InjectionKey<Ref<typeof google.maps | undefined>> = Symbol('api');
export const markerClustererSymbol: InjectionKey<Ref<MarkerClusterer | undefined>> = Symbol('markerClusterer');
export const markerSymbol: InjectionKey<Ref<Marker | undefined>> = Symbol('marker');
4 changes: 3 additions & 1 deletion playground/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<script setup lang="ts">
// import Basic from './components/BasicExample.vue';
// import Marker from './components/MarkerExample.vue';
import InfoWindow from './components/InfoWindowExample.vue';
// import MarkerClustererExample from './components/MarkerClustererExample.vue';
</script>

<template>
<!-- <Basic /> -->
<!-- <Marker /> -->
<InfoWindow />
<!-- <MarkerClustererExample /> -->
</template>
5 changes: 0 additions & 5 deletions playground/src/components/BasicExample.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ const zoom = ref(12);
const center = reactive<google.maps.LatLngLiteral>(createRandomCoordinate());
const mapRef = ref<InstanceType<typeof GoogleMap> | null>(null);
function handleClick(value: any) {
console.log(value);
}
function handleZoomIn(value: number) {
zoom.value = ++value;
}
Expand All @@ -37,7 +33,6 @@ function changeCenter() {
:max-zoom="20"
:min-zoom="10"
:center="center"
@mouseover="handleClick"
/>
<button type="button" style="bottom: 20px; left: 10px" @click="changeCenter()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M20 1v3h3v2h-3v3h-2V6h-3V4h3V1h2zm-8 12c1.1 0 2-.9 2-2s-.9-2-2-2s-2 .9-2 2s.9 2 2 2zm2-9.75V7h3v3h2.92c.05.39.08.79.08 1.2c0 3.32-2.67 7.25-8 11.8c-5.33-4.55-8-8.48-8-11.8C4 6.22 7.8 3 12 3c.68 0 1.35.08 2 .25z" /></svg>
Expand Down
21 changes: 0 additions & 21 deletions playground/src/components/InfoWindowExample.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ const zoom = ref(12);
const center = reactive<google.maps.LatLngLiteral>(createRandomCoordinate());
const singleRef = ref<InstanceType<typeof InfoWindow> | null>(null);
function handleZoomIn(value: number) {
zoom.value = ++value;
}
function handleZoomOut(value: number) {
zoom.value = --value;
}
function changeCenter() {
Object.assign(center, createRandomCoordinate());
}
function handleClick(e: google.maps.MapMouseEvent) {
// eslint-disable-next-line no-console
console.log('click', e.latLng);
Expand Down Expand Up @@ -61,13 +49,4 @@ function handleCloseClick() {
@closeclick="handleCloseClick"
/>
</GoogleMap>
<button type="button" style="bottom: 20px; left: 10px" @click="changeCenter()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M20 1v3h3v2h-3v3h-2V6h-3V4h3V1h2zm-8 12c1.1 0 2-.9 2-2s-.9-2-2-2s-2 .9-2 2s.9 2 2 2zm2-9.75V7h3v3h2.92c.05.39.08.79.08 1.2c0 3.32-2.67 7.25-8 11.8c-5.33-4.55-8-8.48-8-11.8C4 6.22 7.8 3 12 3c.68 0 1.35.08 2 .25z" /></svg>
</button>
<button type="button" style="bottom: 70px; right: 10px;" @click="handleZoomIn(zoom)">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M18 12.998h-5v5a1 1 0 0 1-2 0v-5H6a1 1 0 0 1 0-2h5v-5a1 1 0 0 1 2 0v5h5a1 1 0 0 1 0 2z" /></svg>
</button>
<button type="button" style="bottom: 20px; right: 10px" @click="handleZoomOut(zoom)">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M18 12.998H6a1 1 0 0 1 0-2h12a1 1 0 0 1 0 2z" /></svg>
</button>
</template>
Loading

0 comments on commit 9037a8d

Please sign in to comment.