This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

    Locator

    html,

    body {

    height: 100%;

    margin: 0;

    padding: 0;

    }

    #map-container {

    width: 100%;

    height: 550px;

    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: 22em;

    top: 0;

    right: 0;

    bottom: 0;

    }

    #locations-panel {

    position: absolute;

    left: 0;

    width: 22em;

    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 rgba(0, 0, 0, 0.2);

    border-radius: 0.3em;

    height: 2.2em;

    box-sizing: border-box;

    padding: 0 2.5em 0 1em;

    font-size: 1em;

    }

    #locations-panel-list .search-input-overlay {

    position: absolute;

    }

    #locations-panel-list .search-input-overlay.search {

    right: 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.05em;

    vertical-align: top;

    }

    #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;

    }

    #locations-panel-list .option-container button:hover,

    #locations-panel-list .option-container a:hover {

    background-color: #f1f3f4;

    }

    #locations-panel-list .option {

    border: 1px solid #bdc1c6;

    border-radius: 0.9em;

    color: #1967d2;

    font-size: 0.9em;

    font-weight: 500;

    padding: 0.3em 0;

    }

    #locations-panel-list .option > span {

    margin: 0 0.9em;

    }

    #location-results-list {

    list-style-type: none;

    margin: 0;

    padding: 0;

    }

    /* ————- DETAILS PANEL ——————————- */

    #locations-panel-details {

    padding: 1.4em;

    box-sizing: border-box;

    display: none;

    }

    #locations-panel-details .back-button {

    font-size: 1em;

    font-weight: 500;

    color: #1967d2;

    display: block;

    text-decoration: none;

    background: none;

    border: none;

    cursor: pointer;

    padding: 0;

    font-family: inherit;

    }

    #locations-panel-details .back-button .icon {

    width: 20px;

    height: 20px;

    vertical-align: bottom;

    /* Match link color #1967d2 */

    filter: invert(30%) sepia(67%) saturate(7379%) hue-rotate(209deg) brightness(95%) contrast(80%);

    }

    #locations-panel-details > header {

    text-align: center;

    }

    #locations-panel-details .banner {

    margin-top: 1em;

    }

    #locations-panel-details h2 {

    font-size: 1.1em;

    font-weight: 500;

    margin-bottom: 0.3em;

    }

    #locations-panel-details .distance {

    font-size: 0.9em;

    text-align: center;

    }

    #locations-panel-details .address {

    text-align: center;

    font-size: 0.9em;

    margin-top: 1.3em;

    }

    #locations-panel-details .atmosphere {

    text-align: center;

    font-size: 0.9em;

    margin: 0.8em 0;

    }

    #locations-panel-details .star-rating-numeric {

    color: #555;

    }

    #locations-panel-details .star-icon {

    width: 1.2em;

    height: 1.2em;

    margin-right: -0.3em;

    margin-top: -0.08em;

    vertical-align: top;

    filter: invert(88%) sepia(60%) saturate(2073%) hue-rotate(318deg) brightness(93%) contrast(104%);

    }

    #locations-panel-details .star-icon:last-of-type {

    margin-right: 0.2em;

    }

    #locations-panel-details .price-dollars {

    color: #555;

    }

    #locations-panel-details hr {

    height: 1px;

    color: rgba(0, 0, 0, 0.12);

    background-color: rgba(0, 0, 0, 0.12);

    border: none;

    margin-bottom: 1em;

    }

    #locations-panel-details .contact {

    font-size: 0.9em;

    margin: 0.8em 0;

    display: flex;

    align-items: center;

    }

    #locations-panel-details .contact .icon {

    flex: 0 0 auto;

    width: 1.5em;

    height: 1.5em;

    }

    #locations-panel-details .contact .right {

    padding: 0.1em 0 0 1em;

    }

    #locations-panel-details .hours .weekday {

    display: inline-block;

    width: 5em;

    }

    #locations-panel-details .website a {

    white-space: nowrap;

    display: inline-block;

    overflow: hidden;

    max-width: 16em;

    text-overflow: ellipsis;

    }

    #locations-panel-details p.attribution {

    color: #777;

    margin: 0;

    font-size: 0.8em;

    font-style: italic;

    }

    ‘use strict’;

    /** Hide a DOM element. */

    function hideElement(el) {

    el.style.display = ‘none’;

    }

    /** Show a DOM element that has been hidden. */

    function showElement(el) {

    el.style.display = ‘block’;

    }

    /** 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 ————————————————–

    // When the results list re-renders, always update directions on the

    // first selection event.

    let updateDirectionsOnSelect;

    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);

    };

    }

    /** Initialize Directions service for the locator. */

    function initializeDirections(locator) {

    const directionsCache = new Map();

    const directionsService = new google.maps.DirectionsService();

    const directionsRenderer = new google.maps.DirectionsRenderer({

    suppressMarkers: true,

    });

    // Update directions displayed from the search location to

    // the selected location on the map.

    locator.updateDirections = function() {

    if (!locator.searchLocation || (locator.selectedLocationIdx == null)) {

    return;

    }

    const cacheKey = JSON.stringify(

    [locator.searchLocation.location, locator.selectedLocationIdx]);

    if (directionsCache.has(cacheKey)) {

    const directions = directionsCache.get(cacheKey);

    directionsRenderer.setMap(locator.map);

    directionsRenderer.setDirections(directions);

    return;

    }

    const request = {

    origin: locator.searchLocation.location,

    destination: locator.locations[locator.selectedLocationIdx].coords,

    travelMode: google.maps.TravelMode.DRIVING

    };

    directionsService.route(request, function(response, status) {

    if (status === 'OK') {

    directionsRenderer.setMap(locator.map);

    directionsRenderer.setDirections(response);

    directionsCache.set(cacheKey, response);

    }

    });

    };

    locator.clearDirections = function() {

    directionsRenderer.setMap(null);

    };

    }

    /** Initialize Place Details service and UI for the locator. */

    function initializeDetails(locator) {

    const panelDetailsEl = document.getElementById('locations-panel-details');

    const detailsService = new google.maps.places.PlacesService(locator.map);

    const detailsTemplate = Handlebars.compile(

    document.getElementById('locator-details-tmpl').innerHTML);

    const renderDetails = function(context) {

    panelDetailsEl.innerHTML = detailsTemplate(context);

    panelDetailsEl.querySelector('.back-button')

    .addEventListener('click', hideDetails);

    };

    const hideDetails = function() {

    showElement(locator.panelListEl);

    hideElement(panelDetailsEl);

    };

    locator.showDetails = function(locationIndex) {

    const location = locator.locations[locationIndex];

    const context = {location};

    // Helper function to create a fixed-size array.

    const initArray = function(arraySize) {

    const array = [];

    while (array.length e.split(/\:\s+/))

    .map(e => ({‘days’: e[0].substr(0, 3), ‘hours’: e[1]}));

    for (let i = 1; i < daysHours.length; i++) {

    if (daysHours[i – 1].hours === daysHours[i].hours) {

    if (daysHours[i – 1].days.indexOf('-') !== -1) {

    daysHours[i – 1].days =

    daysHours[i – 1].days.replace(/\w+$/, daysHours[i].days);

    } else {

    daysHours[i – 1].days += ' – ' + daysHours[i].days;

    }

    daysHours.splice(i–, 1);

    }

    }

    place.openingHoursSummary = daysHours;

    }

    if (place.rating) {

    const starsOutOfTen = Math.round(2 * place.rating);

    const fullStars = Math.floor(starsOutOfTen / 2);

    const halfStars = fullStars !== starsOutOfTen / 2 ? 1 : 0;

    const emptyStars = 5 – fullStars – halfStars;

    // Express stars as arrays to make iterating in Handlebars easy.

    place.fullStarIcons = initArray(fullStars);

    place.halfStarIcons = initArray(halfStars);

    place.emptyStarIcons = initArray(emptyStars);

    }

    if (place.price_level) {

    place.dollarSigns = initArray(place.price_level);

    }

    if (place.website) {

    const url = new URL(place.website);

    place.websiteDomain = url.hostname;

    }

    context.place = place;

    renderDetails(context);

    }

    });

    }

    renderDetails(context);

    hideElement(locator.panelListEl);

    showElement(panelDetailsEl);

    };

    }

    const CONFIGURATION = {

    “locations”: [

    {“title”:”Houri Hearing Dubai”,”address1″:”1079 Al Wasl Road”,”address2″:”Dubai, United Arab Emirates”,”coords”:{“lat”:25.141332,”lng”:55.2055273},”placeId”:”ChIJi-WHbi9rXz4R8q8yr5OQbKc”},

    {“title”:”Houri Hearing Abu Dhabi”,”address1″:”108 Khalifa Bin Zayed the First Street”,”address2″:”Abu Dhabi, United Arab Emirates”,”coords”:{“lat”:24.486016,”lng”:54.353355},”placeId”:”ChIJX4AO1TxnXj4Rf5JYVj6ajhc”}

    ],

    “mapOptions”: {“center”:{“lat”:38.0,”lng”:-100.0},”fullscreenControl”:true,”mapTypeControl”:false,”streetViewControl”:false,”zoom”:4,”zoomControl”:true,”maxZoom”:17,”mapId”:””},

    “mapsApiKey”: “AIzaSyBHEKF9g1xfeLqnzSHhYUoQMNjv1CEPAGU”,

    “capabilities”: {“input”:true,”autocomplete”:true,”directions”:true,”distanceMatrix”:true,”details”:true,”actions”:false}

    };

    function initMap() {

    new LocatorPlus(CONFIGURATION);

    }

    {{#each locations}}

  • {{address1}}
    {{address2}}

    {{#if travelDistanceText}}

    {{travelDistanceText}}

    {{/if}}

  • {{/each}}

    {{location.title}}

    {{#if location.travelDistanceText}}

    {{location.travelDistanceText}} away

    {{/if}}

    {{location.address1}}

    {{location.address2}}

    {{#if place.rating}}

    {{place.rating}}

    {{#each place.fullStarIcons}}

    {{/each}}

    {{#each place.halfStarIcons}}

    {{/each}}

    {{#each place.emptyStarIcons}}

    {{/each}}

    {{/if}}

    {{#if place.user_ratings_total}}

    {{place.user_ratings_total}} reviews

    {{else}}

    See on Google Maps

    {{/if}}

    {{#if place.price_level}}

    {{#each place.dollarSigns}}${{/each}}

    {{/if}}


    {{#if place.opening_hours}}

    Opening hours

    {{#each place.openingHoursSummary}}

    {{days}}

    {{hours}}

    {{/each}}

    {{/if}}

    {{#if place.website}}

    {{/if}}

    {{#if place.formatted_phone_number}}

    Phone number

    {{place.formatted_phone_number}}

    {{/if}}

    {{#if place.html_attributions}}

    {{#each place.html_attributions}}

    {{{this}}}

    {{/each}}

    {{/if}}

    Find a location near you

    All locations