JavaScript
GoogleMapsAPI
MVCObject

GoogleMapでカスタム可能なラベルを持つマーカー

More than 1 year has passed since last update.

ラベル付きのマーカーをマップ上に表示したい

  • マーカーgoogle.maps.Markerはラベルを指定できる。
    • MarkerLabel object specification
    • オプションで指定できるのはフォントの色など簡易的。
    • 表示位置の変更もできないし、もっとカスタマイズしたラベルを表示したいところ。
    var marker = new google.maps.Marker({
        position: new google.maps.LatLng({lat: latitude, lng: longitude}),
        map: map,
        label: {
            color: 'blue',
            fontFamily: 'sans-serif',
            fontSize: '10px',
            fontWeight: '100',
            text: 'Marker label text'
        }
    });
  • マーカー上にテキストが表示されるが、細かい指定はできないのがツライ。

image

ラベルの<div>を持つ独自のマーカークラスを作る

  • google.maps.MVCObjectをプロトタイプに持つLabeledMarkerを作成する。
    • 独自のタグをマップ上に表示するにはgoogle.maps.OverlayViewを利用する。
LabeledMarkerクラス
function LabeledMarker(map, markerOptions, labelOptions) {
    this.setMap(map);
    this.setPosition(markerOptions.position);

    // MarkerとLabel(Overlay)を作成する
    this.marker = this.createMarker(markerOptions);
    this.label = this.createLabel(labelOptions);
}
LabeledMarker.prototype = new google.maps.MVCObject();
LabeledMarker.prototype.setMap = function (map) {
    this.set('map', map);
};
LabeledMarker.prototype.setPosition = function (position) {
    this.set('position', position);
};
LabeledMarker.prototype.createMarker = function (markerOptions) {
    var marker = new google.maps.Marker(markerOptions);
    marker.parent = this;
    marker.bindTo('map', this);
    marker.bindTo('position', this);
    google.maps.event.addListener(marker, 'dragend', function () {
        google.maps.event.trigger(this.parent, 'dragend');
    });
    return marker;
};
LabeledMarker.prototype.createLabel = function (labelOptions) {
    var label = new google.maps.OverlayView();
    label.parent = this;
    label.bindTo('map', this);
    label.bindTo('position', this);
    label.onAdd = function () {
        var el = document.createElement('div');
        el.style.borderStyle = labelOptions.style.borderStyle || 'none';
        el.style.borderWidth = labelOptions.style.borderWidth || '0px';
        el.style.backgroundColor = labelOptions.style.backgroundColor || '';
        el.style.position = labelOptions.style.position || 'absolute';
        el.style.zIndex = labelOptions.style.zIndex || 100;
        el.innerHTML = labelOptions.innerHTML || '<div>' + labelOptions.text + '</div>';
        this.el = el;
        var panes = this.getPanes();
        panes.overlayLayer.appendChild(el);
    }
    label.draw = function () {
        if (!this.el) return;

        var overlayProjection = this.getProjection();
        var position = this.get('position');
        var xy = overlayProjection.fromLatLngToDivPixel(position);

        var el = this.el;
        el.style.left = xy.x + 'px';
        el.style.top = xy.y + 'px';
    };
    label.onRemove = function () {
        this.el.parentNode.removeChild(this.el);
        this.el = null;
    };
    label.position_changed = function () {
        this.draw(); // 親コンポーネントのポジションが変更されたら連動してラベルの表示位置を更新する
    };
    return label;
}
mapにLabeledMarkerを表示する
var position = new google.maps.LatLng({
    lat: -34.397,
    lng: 150.644
});
var map = new google.maps.Map(document.getElementById('map-canvas'), {
    center: position,
    scrollwheel: false,
    zoom: 8
});

// ラベル付きマーカのオブジェクトを作成してマップに表示する
var labeldMarker = new LabeledMarker(map, {
    position: position,
    draggable: true
}, {
    text: 'Label text',
    style: {
        backgroundColor: 'white',
        borderStyle: 'solid',
        borderWidth: '1px'
    }
});
labeldMarker.addListener('position_changed', function () {
    // ドラッグによる位置変更をハンドリング
    console.log(JSON.stringify(this.get('position')));
});

表示サンプル

image