さくっとGoogleマップをカスタマイズしよう!【サンプル有り】

,

こんにちは、katori@xxbicotです。

2018/6にGoogle Maps APIのAPI群の構成や料金プラン等が変わったのをご存知でしょうか?
私は一切Google Maps APIに触ったことがなかったので「へ〜」という感じだったんですが、このタイミングで初めてのGoogle Mapのカスタマイズ案件が。

使ってみたところさくっとデザイン・マーカー変更ができて楽しかったので、覚書きがてらまとめてみました。
変更された料金プランについても触れるので、参考にどうぞ!

料金について

今回のアップデートにより、スタンダードプラン/プレミアムプランという区分がなくなり一本化されました。

今後は、必ず最初に請求情報を登録した上で

  • 月200ドルを超えた分だけ請求されるようになる(全API利用金額の合計)
  • 逆に言えば、200ドル分以下であれば無料
  • 金額はAPIによって異なる

という体系になるとのこと。

ピンと来なかったので、地図・マーカーのデザインカスタマイズで使用するMaps JavaScript API(Dynamic Maps)に限定して無料で使える範囲を確認したところ、こんな感じのようです。

従来 1日2万5000リクエストまで無料
アップデート後 月間2万8000リクエストまで無料
= 1日平均933リクエスト

引用元)6月11日以降、Google Maps APIによる地図表示が薄暗くなる/エラーになるケースも――「Google Maps Platform」移行で何が変わる?

これ、前から使ってた人にとってはだいぶシビアになったような。。

1日1000リクエスト未満となると個人のサイトでも厳しい場合がありそうなので、注意した方が良さそうです。

課金を防ぐ設定をする

今回は確実に課金させないようにしたかったので、以下のような設定をしてみました。

  1. リクエストの上限値設定
    「API」からMaps JavaScript API(Dynamic Maps)を選択、Map loads per day 933へ変更
    →Dynamic Mapsは1日933リクエスト以下なら無料のため
  2. 使わないAPIを無効化
    「API」から使用しないAPIを選択、無効へ変更
    →リクエストの上限値設定はAPIごとに行うので、うっかり上限設定してないAPIを使ってうっかり無料回数超えちゃった!という事故を防ぐため
  3. API キーの保護
    「認証情報を保護」ボタンから、使用するリファラー(サイト)を指定
    →他の人にAPIキーを使われてた!ということを防ぐため

多分これで無料範囲超えることはないはず(ふんわり

設定したら、登録時に取得できるAPIキーを使ってカスタマイズに入ります。

カスタマイズ方法

API読み込み

取得したAPIキーを使って、まずはAPIを読み込みます。

<script async defer src="https://maps.googleapis.com/maps/api/js?key=APIキー&callback=initMap"></script>

ここで「initMap」という関数をcallbackパラメータで呼び出していますが、これは任意の関数名でOK。
定義した名前の関数を用意して、そこにカスタマイズ内容を書いていきます。

スタイル変更・マーカーの設置

地図のデザインとオリジナル画像のマーカーを設置します。

DEMO

var map;
function initMap() {

map = new google.maps.Map(document.getElementById('map'), {
  zoom: 15,
  center: new google.maps.LatLng(35.681189, 139.767055),
  mapTypeId: 'roadmap',
  //地図デザインの設定
  styles: [ {
	        "featureType": "administrative",
	        "elementType": "labels.text.fill",
	        "stylers": [ { "color": "#6195a0" } ]
	    },{
	        "featureType": "landscape",
	        "elementType": "all",
	        "stylers": [ { "color": "#f2f2f2" } ]
	    },{
	        "featureType": "landscape",
	        "elementType": "geometry.fill",
	        "stylers": [ { "color": "#ffffff" } ]
	    },{
	        "featureType": "poi",
	        "elementType": "all",
	        "stylers": [ { "visibility": "off" } ]
	    },{
	        "featureType": "poi.park",
	        "elementType": "geometry.fill",
	        "stylers": [ { "color": "#e6f3d6" },{ "visibility": "on" } ]
	    },{
	        "featureType": "road",
	        "elementType": "all",
	        "stylers": [ { "saturation": -100 },{ "lightness": 45},{ "visibility": "simplified" } ]
	    },{
	        "featureType": "road.highway",
	        "elementType": "all",
	        "stylers": [ { "visibility": "simplified" } ]
	    },{
	        "featureType": "road.highway",
	        "elementType": "geometry.fill",
	        "stylers": [ { "color": "#f4d2c5" }, { "visibility": "simplified" } ]
	    },{
	        "featureType": "road.highway",
	        "elementType": "labels.text",
	        "stylers": [ { "color": "#4e4e4e" } ]
	    },{
	        "featureType": "road.arterial",
	        "elementType": "geometry.fill",
	        "stylers": [ { "color": "#f4f4f4" } ]
	    },{
	        "featureType": "road.arterial",
	        "elementType": "labels.text.fill",
	        "stylers": [ { "color": "#787878" } ]
	    },{
	        "featureType": "road.arterial",
	        "elementType": "labels.icon",
	        "stylers": [ { "visibility": "off" } ]
	    },{
	        "featureType": "transit",
	        "elementType": "all",
	        "stylers": [ { "visibility": "off" } ]
	    },{
	        "featureType": "water",
	        "elementType": "all",
	        "stylers": [ { "color": "#eaf6f8"
	            },{ "visibility": "on" } ]
	    },{
	        "featureType": "water",
	        "elementType": "geometry.fill",
	        "stylers": [ { "color": "#eaf6f8" } ]
	    }
	] 
});

//マーカーの設定
var iconBase = '';
var marker = new google.maps.Marker({
    position: new google.maps.LatLng(35.681189, 139.767055),
    icon: { url: iconBase + 'pin.png', scaledSize : new google.maps.Size(48, 62) },
    map: map,
    title: 'Tokyo!'
});
}

スタイルの変更

google.maps.Map」は地図の生成を行います。デザインに関する設定は9行目〜71行目のstyles: [〜]の部分。

めっちゃ長いし難しそう(;・`д・́)…ゴクリ

と最初思いましたが、こちらのスタイルギャラリーを使うと一瞬でおしゃれな地図デザインセットのコードをゲットできます。

SNAZZY MAPS

イメージに近いデザインセットを選んだり、ちょっと違うな〜という時はそのデザインセットをプレビューで見ながらカスタマイズということもできます!便利すぎる!

マーカーの設置

google.maps.Marker」がマーカーの生成&設定です。

icon: {〜}でオリジナル画像や画像サイズを指定できます。ただそれ自体は必須ではないので、iconを指定しなければ以下のようなデフォルトのマーカー画像になります。

お馴染みのマーカー

応用編(1)マーカー複数の場合&高画質対応

DEMO

マーカーを複数設置したい、またマーカーを高画質対応にしたい場合は、マーカー設定を以下のように変更します。

var iconBase = '';
var icons = [
  {
    name: 'Tokyo!',
    position: new google.maps.LatLng(35.681189, 139.767055),
    img: { url: iconBase + 'pin.png', scaledSize : new google.maps.Size(48, 62) }
  },
  {
    name: 'Nihonbashi!',
    position: new google.maps.LatLng(35.682201, 139.774673),
    img: { url: iconBase + 'pin2.png', scaledSize : new google.maps.Size(36, 46) }
  },
  {
    name: 'Otemachi!',
    position: new google.maps.LatLng(35.686018, 139.763438),
    img: { url: iconBase + 'pin3.png', scaledSize : new google.maps.Size(36, 46) }
  }
];
icons.forEach(function(icon) {
  var marker = new google.maps.Marker({
    position: icon.position,
    icon: icon.img,
    map: map,
    title: icon.name
  });
});

ピンの情報を用意してあげて、1つ1つgoogle.maps.Markerで生成・配置していきます。

高画質対応に関しては「scaledSize」に表示したいサイズを指定し、その3倍の元画像を用意すればOK。
サイズの自由が効くので、特定のピンだけ少し大きめにして差別化したいって時も、わざわざ別画像を用意せず対応できます。

応用編(2)クリックで説明ボックス表示&言語切り替え

DEMO

説明表示

マーカー設定あたりに、説明文をいれた配列(ここれはsecretMessages)を用意してマーカーに紐づけます。

var secretMessages = ['Tokyo! text text text', 'Nihonbashi! text text text', 'Otemachi! text text text'];
icons.forEach(function(icon,index) {
  var marker = new google.maps.Marker({
    position: icon.position,
    icon: icon.img,
    map: map,
    title: icon.name
  });
  attachSecretMessage(marker, secretMessages[index]);
});
//initMap()の外に追加
function attachSecretMessage(marker, secretMessage) {
	var infowindow = new google.maps.InfoWindow({
		content: secretMessage
	});

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

言語切り替え

読み込むAPIのパラメータを変更します。

<script async defer src="https://maps.googleapis.com/maps/api/js?key=APIキー&callback=initMap&language=en"></script>

この「language=en」のen部分を表示させたい言語に変えればOKです。

追記7/11:  応用編(3)ポリゴン表示(&領域内クリックで説明ボックス表示)

DEMO

ポリゴンなる存在を教えていただいたので試したところ、お手軽に実装できたので追記。(ママケさん@_m_a_m_a_k_e_、有難うございました!)

ポリゴン“は多角形を地図上に表示させることができます。これもDynamic Mapsで実装可能です。

マーカー設定の下に以下の記述を追加します。

// initMap()内
var patharray = new Array();	// 多角形の頂点の座標を指定
patharray[0] = new google.maps.LatLng(35.681189, 139.767055);
patharray[1] = new google.maps.LatLng(35.682201, 139.774673);
patharray[2] = new google.maps.LatLng(35.686018, 139.763438);
var polygonOpts = {
    map: map,
    paths: patharray,
    fillColor: "#77984c",	//塗りつぶし色
    fillOpacity: 0.20,		//塗りつぶし透明度
    strokeColor: "#77984c",	//線色
    strokeOpacity: 0.5,		//線透明度
    strokeWeight: 2			//線太さ(px)
};
var polygon = new google.maps.Polygon(polygonOpts);

polygon.addListener('click', showArrays);
infoWindow = new google.maps.InfoWindow;
// initMap()の外に追加
function showArrays(event) {
    var vertices = this.getPath();

    var contentString = '<b>ポリゴン内だよ!</b><br>' +
        '緯度: ' + event.latLng.lat() + ',<br>経度' + event.latLng.lng();
        
    infoWindow.setContent(contentString);
    infoWindow.setPosition(event.latLng);

    infoWindow.open(map);
}

今回は立てたマーカーを座標にして三角形を作ってますが、多角形はマーカーの位置とは関係なく作れます。
patharrayに座標を追加していけばより精密に領域指定をすることもできます。

ものすごく便利な気がするけどどういう時に使えるんだろう、と思ったところ、イベント系のエリア表示等に使われるとのこと。
確かにめちゃくちゃ便利だ…(°Д°

ちなみにポリゴンを利用したアニメーションを実装されてる方もいらっしゃいました。

クリックした地点を中心に円が広がっていくアニメーションです。
Googleマップでこんな動きができるとワクワクしますね!

まとめ

以上、Googleマップカスタマイズ方法を簡単にまとめてみました。

使って見た感想としては、Google Maps APIは公式でもわかりやすい使い方ガイドがあるし、デザインセットを共有できるSNAZZY MAPSもあるしで、わりと手軽に導入できるなぁという印象でした。

請求情報の登録があるので精神的ハードルは高めですが、無料で使うための設定だけちゃんとすればきっと問題ないはず(ふんわり

また今回でGoogle Maps APIの種類がたくさんあることを初めて知ったので、今後色々試していきたいと思います。