Overlays Within Street View
Sample code for Google Maps Platform JavaScript API author(s): Justin Poehnelt
by wintlu
HTML
<!doctype html>
<!--
@license
Copyright 2019 Google LLC. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
-->
<html>
<head>
<title>Overlays Within Street View</title>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="floating-panel">
<input type="button" value="Toggle Street View" id="toggle" />
</div>
<div id="map"></div>
<!--
The `defer` attribute causes the script to execute after the full HTML
document has been parsed. For non-blocking uses, avoiding race conditions,
and consistent behavior across browsers, consider loading using Promises. See
https://developers.google.com/maps/documentation/javascript/load-maps-js-api
for more information.
-->
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&libraries=marker&v=weekly"
defer
></script>
</body>
</html>
CSS
/* Ensure map fills the window */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
/* --- Custom Marker Styles --- */
.custom-marker {
position: absolute;
cursor: pointer;
/* Center the marker's bottom tip on the coordinates */
transform: translate(-50%, -100%);
}
/* The visual pin */
.marker-pin {
width: 50px;
height: 50px;
background: #ff0000;
border-radius: 50% 50% 50% 0;
transform: rotate(-45deg);
box-shadow: 0 0 10px rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
animation: bounce 1s infinite alternate;
}
/* Inner white dot */
.marker-pin::after {
content: '';
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
}
/* Pulse effect on the ground */
.marker-pulse {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 20px;
height: 10px;
background: rgba(255, 0, 0, 0.5);
border-radius: 50%;
animation: pulse 1s infinite alternate;
z-index: -1;
}
@keyframes bounce {
0% { transform: rotate(-45deg) translateY(0); }
100% { transform: rotate(-45deg) translateY(-10px); }
}
@keyframes pulse {
0% { transform: translateX(-50%) scale(1); opacity: 0.8; }
100% { transform: translateX(-50%) scale(2); opacity: 0.2; }
}
JavaScript
function initMap() {
const bankPos = { lat: 40.729681, lng: -73.991138 };
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 19,
center: bankPos,
});
// --- 1. DEFINE THE SVG ICON (The "Zero Lag" Solution) ---
// This SVG string recreates your red pin design.
// We use this instead of an HTML div so it renders IN the 3D world.
const pinSvg = `
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 50 50">
<path d="M 25,50 C 10,35 0,25 0,18 C 0,8 8,0 25,0 C 42,0 50,8 50,18 C 50,25 40,35 25,50 Z" fill="#ff0000"/>
<circle cx="25" cy="18" r="8" fill="white"/>
</svg>`;
// Convert the SVG string into a data URL
const iconUrl = 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(pinSvg);
const iconOptions = {
url: iconUrl,
scaledSize: new google.maps.Size(60, 60), // Size of the marker
anchor: new google.maps.Point(30, 60), // Anchor at bottom-center (x=width/2, y=height)
};
// --- 2. SETUP STREET VIEW ---
const svService = new google.maps.StreetViewService();
const panorama = map.getStreetView();
// Find the nearest OUTDOOR panorama
svService.getPanorama({
location: bankPos,
radius: 50,
source: google.maps.StreetViewSource.OUTDOOR
}).then(({ data }) => {
panorama.setPano(data.location.pano);
panorama.setPov({
heading: 265,
pitch: 0,
});
}).catch((err) => {
console.error("No outdoor street view found:", err);
});
// --- 3. CREATE THE NATIVE MARKERS ---
// Marker for the 2D Map
new google.maps.Marker({
position: bankPos,
map: map,
icon: iconOptions,
title: "2D Map Marker"
});
// Marker for the 3D Street View (This will now be perfectly synced)
new google.maps.Marker({
position: bankPos,
map: panorama, // Attach directly to the panorama
icon: iconOptions,
title: "Street View Marker"
});
...