html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#map-container {
width: 100%;
height: 100%;
position: relative;
font-family: “Roboto”, sans-serif;
box-sizing: border-box;
}
#map-container a {
text-decoration: none;
color: #1967d2;
}
#map-container button {
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
font-size: inherit;
cursor: pointer;
}
#gmp-map {
position: absolute;
left: 25em;
top: 0;
right: 0;
bottom: 0;
}
#locations-panel {
position: absolute;
left: 0;
width: 25em;
top: 0;
bottom: 0;
overflow-y: auto;
background: white;
padding: 0.5em;
box-sizing: border-box;
}
@media only screen and (max-width: 876px) {
#gmp-map {
left: 0;
bottom: 50%;
}
#locations-panel {
top: 50%;
right: 0;
width: unset;
}
}
#locations-panel-list > header {
padding: 1.4em 1.4em 0 1.4em;
}
#locations-panel-list h1.search-title {
font-size: 1em;
font-weight: 500;
margin: 0;
}
#locations-panel-list h1.search-title > img {
vertical-align: bottom;
margin-top: -1em;
}
#locations-panel-list .search-input {
width: 100%;
margin-top: 0.8em;
position: relative;
}
#locations-panel-list .search-input input {
width: 100%;
border: 1px solid #80868b;
border-radius: 0.3em;
height: 2.7em;
box-sizing: border-box;
padding: 0 1em 0 2.5em;
font-size: 0.9em;
}
#locations-panel-list .search-input input:focus {
outline: 2px solid #1e88e5;
}
#locations-panel-list .search-input input::placeholder {
color: #212121;
opacity: 0.5;
}
#locations-panel-list .search-input-overlay {
position: absolute;
}
#locations-panel-list .search-input-overlay.search {
left: 2px;
top: 2px;
bottom: 2px;
width: 2.4em;
}
#locations-panel-list .search-input-overlay.search button {
width: 100%;
height: 100%;
border-radius: 0.2em;
color: black;
background: transparent;
}
#locations-panel-list .search-input-overlay.search .icon {
margin-top: 0.15em;
vertical-align: top;
width: 0.9em;
}
#locations-panel-list .section-name {
font-weight: 500;
font-size: 0.9em;
margin: 1.8em 0 1em 1.5em;
}
#locations-panel-list .location-result {
position: relative;
padding: 0.8em 3.5em 0.8em 1.4em;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
cursor: pointer;
}
#locations-panel-list .location-result:first-of-type {
border-top: 1px solid rgba(0, 0, 0, 0.12);
}
#locations-panel-list .location-result:last-of-type {
border-bottom: none;
}
#locations-panel-list .location-result.selected {
outline: 2px solid #4285f4;
}
#locations-panel-list button.select-location {
margin-bottom: 0.6em;
text-align: left;
}
#locations-panel-list .location-result h2.name {
font-size: 1em;
font-weight: 500;
margin: 0;
}
#locations-panel-list .location-result .address {
font-size: 0.9em;
margin-bottom: 0.5em;
}
#locations-panel-list .directions-button {
position: absolute;
right: 1.2em;
top: 2.3em;
}
#locations-panel-list .directions-button-background:hover {
fill: rgba(116,120,127,0.1);
}
#locations-panel-list .directions-button-background {
fill: rgba(255,255,255,0.01);
}
#locations-panel-list .location-result .distance {
position: absolute;
top: 0.9em;
right: 0;
text-align: center;
font-size: 0.9em;
width: 5em;
}
#locations-panel-list .option-container {
display: inline-block;
margin: 0.2em 0;
position: relative;
vertical-align: top;
}
#locations-panel-list .option-container button:hover,
#locations-panel-list .option-container a:hover {
background-color: #f1f3f4;
}
#locations-panel-list .option {
border: 1px solid #e0e0e0;
border-radius: 1.3em;
color: #1967d2;
font-size: 0.9em;
font-weight: 500;
padding: 0.6em 0.7em;
}
#locations-panel-list .action-button .option {
align-items: center;
display: flex;
}
#locations-panel-list .action-button .open-icon {
/* Match link color #1967d2 */
filter: invert(30%) sepia(67%) saturate(7379%) hue-rotate(209deg) brightness(95%) contrast(80%);
height: 1.2em;
margin-right: 0.4em;
}
#locations-panel-list .action-button span {
margin-right: 0.3em;
}
#location-results-list {
list-style-type: none;
margin: 0;
padding: 0;
}
‘use strict’;
/** Helper function to generate a Google Maps directions URL */
function generateDirectionsURL(origin, destination) {
const googleMapsUrlBase = ‘https://www.google.com/maps/dir/?’;
const searchParams = new URLSearchParams(‘api=1’);
searchParams.append(‘origin’, origin);
const destinationParam = [];
// Add title to destinationParam except in cases where Quick Builder set
// the title to the first line of the address
if (destination.title !== destination.address1) {
destinationParam.push(destination.title);
}
destinationParam.push(destination.address1, destination.address2);
searchParams.append(‘destination’, destinationParam.join(‘,’));
return googleMapsUrlBase + searchParams.toString();
}
/**
* Defines an instance of the Locator+ solution, to be instantiated
* when the Maps library is loaded.
*/
function LocatorPlus(configuration) {
const locator = this;
locator.locations = configuration.locations || [];
locator.capabilities = configuration.capabilities || {};
const mapEl = document.getElementById(‘gmp-map’);
const panelEl = document.getElementById(‘locations-panel’);
locator.panelListEl = document.getElementById(‘locations-panel-list’);
const sectionNameEl =
document.getElementById(‘location-results-section-name’);
const resultsContainerEl = document.getElementById(‘location-results-list’);
const itemsTemplate = Handlebars.compile(
document.getElementById(‘locator-result-items-tmpl’).innerHTML);
locator.searchLocation = null;
locator.searchLocationMarker = null;
locator.selectedLocationIdx = null;
locator.userCountry = null;
// Initialize the map ——————————————————-
locator.map = new google.maps.Map(mapEl, configuration.mapOptions);
// Store selection.
const selectResultItem = function(locationIdx, panToMarker, scrollToResult) {
locator.selectedLocationIdx = locationIdx;
for (let locationElem of resultsContainerEl.children) {
locationElem.classList.remove(‘selected’);
if (getResultIndex(locationElem) === locator.selectedLocationIdx) {
locationElem.classList.add(‘selected’);
if (scrollToResult) {
panelEl.scrollTop = locationElem.offsetTop;
}
}
}
if (panToMarker && (locationIdx != null)) {
locator.map.panTo(locator.locations[locationIdx].coords);
}
};
// Create a marker for each location.
const markers = locator.locations.map(function(location, index) {
const marker = new google.maps.Marker({
position: location.coords,
map: locator.map,
title: location.title,
});
marker.addListener(‘click’, function() {
selectResultItem(index, false, true);
});
return marker;
});
// Fit map to marker bounds.
locator.updateBounds = function() {
const bounds = new google.maps.LatLngBounds();
if (locator.searchLocationMarker) {
bounds.extend(locator.searchLocationMarker.getPosition());
}
for (let i = 0; i < markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
locator.map.fitBounds(bounds);
};
if (locator.locations.length) {
locator.updateBounds();
}
// Get the distance of a store location to the user's location,
// used in sorting the list.
const getLocationDistance = function(location) {
if (!locator.searchLocation) return null;
// Use travel distance if available (from Distance Matrix).
if (location.travelDistanceValue != null) {
return location.travelDistanceValue;
}
// Fall back to straight-line distance.
return google.maps.geometry.spherical.computeDistanceBetween(
new google.maps.LatLng(location.coords),
locator.searchLocation.location);
};
// Render the results list ————————————————–
const getResultIndex = function(elem) {
return parseInt(elem.getAttribute('data-location-index'));
};
locator.renderResultsList = function() {
let locations = locator.locations.slice();
for (let i = 0; i 0) {
const result = results[0];
geocodeCache.set(query, result);
handleResult(result);
}
}
});
};
// Set up geocoding on the search input.
searchButtonEl.addEventListener(‘click’, function() {
geocodeSearch(searchInputEl.value.trim());
});
// Initialize Autocomplete.
initializeSearchInputAutocomplete(
locator, searchInputEl, geocodeSearch, updateSearchLocation);
}
/** Add Autocomplete to the search input. */
function initializeSearchInputAutocomplete(
locator, searchInputEl, fallbackSearch, searchLocationUpdater) {
// Set up Autocomplete on the search input. Bias results to map viewport.
const autocomplete = new google.maps.places.Autocomplete(searchInputEl, {
types: [‘geocode’],
fields: [‘place_id’, ‘formatted_address’, ‘geometry.location’]
});
autocomplete.bindTo(‘bounds’, locator.map);
autocomplete.addListener(‘place_changed’, function() {
const placeResult = autocomplete.getPlace();
if (!placeResult.geometry) {
// Hitting ‘Enter’ without selecting a suggestion will result in a
// placeResult with only the text input value as the ‘name’ field.
fallbackSearch(placeResult.name);
return;
}
searchLocationUpdater(
placeResult.formatted_address, placeResult.geometry.location);
});
}
/** Initialize Distance Matrix for the locator. */
function initializeDistanceMatrix(locator) {
const distanceMatrixService = new google.maps.DistanceMatrixService();
// Annotate travel times to the selected location using Distance Matrix.
locator.updateTravelTimes = function() {
if (!locator.searchLocation) return;
const units = (locator.userCountry === ‘USA’) ?
google.maps.UnitSystem.IMPERIAL :
google.maps.UnitSystem.METRIC;
const request = {
origins: [locator.searchLocation.location],
destinations: locator.locations.map(function(x) {
return x.coords;
}),
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: units,
};
const callback = function(response, status) {
if (status === ‘OK’) {
const distances = response.rows[0].elements;
for (let i = 0; i < distances.length; i++) {
const distResult = distances[i];
let travelDistanceText, travelDistanceValue;
if (distResult.status === 'OK') {
travelDistanceText = distResult.distance.text;
travelDistanceValue = distResult.distance.value;
}
const location = locator.locations[i];
location.travelDistanceText = travelDistanceText;
location.travelDistanceValue = travelDistanceValue;
}
// Re-render the results list, in case the ordering has changed.
locator.renderResultsList();
}
};
distanceMatrixService.getDistanceMatrix(request, callback);
};
}
const CONFIGURATION = {
“locations”: [
{“title”:”Atracare – Pediatrics, Primary Care, \u0026 Urgent Care Clinic”,”address1″:”18068 Coastal Hwy”,”address2″:”Lewes, DE 19958, USA”,”coords”:{“lat”:38.745668942114314,”lng”:-75.15569283624572},”placeId”:”ChIJKatbRLi5uIkRGXfjmyleYSY”,”actions”:[{“label”:”Book appointment”,”defaultUrl”:”https://atracare.com/”}]},
{“title”:”Atracare – Urgent Care Clinic”,”address1″:”90 Atlantic Ave Suite 4″,”address2″:”Ocean View, DE 19970, USA”,”coords”:{“lat”:38.54456566055961,”lng”:-75.09555643558197},”placeId”:”ChIJDQ-iRnnPuIkRumZf20A87z4″},
{“title”:”Atracare – Mental Health”,”address1″:”1532 Savannah Rd A”,”address2″:”Lewes, DE 19958, USA”,”coords”:{“lat”:38.753311736200416,”lng”:-75.16127037976229},”placeId”:”ChIJp7tia9K5uIkRSYSzauT7vTs”}
],
“mapOptions”: {“center”:{“lat”:38.0,”lng”:-100.0},”fullscreenControl”:true,”mapTypeControl”:false,”streetViewControl”:false,”zoom”:4,”zoomControl”:true,”maxZoom”:17,”mapId”:””},
“mapsApiKey”: “AIzaSyAE870KdQuKI-6TfqcqSP4EV8pG0Craa4A”,
“capabilities”: {“input”:true,”autocomplete”:true,”directions”:false,”distanceMatrix”:true,”details”:false,”actions”:true}
};
function initMap() {
new LocatorPlus(CONFIGURATION);
}
{{#each locations}}
{{address2}}
{{#if travelDistanceText}}
{{/each}}