写真やコメントなどの位置を表すための点の描画と、clusterを使って近い場所の点をまとめて丸を大きくする方法。
点の描画
Open Street Map上の点を経緯度で指定して、集合に対応できる点を描画する。
ページ初期化時
- Open Street Mapを、projectionにEPSG900913を設定して生成する。
- 点を描画する先のOpenLayers.Layer.Vector()を生成して、地図に追加する。
// 写真の撮影ポイント strategy_photopnt = new OpenLayers.Strategy.Cluster(); vecPhotoLayer = new OpenLayers.Layer.Vector("Photo Points", {}); // マップにVectorを追加 olMap.addLayer(vecPhotoLayer);
点をまとめて追加する
点をまとめて追加するには、点の配列を作成して、まとめて登録する。
imagesという配列のlonに経度、latに緯度が入っているものとする。
var features = []; for(var i=0 ; i<images.length ; i++) { features.push( new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point( images[i].lon,images[i].lat).transform(projLonLat,projSpMerc), {x: images[i].lon, y: images[i].lat, file: images[i].file} ) ); } // 写真の点を追加する vecPhotoLayer.removeFeatures(vecPhotoLayer.features); vecPhotoLayer.addFeatures(features);
- OpenLayers.Feature.Vector型は、Vector型のレイヤーに追加するオブジェクトを表す。生成時にGeometry、属性、スタイルを渡す。
- Featureの形状は、OpenLayers.Geometryで表す。点はPointで、x,yの順に引数を受けとる。今回はSpherical Mercator座標系のOSMを利用するので、transformを使って経緯度をSpherical Mercator座標系に変換している。
- Featureに追加するプロパティを属性に設定。この例ではx,y,fileを渡している。これは自由に追加してよい。Featureから後で取り出したいデータを追加しておく。
- スタイルは省略している
- 点リストの作成が完了したら、一度レイヤーに追加済みのfeatureを削除してから、新しいfeatureを追加する。
点を個別に追加する
点を一つずつ追加したい場合、OpenLayers.Layer.drawFeature()が使えそうだが、Zoomした際に点がずれてしまった。そこで、今回はOpenLayers.Feature.Vector型の配列を用意して、そこに点の追加をして、レイヤーからFeatureの削除と追加を行う方法で実装した。
// featureに追加描画 ftPhotoPoints.push( new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point(lon,lat).transform(projLonLat,projSpMerc), {x: lon, y: lat, file: fl} ) ); // 写真の点を追加する vecPhotoLayer.removeFeatures(vecPhotoLayer.features); vecPhotoLayer.addFeatures(ftPhotoPoints);
Clusterによる点の集約化
OpenLayers.Strategy.Cluster()クラスをVectorレイヤーに追加すると、指定の距離内に、指定の数以上の点があった場合、1つの大きな円に集約化してくれる。以下、使い方。
スタイルの定義
//// 写真点のスタイル var style_photopnt = new OpenLayers.Style({ pointRadius: "${radius}", fillColor: "#ffcc66", fillOpacity: 0.8, strokeColor: "#cc6633", strokeWidth: "${width}", strokeOpacity: 0.8 },{ context: { width: function(feature) { return (feature.cluster) ? 2 : 1; }, radius: function(feature) { var pix = 16; if(feature.cluster) { pix = Math.min(feature.attributes.count, 8)*2 + 4; } return pix; } } });
初期化
// 写真の撮影ポイント vecPhotoLayer = new OpenLayers.Layer.Vector("Photo Points", { strategies: [new OpenLayers.Strategy.Cluster()], styleMap: new OpenLayers.StyleMap({ "default": style_photopnt, "select": { fillColor: "#8aeeef", strokeColor: "#32a8a9" } }), distance: 20, threshold: 2 });
- 予め、OpenLayers.Strategyオブジェクトを生成する。
- OpenLayers.Layer.Vector(ベクトル名,パラメータ)として初期化。
- strategiesに、作成したStrategyオブジェクトを指定。
- styleMapに、通常時のスタイルと、選択時の水色のスタイルを設定。
- distanceに、集約化する時の距離を指定。
- thresholdに、集約化するための最低個数を指定。
Featureの選択
追加したFeatureをマウスカーソルなどで選択するために、Openlayers.Control.SelectFeature()オブジェクトを利用する。
初期化
// selectFeatureを設定する var select = new OpenLayers.Control.SelectFeature( vecPhotoLayer,{hover:true} ); olMap.addControl(select); select.activate(); vecPhotoLayer.events.on({"featureselected": display});
- 追加先のレイヤーと、発生させるイベント(今回はFeature上にマウスカーソルが来たときのイベント)を指定して、OpenLayers.Control.SelectFeature()オブジェクトを生成。
- 作成したSelectFeatureを地図に追加。
- SelectFeatureをactivate()して有効化。
- 追加先のレイヤーに、イベントハンドラを指定。featureselectedで選択時で、display関数を呼び出すようにする。
イベント
// ホバーしたfeatureの情報を表示 function display(event) { var f = event.feature; if (f.cluster) { for (var i=0 ; i<f.cluster.length ; i++) { // ホバーした場所の情報を取り出す。 console.log( "photo["+i+"]="+f.cluster[i].attributes.x+"/" +f.cluster[i].attributes.y+"/" +f.cluster[i].attributes.file.name); } } else { console.log("no cluster"); } }
設定したイベントの例。
- event.featureに、選択されたFeatureのデータが渡される。
- event.feature.clusterに、集約されたデータが配列で入っている。
- attributes.countに、Featureの数。
- cluster[n].attributes.パラメータ名で、各featureの属性に設定した値が取得できる
参考URL
- Cluster Strategy Threshold , http://openlayers.org/dev/examples/strategy-cluster-threshold.html
- Flickr API with Cluster Strategy Example , http://openlayers.org/dev/examples/strategy-cluster.html
- OpenLayers.API Docs , http://dev.openlayers.org/apidocs/