Making Multiple Style References in Google Maps API

Making Multiple Style References In Google Maps API

I think this is a combination of poor documenation, plus a bug in ggmap.

Explanation

If you look at the example on Google Documentation you see that styles are separated by &style=

&style=feature:road.local%7Celement:geometry%7Ccolor:0x00ff00&style=feature:landscape%7Celement:geometry.fill%7Ccolor:0x000000&style=element:labels%7Cinvert_lightness:true

So in your example, if you wanted your two styles

style1 <- c(feature = "poi.medical", element = "geometry", color = "red")
style2 <- c(feature = "poi.park", element = "geometry", color = "blue")

This woud look something like

&style=feature:poi.medical|element:geometry|color:red&style=feature:poi.park|element:geometry|color:blues

In ?get_googlemap, for the style argument it says

character string to be supplied directly to the api for the style argument or a named vector (see examples)

And in the source code we see that it can also supposedly handle lists. So if we create a list out of our styles we get

style <- list(style1, style2)

Which, when run through the get_googlemap gives the url

map <- get_googlemap("new york city", 
zoom = 12,
maptype = "roadmap",
style = style)

...&style=style=c(%22poi.medical%22,%20%22geometry%22,%20%22red%22)&style=c(%22poi.park%22,%20%22geometry%22,%20%22blue%22)&sensor=false

Which is also incorrect.

And similarly for a concatenated vector of styles we get an incorrectly formatted URL

style <- c(style1, style2)

map <- get_googlemap("new york city",
zoom = 12,
maptype = "roadmap",
style = style)

...&style=feature:poi.medical%7Celement:geometry%7Ccolor:red%7Cfeature:poi.park%7Celement:geometry%7Ccolor:blue&sensor=false

Solution

Force it to use a &sytle= value as the first (unnamed) element in the 2nd (and subsequent) style vector, and concatenate them using c(), rather than list()

style1 <- c(feature = "poi.medical", element = "geometry", color = "red")
style2 <- c("&style=", feature = "poi.park", element = "geometry", color = "blue")

style <- c(style1, style2)

map <- get_googlemap("new york city",
zoom = 12,
maptype = "roadmap",
style = style)

plot(map)

Sample Image


And now a separate plug for my gooleway package, where you can specify the style using JSON, and the map is interactive

library(googleway)

style <- '[{"featureType": "poi.park","elementType": "geometry","stylers": [{"color": "#00FF00"}]},{"featureType":"poi.medical","elementType":"geometry","stylers":[{"color":"#FF00FF"}]}]'

map_key <- "you_need_an_api_key"

google_map(key = map_key, location = c(40.7128, -74.0059),
zoom = 13, height = 800,
styles = style)

Stacking Map Styles (Google Maps API)

// create a variable for the element you want an option for
var styleOptionCityLabels = {
featureType: 'administrative',
elementType: 'labels',
stylers: [{'visibility': 'on'}]
};

// create a variable for your map styles that pulls any option variables you have
var mapStyle = [styleOptionCityLabels];

// get the checkbox element you want to control your toggle
var cityCheck = $('#city-labels-checkbox');

// apply a click listener to the box
cityCheck.on('click', function(){

// check if the box is checked
if ($(cityCheck).is(':checked')) {

// change the desired style
styleOptionCityLabels.stylers = [{'visibility': 'on'}];
} else {

// change the desired style
styleOptionCityLabels.stylers = [{'visibility': 'off'}];
}

// call the setOptions method to reload the altered styles
map.setOptions({styles: mapStyle});
});

google maps multiple custom markers with numbers referencing to item in list

Instead of a Marker you may create a custom overlay

It will give you the option to use HTML, via CSS it's not difficult to create an element that is styled like your example-images.

A possible implementation:

function HtmlMarker(map,position,content,cssText){
this.setValues({
position:position,
container:null,
content:content,
map:map,
cssText:cssText
});

this.onAdd = function() {
var that = this,container = document.createElement('div'),
content = this.get('content'),
cssText = this.get('cssText')
||'border-color:#fff;background:#fff;color:#000;';
container.className='HtmlMarker';
container.style.cssText = cssText;

google.maps.event.addDomListener(container,'click',
function(){google.maps.event.trigger(that,'click');});
if(typeof content.nodeName!=='undefined'){
container.appendChild(content);
}
else{
container.innerHTML=content;
}

container.style.position='absolute';
this.set('container',container)
this.getPanes().floatPane.appendChild(container);
}

this.draw=function(){
var pos = this.getProjection()
.fromLatLngToDivPixel(this.get('position')),
container = this.get('container');
container.style.left = pos.x - (container.offsetWidth/2)+ 'px';
container.style.top = pos.y - (container.offsetHeight) + 'px';
}

this.onRemove = function() {
this.get('container').parentNode.removeChild(this.get('container'));
this.set('container',null)
}
}

The overlay-div will have the className HtmlMarker , use this class to apply the basic layout:

  .HtmlMarker {
font-size:18px;
margin-top:-6px;/*!*/
padding: 4px 10px;
position: relative;
display:inline-block;
cursor:pointer;
}
.HtmlMarker:after {
position: absolute;
display: inline-block;
border-bottom: 6px solid transparent;/*!*/
border-top: 6px solid;/*!*/
border-top-color:inherit;
border-right: 6px solid transparent;/*!*/
border-left: 6px solid transparent;/*!*/
left: 50%;
margin-left:-6px;/*!*/
top:100%;
content:'';
}

The 6px/-6px in the properties marked with the /*!*/ define the size of the tip, when you modify the size you must modify all these values.

The first 3 arguments of HtmlMarker() (map,position,content) should be self-explaining.
The 4th argument cssText expects a cssText that gives you the option to apply custom CSS.

To define a background-color you must set background and border-color to the same value:, e.g.:

border-color:white;background:white;

more properties may be added when you want to, but basically you may use the stylesheet to apply more styles(except the color, this value of course should be compatible with the background)

A click-event is already implemented, more features are possible too, e.g. a draggable-option.

Demo: http://jsfiddle.net/doktormolle/5arST/

style multiple GeoJson files with the Google Maps Javascript API v3 data layer

I have created a demo on github where I load polygons (boundaries) using Data Layer and I also show how to keep reference to respective polygons and update their specific styles. Check out this SO answer for a snippet (I don't want to copy it here, because it's redundant).

Notice mainly: new_boundary.feature = data_layer.getFeatureById(boundary_id); where I store reference to specific feature, which styles I can update anytime using e.g.:

data_layer.overrideStyle(new_boundary.feature, {
fillColor: '#0000FF',
fillOpacity: 0.9
});

And it would just update that one polygon, not all of them. So if your polygons in geoJSON files have some unique ids, or you can assign ids to all of them, you can then reference and change their styles based on that.

Another option, not shown in the example is, to have multiple data layers. It's possible to have multiple data layers in your application, e.g. create them like this:

var data_layer = new google.maps.Data({map: map});
var data_layer_2 = new google.maps.Data({map: map});

and then load data to them and change styles:

data_layer.loadGeoJson(
'https://storage.googleapis.com/mapsdevsite/json/google.json');
data_layer_2.loadGeoJson(
'https://storage.googleapis.com/mapsdevsite/json/google.json');
data_layer.setStyle({
fillColor: 'green',
strokeWeight: 1
});
data_layer_2.setStyle({
fillColor: 'blue',
strokeWeight: 2
});

styling of google map

https://mapstyle.withgoogle.com/ is just a tool that helps you create the JSON you need to style your map implementation.

You should read the style reference guide.

The easiest implementation is as follow. The JSON style you exported goes in the styles property of the MapOptions object.

var map;
function initialize() {
// Map Style JSON var blueStyle = [{ 'featureType': 'all', 'elementType': 'labels', 'stylers': [{ 'visibility': 'off' }] }, { 'featureType': 'road', 'elementType': 'labels.icon', 'stylers': [{ 'visibility': 'off' }] }, { 'stylers': [{ 'hue': '#00aaff' }, { 'saturation': -50 }, { 'gamma': 1.15 }, { 'lightness': 12 }] }, { 'featureType': 'road', 'elementType': 'labels.text.fill', 'stylers': [{ 'visibility': 'on' }, { 'lightness': 24 }] }, { 'featureType': 'road', 'elementType': 'geometry', 'stylers': [{ 'lightness': 85 }] }];
var mapOptions = { center: new google.maps.LatLng(52.368465, 4.903921), zoom: 10, styles: blueStyle };
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);}
initialize();
#map-canvas {  height: 200px;}
<div id="map-canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js?callback=initialize" async defer></script>

Google Maps JS API v3 - Simple Multiple Marker Example

This is the simplest I could reduce it to:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Google Maps Multiple Markers</title>
<script src="http://maps.google.com/maps/api/js?key=YOUR_API_KEY"
type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 500px; height: 400px;"></div>

<script type="text/javascript">
var locations = [
['Bondi Beach', -33.890542, 151.274856, 4],
['Coogee Beach', -33.923036, 151.259052, 5],
['Cronulla Beach', -34.028249, 151.157507, 3],
['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
['Maroubra Beach', -33.950198, 151.259302, 1]
];

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: new google.maps.LatLng(-33.92, 151.25),
mapTypeId: google.maps.MapTypeId.ROADMAP
});

var infowindow = new google.maps.InfoWindow();

var marker, i;

for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
});

google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
}
</script>
</body>
</html>

‍ Edit/fork on a Codepen →

SCREENSHOT

Google Maps Multiple Markers

There is some closure magic happening when passing the callback argument to the addListener method. This can be quite a tricky topic if you are not familiar with how closures work. I would suggest checking out the following Mozilla article for a brief introduction if it is the case:

❯ Mozilla Dev Center: Working with Closures



Related Topics



Leave a reply



Submit