#javascript #leaflet
#javascript #листовка
Вопрос:
У меня есть слой с маркерами в нем, markerLayer
. У меня также есть один дополнительный маркер, user_marker
. Я хочу, чтобы карта соответствовала, чтобы показать дополнительный маркер и следующие k маркеров вокруг него.
Я знаю, что есть leaflet-knn, но он принимает GeoJSON, а не слои листовки, и возвращает массив координат, что не совсем то, что требуется. Существует также брошюра.GeometryUtil , но у него есть только возможность возвращать все слои в пределах определенного радиуса, а не k ближайших.
Есть ли встроенное решение в листовке, которое я пропустил, или простое решение либо с помощью встроенных листовок, либо с помощью внешней библиотеки для масштабирования до k ближайших маркеров вокруг определенного маркера?
Ответ №1:
Вам не обязательно нужны плагины для листовок. Вы могли бы просто использовать метод distanceTo и отсортировать свои маркеры по расстоянию до user_marker . Затем вы вызываете метод fitBounds . Я создал здесь рабочий пример.
Ниже приведены важнейшие этапы кода:
var testData = [{lat:37.7859,lon:-122.1362},{lat:37.6921,lon:-122.0312},{lat:37.823,lon:-122.6112},{lat:37.7478,lon:-122.1562},{lat:37.6759,lon:-122.0458},{lat:37.555,lon:-122.050}];
var marker_layer = new L.layerGroup();
var user_marker = L.marker(L.latLng(37.7829, -122.1312)).addTo(map);
//k closest markers
var k = 3;
var dist_markers = [];
$.each(testData, function(index, p) {
var latlng = L.latLng(p.lat, p.lon)
var marker = L.marker(latlng);
marker.addTo(marker_layer);
dist = L.latLng(37.7829, -122.1312).distanceTo(latlng);
dist_markers.push([dist,marker]);
});
dist_markers.sort(Comparator);
var close_markers = dist_markers.slice(0,k)
close_markers = close_markers.map(function(d) {return d[1];});
var group = new L.featureGroup(close_markers);
marker_layer.addTo(map);
user_marker.addTo(map);
map.on('click', function() {
map.fitBounds(group.getBounds());
});
Комментарии:
1. Это очень похоже на решение, которое я бы выбрал 🙂 В конце концов я нашел решение с
leaflet.GeometryUtil
помощью какого-то хакерского обходного пути 😉
Ответ №2:
Я знаю, что есть leaflet-knn, но для этого требуется GeoJSON, а не слои листовки
Итак? Просто соедините свои маркеры в a L.LayerGroup
и используйте его toGeoJSON()
метод.
С некоторыми обратными ссылками вы сможете снова извлекать маркеры из поиска knn.
Комментарии:
1. Я действительно сделал это и вернул массив с широтами и долготами. В этот момент я остановился, так как мне каким-то образом нужно было преобразовать их обратно в маркеры. Вместо этого я выбрал решение с помощью L.GeometryUtil. В любом случае, вопрос заключался в том, было ли более простое решение или решение, которое не требовало внешнего кода и некоторого «обходного пути». Похоже, что ничего подобного там или в StackOverflow пока нет, поэтому я спросил 🙂
Ответ №3:
Это решение, к которому я в конечном итоге пришел, используя L.GeometryUtil .
function fit_around_marker(user_marker, number) {
if (number >= markerLayer.getLayers().length) {
map.fitBounds(markerLayer.getBounds());
} else {
var p = user_marker.getLatLng();
var fit_layers = markerLayer.getLayers();
var fit_array = [];
var r = 1;
while (fit_array.length < number) {
fit_array = L.GeometryUtil.layersWithin(map, fit_layers, p, r );
}
var fit_markers = [user_marker];
for (index = 0; index < fit_array.length; index) {
fit_markers.push(fit_array[index]["layer"]);
}
console.log(fit_markers);
var fit_layer = L.featureGroup(fit_markers);
map.fitBounds(fit_layer.getBounds());
}
}
Комментарии:
1. GeometryUtil.layersWithin — хороший метод. Я думаю, что наиболее эффективное решение во многом зависит от количества маркеров, которые у вас есть на вашем слое, расстояния между этими маркерами и значения ‘number’ в вашей функции. Действительно, во многих случаях будет достаточно вызвать layersWithin без аргумента radius, и, следовательно, вы сэкономите цикл while. Если ваши маркеры находятся очень далеко друг от друга, кажется сомнительным использовать цикл while с увеличением r на единицу измерения на один метр каждый раз.
2. Я согласен с увеличением, это было первое, что я протестировал, и оно было достаточно быстрым, поэтому я пока оставил его. Два примечания: увеличение указано в пикселях, а не в метрах. Я не знаю, как это переводится в метры. И внутренне
layersWithin
делает почти то же самое, что и ваш код 🙂 Поэтому я бы на самом деле предположил, что используется ваш пример.