前回の続きで、
MarkerClustererをnewした状態からです
公式ドキュメントのdemoよりなんだか動作が遅いので
表示範囲外のMarkerを非表示処理するのに時間がかかったのでメモです
作業環境
- Nuxt.js (v2.15.8)
-
@googlemaps/js-api-loader
(v1.15.2) を使用 -
@googlemaps/markerclusterer
(v2.1.3) を使用
MarkerClustererをnewします
前回の記事から違うのは、
algorithm
のオプションに maxZoom: 12
を追加しました
この設定は、GoogleMapのzoomが12より大きくなった時は、Cluster化しないという設定です
デフォルトは 16
みたいです
https://github.com/googlemaps/js-markerclusterer/blob/b4cb8f3/src/algorithms/core.ts#L60
this.markerCluster = new MarkerClusterer({
map: this.map,
// markers: this.markers,
algorithm: new GridAlgorithm({ maxZoom: 12, maxDistance: 4000 }),
renderer: {
render: ({ count, position }) =>
new google.maps.Marker({
icon: {
// アイコン画像を使う場合はここにその情報を書く
},
label: {
text: String(count),
},
position,
// 他のマーカーの上になるよう調整
zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,
}),
},
});
markers: this.markers,
をコメントアウトしているのは
後に画面外のピンを非表示するからです
表示外のMarkerを消す処理を書く
bounds
が undefind
になる事があったため、エラー回避のため、if文をかまします
updateDisplayVisibleMarker() {
const map = this.map;
const markers = this.markers;
const bounds = map.getBounds();
const zoom = map.getZoom();
const setMaxZoom = 12; // `algorithm`のオプションに設定した値です、今回はしてないけど変数化しとくとGood
if (bounds) {
if (zoom < setMaxZoom) {
// クラスター化している場合
this.markerCluster.clearMarkers();
const visibleMarkers = markers.filter(marker =>
marker.getVisible() && bounds.contains(marker.getPosition())
)
this.markerCluster.addMarkers(visibleMarkers);
} else {
// クラスター化していない場合
for (let i = 0; i < markers.length; i++) {
if (bounds.contains(markers[i].getPosition())) {
// 表示内マーカーを表示
markers[i].setMap(map);
} else {
// 表示外マーカーを非表示
markers[i].setMap(null);
}
}
}
}
}
表示外のMarkerを消す処理を実行する
-
new MarkerClusterer()
した後 - GoogleMapのzoom値が変更された時
- GoogleMapをドラッグ移動終了時
GoogleMapイベントは、②と③の2つのタイミングで実行すればOKかなと思いますが、
タイル読み込み完了時にも入れておくと安心
理由は updateDisplayMarker()
内で、map.getBounds()
が undefind
になるタイミングがあるため…
丁寧に書くなら、map.getBounds()
が undefind
になったかどうかのフラグ管理をすれば、
タイル読み込み完了時に再度重複処理が省けるかと(今回はその記述は書いてない)
本当は、GoogleMap表示完了のイベントがあればいいんですが、
見つからなかったので(良い方法あれば教えて……
// zoom表示変更
this.map.addListener('zoom_changed', () => {
this.updateDisplayVisibleMarker()
});
// ドラッグ移動時
this.map.addListener('dragend', () => {
this.updateDisplayVisibleMarker()
});
// タイル読み込み完了時(1回のみ)
google.maps.event.addListenerOnce(this.map, 'tilesloaded', () => {
this.updateDisplayVisibleMarker()
});
あれ?なんか前回、表示外の処理勝手にしてくれるって喜んでなかった?w
Markerにクリックイベントを追加したりしていたら
なんだか表示処理遅いし、表示範囲外もMarkerが刺さってるな
という事があり、色々と見まくっていたら GridAlgorithm
でこんな処理見つけたんですな
if (map.getZoom() >= this.maxZoom) {
return {
clusters: this.noop({
markers,
}),
changed,
};
}
ん?これって、maxZoom値が現在のzoom値より大きいと、Markerはnoopするって処理やん
※noopってのはCluster化せず全部表示するって処理っぽい
ドキュメント的にはこのアルゴリズム
ほほう、どおりで地図zoomしたらなんか重たいな!って思うわけだわ
結局自分で表示範囲外のMarker処理書かないかんのかい・・!です
参考(コピペ)したサイト
本当、助かりマンモス
https://zenn.dev/wintyo/articles/dfe08d919f2ce7
https://www.mugo.ca/Blog/Making-your-custom-embedded-Google-Maps-more-efficient-with-marker-clusters
まとめ
頼むぜGoogleMapさん、ちゃんと表示外は消すんだったら、
Clusterしてない状態もその処理してよん