Google Maps Customization

JavaScript Web Development

Demo: link Sources: link

Working for the first time on the implementation and customization of Google Maps I couldn’t find any article to contain the whole scope of information and details, so I had to glean information on this issue, but mostly to come up with my own ideas. Afterwards I decided to write this article for those who have either no experience of working on styling Google Maps and their customization or lack time (or maybe lack the will) to learn API perfectly, thus making it easier for them to find information on the issue. I also hope that even old-hands might also find some ideas of the article helpful, particularly parallax-effect for information window’s elements.

The article covers the following issues:

1. Embedding of Google Maps on web sites

  • adding to layout via iframe insertion
  • adding via API

2. Marker customization

  • Marker initialization
  • Marker animation
  • Marker image

3. Information window customization

  • Adding an information window
  • Opening an information window
  • Customisation of the elements of the information window
  • Parallax-effect for information window’s elements.

4. Map Customization

  • Changing map objects’ colors
  • Customization of controls
  • Map masks

1. Embedding on web site

Adding to layout via iframe insertion

Given you don’t need to alter a marker, create a customized information window or do whatever else manipulation with a map, in order to insert it, you can do the following:

• Open Google Maps • Find the necessary object on the map (type the address in the search box, or choose from the right-click menu “What’s Here?”)

• then click on the hamburger button.

• Then find the “Share or embed map” button

• Copy code for pasting

• Paste the code in the layout

Adding via API

But given any manipulation is necessary, you’ll need the key. If it’s not immediately at hand, you can get it here: link

Insert it into the address instead of YOUR_API_KEY:

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>

If callback is needed after loading api, type YOUR_API_KEY&callback=initMap after the key. Add script in the page and create a block in the layout for the prospective map:

<div id="map"></div>

Now it’s necessary to initialize the map.

function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},
    
        map = new google.maps.Map(document.getElementById('map'), {
            center: coordinates
        });
}

You can find coordinates using “What’s Here” option (see above).

You may need the following features:

  • zoom: number – enables zoom
  • disableDefaultUI: boolean – disables UI controls
  • scrollwheel: boolean – disables mouse-wheel zoom (maybe helpful in case of a full-page map, disabling scroll down)

2. Customization of marker

Marker initialization

For starters add the marker:

function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},

        map = new google.maps.Map(document.getElementById('map'), {
            center: coordinates
        }),
    
        marker = new google.maps.Marker({
            position: coordinates,
            map: map
        });
}

Position (a must) points to the initial position of the marker. If the coordinates for the marker are the same as for the map, the marker will be in the center of the screen. Changing marker’s position is possible either by changing coordinates, or the map itself in the visible area (parental block).

map (not a must) points to the map, which the marker is on.

Marker animation

It’s possible to animate the marker:

  • DROP – After map downloading the marker drops upside down
  • BOUNCE – The marker bounces at one place.
function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},

        map = new google.maps.Map(document.getElementById('map'), {
            center: coordinates
        }),

        marker = new google.maps.Marker({
            position: coordinates,
            map: map,
            animation: google.maps.Animation.BOUNCE
        });
}

Animation can be set during marker initialization, enabled or disabled, using method setAnimation().

An example of enabling marker animation when the information window is closing, and disabling it when the information window is opening:

google.maps.event.addListener(infowindow,'closeclick',function(){
    marker.setAnimation(google.maps.Animation.BOUNCE);
});

marker.addListener('click', function () {
    marker.setAnimation(null);
});

Marker image

It’s possible to change marker images by setting the address of the picture for the icon feature.

image = 'images/marker.png',
marker = new google.maps.Marker({
    position: coordinates,
    map: map,
    icon: image
});

3. Customization of information window

Adding the information window

It’s possible to add any layout to a customized information window via the content feature:

function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},
        popupContent = '<p class="content">Что угодно</p>',
        markerImage = 'images/marker.png',

        map = new google.maps.Map(document.getElementById('map'), {
            center: {lat: 47.212325, lng: 38.933663}
        }),

        marker = new google.maps.Marker({
            position: coordinates,
            map: map,
            icon: markerImage
        }),

        infowindow = new google.maps.InfoWindow({
            content: popupContent
        });
}

Opening the information window

In order to get the information window immediately visible it’s necessary to use the method open():

infowindow.open(map, marker);

It’s also necessary to add information window opening while clicking on the marker (otherwise it will be impossible to open popup):

marker.addListener('click', function() {
    infowindow.open(map, marker);
});

Customisation of the elements of the information window

An information window can be both customized and standard. The former allows us adding and working with any elements, with the capabilities depending only on our creativity. The main problem you can face customizing a window is edges (white area) surrounding the content, alongside an arrow. These elements are not the subject to css selection.

However, it’s possible to resolve this problem using pseudo-elements for accessible blocks. If, for some reasons, using a pseudo-element is impossible, a frame can be eliminated using a shadow.

.gm-style-iw {
  background: $black;
  box-shadow: -14px 0px 0px $black, -14px 9px 0px $black, -14px -8px 0px $black, 15px -8px 0px $black, 15px 9px 0px $black;
}

Let’s see this in detail:

.gm-style-iw — the main block with the content. In the upper screenshot this block has a black background. .poi-info-window — A wrapper for the text in a standard information window. It’s inside .gm-style-iw .gm-style-iw + div – a cross

The question is: how can we affect the area outside the content block? The answer is: get beyond the block by adding a feature making the block beyond the boundaries visible:

.gm-style-iw {
  overflow: visible !important;

  div {
    overflow: visible !important;
  }
}

As a result, for .gm-style-iw or the block inside it’s possible to create pseudo-elements to handle the background and the arrow:

.gm-style-iw {
  // background
  &::before {
    content: '';
    width: calc(100% + 29px);
    height: calc(100% + 17px);
    @include absolute;
    @include center-align;
    background: $black;
  }
  
  // arrow
  &::after {
    content: '';
    width: 0;
    height: 0;
    border: 22px solid transparent;
    border-top-color: $black;
    z-index: 4;
    @include absolute;
    top: auto;
    bottom: -53px;
    margin: auto;
  }
}

Here we are:

Parallax-effect for the elements of the information window

Yet, there is a minor problem resulting from dynamic character of maps’ objects, and it’s impossible to solve it just by simply adding listeners. As for cloning the block using .clone(true) in the content of the information window and moving the listeners, it’s API that makes it impossible.

As an option, you can keep searching for the element and save it when it appears:

var $parallaxImg  = null;
this.$body.mousemove(function(e) {
    if($parallaxImg) {
        ...
    } else if($(this.parallaxImg).length) {
        $parallaxImg = $(this.parallaxImg);
    }
}.bind(this));

Now we just add the code, which enables horizontal shifting of the block depending on the cursor’s position:

var $parallaxImg  = null;

this.$body.mousemove(function(e) {
    if($parallaxImg) {
        var $el    = $(e.currentTarget),
            xPos   = e.pageX - (window.innerWidth / 2),
            mXPcnt = Math.round(xPos / $el.width() * 100),
            diffX  = $parallaxImg.width() - $el.width(),
            myX    = diffX * (mXPcnt / 1500);

        $parallaxImg.animate({left: myX}, 0);
    } else if($(this.parallaxImg).length) {
        $parallaxImg = $(this.parallaxImg);
    }
}.bind(this));

Should the click on a dynamic element be handled, we simply put a listener on the wrapper and “catch” the object on surfacing:

$('.map').on('click', '.js-parallax-img', function() {
    ...
});

4. Map customization

Changing map objects’ colors

For map styling we use an array of different styles, pointing to a selector and the css feature to be applied.

Here is an example of the settings, which allow making the color of the water violet.

var styles = [
        {
            "featureType": "water",
            "stylers": [
                {
                    "color": "#a73cff"
                }
            ]
        }
    ]

Parameters applied:

map.setOptions({styles: styles});

Working with styles, it’s better to use specialized services, for instance Google Maps APIs Styling Wizard. In order to get a map in more detail click “More options.”

Making settings:

Copying obtained json:

If the array of styles is too big, it can be put in a separate .json file and apply styles after its loading:

$.getJSON("../json/map-style/map-style.json", function(data) {
    map.setOptions({styles: data});
});

Eventually, we get the following map settings:

var coordinates = {lat: 47.212325, lng: 38.933663},
    popupContent = this.$popupContent.html(),
    markerImage = 'images/marker.png',
    zoom = 15,

    map = new google.maps.Map(document.getElementById('map'), {
        center: coordinates,
        zoom: zoom,
        disableDefaultUI: true
    }),

    infowindow = new google.maps.InfoWindow({
        content: popupContent
    }),

    marker = new google.maps.Marker({
        position: coordinates,
        map: map,
        icon: markerImage
    });

$.getJSON("../json/map-style/map-style_colored.json", function(data) {
    map.setOptions({styles: data});
});

google.maps.event.addListener(infowindow,'closeclick',function(){
    marker.setAnimation(google.maps.Animation.BOUNCE);
});

marker.addListener('click', function () {
    marker.setAnimation(null);
});

marker.addListener('click', function() {
    infowindow.open(map, marker);
});

infowindow.open(map, marker);

Customization of control elements

Buttons “Map” and “Satellite” are in the block class .gm-style-mtc

Zoom buttons are in the block class .gmnoprint

“View streets” button is in class .gm-svpc

Using these classes you can do whatever you want with the control elements. In this example I hid the control elements, but changed the color.

.gm-style-mtc > div,
.gmnoprint > div,
.gm-svpc {
  background-color: #f63981 !important;
}

Map mask

And for dessert here is a very simple thing, which, however, may be a discovery for somebody. In general, it’s a full-map-size block, either as an image or with a background. Feature mask-image is also available, but it works not in all browsers. The point to remember is css’ property pointer-events, which on the mask must have “none” value, thus allowing skipping this block in mouse events (simply speaking clicking and scrolling).

So the quick start of Google Maps is completed. I hope this article to be helpful for you. You can find source here: GitHub

Comments

1,128

Ropes — Fast Strings

Most of us work with strings one way or another. There’s no way to avoid them — when writing code, you’re doomed to concatinate strings every day, split them into parts and access certain characters by index. We are used to the fact that strings are fixed-length arrays of characters, which leads to certain limitations when working with them. For instance, we cannot quickly concatenate two strings. To do this, we will at first need to allocate the required amount of memory, and then copy there the data from the concatenated strings.