Skip to content

Commit

Permalink
feat(googleMaps): unified styling of static image and map
Browse files Browse the repository at this point in the history
Fixes #202
  • Loading branch information
harlan-zw committed Sep 3, 2024
1 parent 63e6041 commit c85d278
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 3 deletions.
17 changes: 17 additions & 0 deletions docs/content/scripts/content/google-maps.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,23 @@ If you want to load the Google Maps immediately, you can use the `trigger` prop.
</template>
```

#### Map Styling

You can style the map by using the `mapOptions.styles` prop. You can find pre-made styles on [Snazzy Maps](https://snazzymaps.com/).

This will automatically work for both the static map placeholder and the interactive map.

```vue
<script setup lang="ts">
const mapOptions = {
styles: [{ elementType: 'labels', stylers: [{ visibility: 'off' }, { color: '#f49f53' }] }, { featureType: 'landscape', stylers: [{ color: '#f9ddc5' }, { lightness: -7 }] }, { featureType: 'road', stylers: [{ color: '#813033' }, { lightness: 43 }] }, { featureType: 'poi.business', stylers: [{ color: '#645c20' }, { lightness: 38 }] }, { featureType: 'water', stylers: [{ color: '#1994bf' }, { saturation: -69 }, { gamma: 0.99 }, { lightness: 43 }] }, { featureType: 'road.local', elementType: 'geometry.fill', stylers: [{ color: '#f19f53' }, { weight: 1.3 }, { visibility: 'on' }, { lightness: 16 }] }, { featureType: 'poi.business' }, { featureType: 'poi.park', stylers: [{ color: '#645c20' }, { lightness: 39 }] }, { featureType: 'poi.school', stylers: [{ color: '#a95521' }, { lightness: 35 }] }, {}, { featureType: 'poi.medical', elementType: 'geometry.fill', stylers: [{ color: '#813033' }, { lightness: 38 }, { visibility: 'off' }] },
}
</script>
<template>
<ScriptGoogleMaps :mapOptions="mapOptions" />
</template>
```

### Component API

See the [Facade Component API](/docs/guides/facade-components#facade-components-api) for full props, events, and slots.
Expand Down
45 changes: 45 additions & 0 deletions playground/pages/third-parties/google-maps/styled.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script setup lang="ts">
const mapOptions = {
center: { lat: -34.397, lng: 150.644 },
styles: [{ elementType: 'labels', stylers: [{ visibility: 'off' }, { color: '#f49f53' }] }, { featureType: 'landscape', stylers: [{ color: '#f9ddc5' }, { lightness: -7 }] }, { featureType: 'road', stylers: [{ color: '#813033' }, { lightness: 43 }] }, { featureType: 'poi.business', stylers: [{ color: '#645c20' }, { lightness: 38 }] }, { featureType: 'water', stylers: [{ color: '#1994bf' }, { saturation: -69 }, { gamma: 0.99 }, { lightness: 43 }] }, { featureType: 'road.local', elementType: 'geometry.fill', stylers: [{ color: '#f19f53' }, { weight: 1.3 }, { visibility: 'on' }, { lightness: 16 }] }, { featureType: 'poi.business' }, { featureType: 'poi.park', stylers: [{ color: '#645c20' }, { lightness: 39 }] }, { featureType: 'poi.school', stylers: [{ color: '#a95521' }, { lightness: 35 }] }, {}, { featureType: 'poi.medical', elementType: 'geometry.fill', stylers: [{ color: '#813033' }, { lightness: 38 }, { visibility: 'off' }] }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { elementType: 'labels' }, { featureType: 'poi.sports_complex', stylers: [{ color: '#9e5916' }, { lightness: 32 }] }, {}, { featureType: 'poi.government', stylers: [{ color: '#9e5916' }, { lightness: 46 }] }, { featureType: 'transit.station', stylers: [{ visibility: 'off' }] }, { featureType: 'transit.line', stylers: [{ color: '#813033' }, { lightness: 22 }] }, { featureType: 'transit', stylers: [{ lightness: 38 }] }, { featureType: 'road.local', elementType: 'geometry.stroke', stylers: [{ color: '#f19f53' }, { lightness: -10 }] }, {}, {}, {}],
} satisfies google.maps.MapOptions
</script>

<template>
<div>
<div>
<ScriptGoogleMaps
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
:width="1200"
:height="600"
above-the-fold
:map-options="mapOptions"
/>
</div>
<div class="button-container">
<button
class="button"
@click="changeQuery"
>
change query
</button>
</div>
</div>
</template>

<style>
.button-container {
margin: 20px 0;
}
.button {
background-color: orange;
border-radius: 8px;
padding: 4px 8px;
cursor: pointer;
}
.button:not(:last-child) {
margin-right: 8px;
}
</style>
26 changes: 23 additions & 3 deletions src/runtime/components/ScriptGoogleMaps.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ const props = withDefaults(defineProps<{
trigger: ['mouseenter', 'mouseover', 'mousedown'],
width: 640,
height: 400,
centerMarker: true,
})
const emits = defineEmits<{
Expand Down Expand Up @@ -124,7 +123,7 @@ const options = computed(() => {
return defu({ center: centerOverride.value }, props.mapOptions, {
center: props.center,
zoom: 15,
mapId: 'map',
mapId: props.mapOptions?.styles ? undefined : 'map',
})
})
const ready = ref(false)
Expand Down Expand Up @@ -292,7 +291,11 @@ onMounted(() => {
center = await resolveQueryToLatLang(center as string)
}
map.value!.setCenter(center as google.maps.LatLng)
if (props.centerMarker) {
if (typeof props.centerMarker === 'undefined' || props.centerMarker) {
if (options.value.mapId) {
// not allowed to use advanced markers with styles
return
}
if (prev[0]) {
const prevCenterHash = hash({ position: prev[0] })
// @ts-expect-error broken upstream type
Expand Down Expand Up @@ -335,6 +338,22 @@ if (import.meta.server) {
})
}
function transformMapStyles(styles: google.maps.MapTypeStyle[]) {
return styles.map((style) => {
const feature = style.featureType ? `feature:${style.featureType}` : ''
const element = style.elementType ? `element:${style.elementType}` : ''
const rules = (style.stylers || []).map((styler) => {
return Object.entries(styler).map(([key, value]) => {
if (key === 'color' && typeof value === 'string') {
value = value.replace('#', '0x')
}
return `${key}:${value}`
}).join('|')
}).filter(Boolean).join('|')
return [feature, element, rules].filter(Boolean).join('|')
}).filter(Boolean)
}
const placeholder = computed(() => {
let center = options.value.center
if (center && typeof center === 'object') {
Expand All @@ -349,6 +368,7 @@ const placeholder = computed(() => {
size: `${props.width}x${props.height}`,
key: apiKey,
scale: 2, // we assume a high DPI to avoid hydration issues
style: props.mapOptions?.styles ? transformMapStyles(props.mapOptions.styles) : undefined,
markers: [
...(props.markers || []),
center,
Expand Down

0 comments on commit c85d278

Please sign in to comment.