はじめに
オーバーレイは緯度と経度で表される座標に紐付いたマップ上のオブジェクトで、マップをドラッグしたりズームしたりすると連動して動きます。あらかじめ定義されているオーバーレイのタイプについては、マップ上に描画するで詳細をご覧ください。
Google Maps JavaScript API の OverlayView クラスを使うと、独自のカスタム オーバーレイを作成できます。OverlayView は基本クラスで、このクラスにはオーバーレイの作成時に実装する必要のある複数のメソッドが含まれています。また、画面上の座標とマップ上の位置を変換するメソッドもあります。
カスタム オーバーレイを追加する
カスタム オーバーレイを作成する手順の概要は次のとおりです。
- カスタム オーバーレイ オブジェクトの
prototypeをgoogle.maps.OverlayView()の新しいインスタンスに設定します。これにより、オーバーレイ クラスがサブクラス化されます。 - カスタム オーバーレイ用のコンストラクタを作成し、すべての初期化パラメータを設定します。
- プロトタイプ内に
onAdd()メソッドを実装し、オーバーレイをマップに貼り付けます。マップにオーバーレイを追加できる状態になると、OverlayView.onAdd()が呼び出されます。 - プロトタイプ内に
draw()メソッドを実装し、オブジェクトの表示処理を行います。オブジェクトが初めて表示されるときに、OverlayView.draw()が呼び出されます。 onRemove()メソッドを実装して、オーバーレイに追加したすべての要素を削除する必要もあります。
以下で各ステップの詳細を説明します。実際に動作するサンプルを、こちらで確認することもできます。例を見る(overlay-simple.html)
オーバーレイをサブクラス化する
以下の例では、OverlayView を使って単純なイメージ オーバーレイを作成しています。
// This example creates a custom overlay called USGSOverlay, containing
// a U.S. Geological Survey (USGS) image of the relevant area on the map.
// Set the custom overlay object's prototype to a new instance
// of OverlayView. In effect, this will subclass the overlay class therefore
// it's simpler to load the API synchronously, using
// google.maps.event.addDomListener().
// Note that we set the prototype to an instance, rather than the
// parent class itself, because we do not wish to modify the parent class.
var overlay;
USGSOverlay.prototype = new google.maps.OverlayView();
// Initialize the map and the custom overlay.
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 11,
center: {lat: 62.323907, lng: -150.109291},
mapTypeId: 'satellite'
});
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(62.281819, -150.287132),
new google.maps.LatLng(62.400471, -150.005608));
// The photograph is courtesy of the U.S. Geological Survey.
var srcImage = 'https://developers.google.com/maps/documentation/' +
'javascript/examples/full/images/talkeetna.png';
// The custom USGSOverlay object contains the USGS image,
// the bounds of the image, and a reference to the map.
overlay = new USGSOverlay(bounds, srcImage, map);
}
ここで USGSOverlay クラス用のコンストラクタを作成し、新しいオブジェクトのプロパティとして渡されたパラメータを初期化します。
/** @constructor */
function USGSOverlay(bounds, image, map) {
// Initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay.
this.setMap(map);
}
オーバーレイ コンストラクタでは、このオーバーレイをまだマップに貼り付けできません。まずは、マップへのオブジェクトの表示順序を指定するマップペインが、すべて利用可能であることを確認する必要があります。API には、これを確認できるヘルパー メソッドがあります。次のセクションでは、そのメソッドの扱いについて説明します。
オーバーレイを初期化する
オーバーレイが最初にインスタンス化され、表示できる状態になったら、ブラウザの DOM を介してマップに貼り付ける必要があります。API はオーバーレイの onAdd() メソッドを呼び出すことで、オーバーレイがマップに追加されたことを示します。このメソッドを扱うには、イメージを保持する <div> を作成して、<img> 要素を追加します。これを <div> に貼り付けて、オーバーレイをマップのペインの 1 つに貼り付けます。なお、ペインとは DOM ツリーのノードです。
MapPanes タイプのペインは、マップ上にレイヤを重ねる順番を指定します。以下のペインを利用でき、先に示してあるペインほど下側に積み重ねられます。
mapPaneは最下層のペインでタイルの上にあります。DOM イベントを受け付けない場合があります。(ペイン 0)overlayLayerにはポリラインやポリゴン、地面オーバーレイとタイル レイヤ オーバーレイが含まれます。DOM イベントを受け付けない場合があります。(ペイン 1)overlayImageにはマーカーの影が含まれます。DOM イベントを受け付けない場合があります。(ペイン 2)overlayImageにはマーカーの前景画像が含まれます。(ペイン 3)floatShadowには情報ウィンドウの影が含まれます。このペインはoverlayImageの上にあるので、マーカーは情報ウィンドウの影の中に表示されることがあります。(ペイン 4)overlayMouseTargetには、透明なマーカー用のターゲットなど、DOM のマウスイベントを受け付ける要素が含まれます。このペインはfloatShadowの上にあるので、マーカーが情報ウィンドウの影の中に表示されていてもクリックできます。(ペイン 5)floatPaneには情報ウィンドウが含まれます。このペインはマップ オーバーレイの中で最も上にあります。(ペイン 6)
ここでは「地面オーバーレイ」の画像を表示するので、overlayLayer ペインを使います。このペインを取得したら、オブジェクトを子として貼り付けます。
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.borderStyle = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
img.style.position = 'absolute';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayLayer" pane.
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
};
オーバーレイを描画する
上記のコードではまだ、画面表示を始めていません。最初にオーバーレイを追加したときなど、マップ上にオーバーレイを描画する必要がある際、API では個別の draw() メソッドを呼び出します。
したがって、この draw() メソッドを実装し、getProjection() を使用してオーバーレイの MapCanvasProjection を取得したうえで、オブジェクトの右上と左下を固定する正確な座標を計算します。これで <div> をリサイズできます。あとはオーバーレイのコンストラクタで指定した境界に合うように、画像がリサイズされます。
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
};
カスタム オーバーレイを削除する
ここで、マップからオーバーレイを完全に削除する onRemove() メソッドも追加します。
// The onRemove() method will be called automatically from the API if
// we ever set the overlay's map property to 'null'.
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
};
カスタム オーバーレイを表示/非表示にする
単純にオーバーレイを作成/削除するのではなく、表示/非表示を切り替えたい場合は、独自の hide() メソッドと show() メソッドを実装してオーバーレイの表示状態を変更できます。代わりに、マップの DOM からオーバーレイを取り除くこともできますが、この操作には多くのリソースが必要です。マップの DOM に再度オーバーレイを貼り付ける際は、オーバーレイの onAdd() メソッドをもう一度呼び出す必要があります。
以下の例では、コンテナ <div> の表示状態を切り替える hide() と show() メソッドをオーバーレイのプロトタイプに追加しています。さらにオーバーレイをマップに貼り付けたり、マップから取り外したりする toggleDOM() メソッドも追加しています。
// Set the visibility to 'hidden' or 'visible'.
USGSOverlay.prototype.hide = function() {
if (this.div_) {
// The visibility property must be a string enclosed in quotes.
this.div_.style.visibility = 'hidden';
}
};
USGSOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.visibility = 'visible';
}
};
USGSOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility === 'hidden') {
this.show();
} else {
this.hide();
}
}
};
// Detach the map from the DOM via toggleDOM().
// Note that if we later reattach the map, it will be visible again,
// because the containing <div> is recreated in the overlay's onAdd() method.
USGSOverlay.prototype.toggleDOM = function() {
if (this.getMap()) {
// Note: setMap(null) calls OverlayView.onRemove()
this.setMap(null);
} else {
this.setMap(this.map_);
}
};
UI にも手を加えます。
<!-- Add an input button to initiate the toggle method on the overlay. -->
<div id="floating-panel">
<input type="button" value="Toggle visibility" onclick="overlay.toggle();"></input>
<input type="button" value="Toggle DOM attachment" onclick="overlay.toggleDOM();"></input>
</div>
