Несколько лет назад мой приятель ( Райан ЛеТулле ) продемонстрировал классное приложение на карте недвижимости, которое он создал. Я попросил его написать в блоге (потому что у всех есть блог и время для блога, верно?), Но он так и не нашел его. На прошлой неделе я спросил его, не возражает ли он, чтобы я восстановил то, что я видел, как он делает, и он сказал, что сделай это. Спасибо, Райан, за вдохновение!
Вы когда-нибудь пытались использовать сайт по недвижимости, чтобы найти дома, но не могли сузить критерии поиска? Например, вы знаете, в каком городе вы хотите жить, но также и в каком районе. Если вам повезет, сайт позволит вам искать по подразделениям, но как, черт возьми, вы это выясните? Мое подразделение — Айвенго, но я жил здесь около 10 лет, прежде чем понял это.
Я думаю, что вам действительно хотелось бы получить критерии поиска. Учитывая карту города и смутное представление о том, где вы хотите жить, что, если бы мы могли нарисовать регион и найти в нем результаты?
Эта идея опирается на два основных аспекта. Во-первых, это возможность рисовать на карте. Я собираюсь использовать Google Maps для этого проекта. Карты Google — чертовски глубокий API. Это позволяет рисовать маркеры, линии, прямоугольники и многоугольники в целом на карте. Это также позволяет глубоко взаимодействовать с этими элементами пользовательского интерфейса.
Исследуя эту идею, я обнаружил, что у них есть функция под названием «Редактируемые пользователем формы» . Как вы можете себе представить, это позволяет пользователю перемещать и корректировать фигуру на карте:
Это хорошо — но коробка не совсем точна. Я решил начать с простых строк (то, что Google называет Polylines). Я создал карту, а затем использовал события щелчка, чтобы добавить маркеры с линиями, соединяющими их. К счастью, у Google уже был пример этого ( комплекс Polyline ), поэтому я начал с этого. Я сделал одну модификацию, хотя. Я настроил его так, чтобы, как только вы нажали три раза, я автоматически «закрыл» окно для вас.
Например:
Код довольно прост — просто обратите внимание, сколько линий мы нарисовали, и при третьем щелчке автоматически закройте окно:
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);
var polyOptions = {
strokeColor: '#000000',
strokeOpacity: 1.0,
strokeWeight: 3
}
var markers = [];
poly = new google.maps.Polyline(polyOptions);
poly.setMap(map);
google.maps.event.addListener(map, 'click', function(event) {
var path = poly.getPath();
path.push(event.latLng);
markers.push(new google.maps.Marker({
position: event.latLng,
title: '#' + path.getLength(),
map: map
}));
if(path.getLength() == 4) {
console.log('box it');
path.push(markers[0].getPosition());
console.dir(markers);
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
Это сработало … Хорошо (и вы можете продемонстрировать это здесь ), но мне стало плохо, когда я заставлял вас искать внутри четырехстороннего многоугольника. Что я действительно хотел, так это возможность позволять вам нажимать столько раз, сколько вы хотите, и когда вы закончите, автоматически закрывайте «ящик». В качестве примера я создал многосегментный многоугольник здесь и щелкнул поиск, чтобы завершить регион:
В целом, я чувствовал, что это было хорошее решение. Теперь, прямо сейчас, вы можете спросить, что произойдет, если вы нарисуете что-то сумасшедшее, как, ну, скажем так:
Не делай этого. Шутки в сторону.
Хорошо … Итак, на данный момент мы рассмотрели первый основной аспект этого проекта — дать вам возможность «нарисовать» регион. Теперь приходит второй. Учитывая, что мы знаем регион, как мы можем найти в нем дерьмо?
Я был немного разорван об этом аспекте. Оказывается, есть решение на стороне клиента, предоставленное Google (не удивительно), но также и код на стороне сервера, который вы также можете использовать. У CFLib есть UDF ( PointInPolygon ), которому почти 10 лет, и он будет этим заниматься. Таким образом, теоретически мы можем получить доступ к базе данных сервера, выполнить некоторую логику и вернуть очки. Или мы могли бы сделать это на стороне клиента. Хранение данных на сервере обеспечивает более быструю начальную загрузку. Хранение этого в клиенте позволяет нам искать немного быстрее, но делает первую загрузку «толще».
Я решил использовать клиентское решение главным образом потому, что хотел протестировать этот конкретный API Google, а также потому, что мне было любопытно, насколько «плохим» будет удар, если я сохраню большой набор данных на клиенте. В моем примере я храню только данные долготы / широты. Я полагаю, что, как только вы нажмете на результат, мы можем выполнить пинг AJAX, чтобы получить дополнительные данные. Или, черт возьми, мы можем сделать это, как только вы закончите свой полигон. Я написал скрипт (вы можете посмотреть исходный код здесь ), чтобы сгенерировать 400 различных длинных / латовых пар, которые были примерно в районе Лафайетта. Этот скрипт выводит переменную JavaScript, которую я мог бы затем сохранить и сохранить в файле с именем data.json.
Теперь, когда у меня были данные, я мог обновить свой код, чтобы загрузить его в память. Что касается того, как я мог фильтровать данные, я использовал библиотеку Google Geometry . Он позволяет вам передать точку long / lat и многоугольник, и он возвращает true, если точка находится внутри него. Вот обновленное издание. Вы хотите обратить внимание на функцию doSearch:
function initialize() {
var locData;
var searchButton = document.querySelector("#searchButton");
var resultsDiv = document.querySelector("#results");
var mapOptions = {
center: new google.maps.LatLng(30.223178, -92.024231),
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);
var polyOptions = {
strokeColor: '#000000',
strokeOpacity: 1.0,
strokeWeight: 3
}
var blueIcon = {
url:"http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png"
};
var markers = [];
poly = new google.maps.Polyline(polyOptions);
poly.setMap(map);
google.maps.event.addListener(map, 'click', function(event) {
var path = poly.getPath();
path.push(event.latLng);
markers.push(new google.maps.Marker({
position: event.latLng,
title: '#' + path.getLength(),
icon:blueIcon,
map: map
}));
});
searchButton.addEventListener("click", function(e) {
var path = poly.getPath();
if(path.getLength() < 4) {
alert('Please select at least 4 points.');
return;
}
path.push(markers[0].getPosition());
searchButton.setAttribute("disabled","disabled");
doSearch();
});
$.get("data.json", {}, function(res) {
locData=res;
searchButton.innerText = "Search";
searchButton.removeAttribute("disabled");;
});
function doSearch() {
results.innerHTML = "<i>Searching for matches...</i>";
var totalFound = 0;
for(var i=0; i<locData.length; i++) {
//I should probably cache this creation!
var point = new google.maps.LatLng(locData[i][0],locData[i][1]);
if(google.maps.geometry.poly.containsLocation(point,poly)) {
var m = new google.maps.Marker({
position: point,
title: 'Location '+i,
map: map
});
totalFound++;
}
}
results.innerHTML = "Found " + totalFound + " results.";
}
}
google.maps.event.addDomListener(window, 'load', initialize);
Как видите, я перебираю данные и передаю их в Geometry API. Если совпадение найдено, я добавляю маркер. Когда все будет готово, я сообщу об итогах матчей. Вы можете продемонстрировать это, нажав гигантскую демонстрационную кнопку ниже. Обратите внимание, что двойное нажатие кнопки «Поиск» уничтожит вселенную. Не нажимайте дважды.
PS Я на самом деле проверил «пересечение потоков», и это работало отлично Я знал, что так и будет. Честный.




