作成した地図にリーフレットポリゴンがたくさんあります。各ポリゴンは異なるものを表します。ユーザーが表示しているページに応じて、特定の情報のセットがポップアップに表示されます。それが表すポリゴンの中心に「ポップアップ」バブルを開く方法を見つける必要があります。
各ポリゴンは、次のコードを使用して描画されます。
var L20 = [
[74.0995, -99.92615],
[74.14008, -99.4043],
[74.07691, -99.33838],
[74.03617, -99.86023]
];
var L19 = [
[74.02559, -99.84924],
[74.06636, -99.32739],
[74.0029, -99.26147],
[73.96197, -99.77783]
];
var L18 = [
[73.95142, -99.76684],
[73.99235, -99.25048],
[73.92889, -99.18456],
[73.8878, -99.69543]
];
var set1 = L.polygon([L20, L19, L18], {
color: "#fff",
weight: 1,
stroke: true,
opacity: 0.05,
fillColor: "#346B1F",
}).addTo(map);
ポップアップは、次のコードを使用して描画されます。
var popup = L.popup({})
.setLatLng([73.64017, -100.32715])
.setContent(content).openOn(map);
var popup = L.popup();
ですから、.setLatLang
がポリゴンの中心を決定するか、その中心を与える方法を見つける必要があります。
私はうまくいくかもしれない3つの解決策を思いつきました、それについてどうやって行くかわかりません。
ポリゴンの座標を使用して、ポップアップが開くポリゴンの中心を決定する方法を見つけます。
ポリゴンの1点を呼び出し、ポップアップの位置をオフセットします。
各ポリゴンにIDを使用して、各ポップアップがそれを開くことができるボックス領域(ポリゴン)を認識できるようにします。
誰かが私を助けてくれますか?
ポリゴンの重心を近似する方法はいくつかあります。
最も簡単な(ただし、最も精度の低い方法)は、polygon.getBounds().getCenter();
を使用して、yarlが提案したように、ポリゴンを含むバウンディングボックスの中心を取得することです。
私は元々、その頂点の座標を平均することによって見つけることができる点の重心を見つけるための式で質問に答えました。
var getCentroid = function (arr) {
return arr.reduce(function (x,y) {
return [x[0] + y[0]/arr.length, x[1] + y[1]/arr.length]
}, [0,0])
}
centerL20 = getCentroid(L20);
ポイントの重心は私をだますのに十分に近い近似ですが、コメンターはそれがポリゴンの重心ではないことを指摘しました。
自己交差していない閉じた多角形の重心 の式に基づく実装では、正しい結果が得られます。
var getCentroid2 = function (arr) {
var twoTimesSignedArea = 0;
var cxTimes6SignedArea = 0;
var cyTimes6SignedArea = 0;
var length = arr.length
var x = function (i) { return arr[i % length][0] };
var y = function (i) { return arr[i % length][1] };
for ( var i = 0; i < arr.length; i++) {
var twoSA = x(i)*y(i+1) - x(i+1)*y(i);
twoTimesSignedArea += twoSA;
cxTimes6SignedArea += (x(i) + x(i+1)) * twoSA;
cyTimes6SignedArea += (y(i) + y(i+1)) * twoSA;
}
var sixSignedArea = 3 * twoTimesSignedArea;
return [ cxTimes6SignedArea / sixSignedArea, cyTimes6SignedArea / sixSignedArea];
}
しばらくして、Leafletには組み込みの getCenter() メソッドがあります。
polygon.getBounds().getCenter();
解決しようとしている問題は、アクセス不能の極と呼ばれます。ポリゴンにラベルを配置するのに最適な場所を見つけることは、境界ボックスの中心を見つけることでは完全には解決されません。文字Uの形のポリゴンを考えます。境界ボックスの中心は、ラベルをポリゴンの外側に配置します。この優れたライブラリを見つけるのに永遠にかかりました: https://github.com/mapbox/polylabel
README.MD:から
JavaScriptライブラリとして実装された、アクセスできないポリゴンポール、ポリゴンアウトラインから最も離れた内部ポイント(セントロイドと混同しないでください)を見つけるための高速アルゴリズム。ポリゴン上のテキストラベルの最適な配置に役立ちます。
これは、Garcia-Castellanos&Lombardo、2007年の論文に触発された反復グリッドアルゴリズムです。論文のアルゴリズムとは異なり、このアルゴリズムは次のとおりです。
- 与えられた精度内でグローバル最適を見つけることを保証します
- 何倍も速い(10-40x)
使用法:
GeoJSONのような形式と精度(デフォルトでは1.0)でポリゴン座標を指定すると、Polylabelはアクセスできない座標の極を[x、y]形式で返します。
var p = polylabel(polygon, 1.0);
アルゴリズムのしくみ:
これは、グリッドベースの反復アルゴリズムです。最初に、大きな正方形のセルでポリゴンをカバーし、次に、最も有望なセルの順序でそれらを反復的に分割しながら、興味のないセルを積極的にプルーニングします。
- 多角形を完全にカバーする最初の正方形のセルを生成します(セルサイズは、幅または高さのいずれか小さい方に等しくなります)。各セルの中心から外側のポリゴンまでの距離を計算します。ポイントがポリゴンの外側にある場合は、負の値を使用します(レイキャスティングで検出)。
- セルを、中心からの距離とセル半径の合計として定義されるセル内のポイントからの最大可能距離でソートされた優先キューに入れます(cell_size * sqrt(2)/ 2と等しい)。
- ポリゴンの重心からの距離を計算し、それを最初の「これまでで最高」として選択します。
- 優先度キューからセルを1つずつ引き出します。セルの距離が現在のベストよりも良い場合は、そのように保存します。次に、セルに現在の最良(cell_max-best_dist>精度)より優れたソリューションが含まれている可能性がある場合は、4つの子セルに分割してキューに入れます。
- キューを使い果たしたらアルゴリズムを停止し、アクセス不能の極として最良のセルの中心を返します。与えられた精度の範囲内でグローバル最適であることが保証されます。
各ポリゴンの側面が4つしかない場合は簡単です
var L20 = [
[74.0995, -99.92615],
[74.14008, -99.4043],
[74.07691, -99.33838],
[74.03617, -99.86023]
];
この例を使用すると、最大と最小の緯度がそれぞれ74.03617と74.14008になるので、長い間同じです:それぞれ-99.92615と99.33838
次に、それぞれの中央値を取得します:(最大-最小)/ 2 = 0.051955および-0.293885次に、それらを最小量に追加します
74.088125, -99.632265
の中心を提供します