[英]How to make a form which searches an item around a specific radius using google maps API?
我正在一个网站上工作,我想在Google地图上围绕当前位置或某个手动地址制作一个圆圈。
用户可以选择是否要围绕当前位置或他们将提供的随机地址进行圈选。 (用户可以选择将手动地址放在当前位置,如下图所示)
现在我们还需要确保圆圈具有特定的半径( 距当前位置0-20 / 70km ),用户也需要确定它。 ( 当前位置下方的线将决定用户可在此处移动的半径0-70km )
例如:用户想要从当前位置创建一个圆圈直到30KM,或者用户想要从一些随机地址创建一个圆圈直到20KM。
我用来制作搜索范围搜索栏的HTML代码是 :
<div class="input-searchradius">
<input class="form-control search_radius mb-4" type="text" placeholder="search radius">
</div>
问题陈述:
(1)我想知道我需要进行哪些更改或需要添加的代码,以便围绕特定半径搜索项目。 我想,我需要整合代码谷歌地图圈子,但我不知道我该怎么做。
(2)在网站上搜索半径命中时,底部会显示以下选项/屏幕:
让我们尝试给你一些第一步,我不会编写整个应用程序的代码,而是给你一些如何解决你所拥有的小子问题的指导:
在地图中添加圆圈
那么,为此您有许多不同的输入选项,但最重要的部分是addCircle函数:
function addCircle(center){
circle = new google.maps.Circle({
map: map, //The existing map
center: center,
radius: 200, //This will be modified afterwards
zindex: 100
});
}
该中心可能来自点击 ,例如:
// Area is wherever you want to attach the click, either a polygon, a map...
google.maps.event.addListener(area, "click", function(event) {
addCircle(event.latLng);
});
或者通过获取某个地址的位置( 这也记录在案 ),或者任何方法(拖放圆圈,拖动标记blablabla)
添加动态半径
好吧,如果我们知道圆的半径以米为单位 ,那么很容易给addCircle函数提供正确的半径。 例如,20km - > 20 000米。 所以你必须能够在调用addCircle时访问radius(它可以是一个参数,一个全局变量......你的选择)。
我们完成了绘图部分,现在让我们在该圆圈内搜索。
仅获取圆圈内的标记
这里有一个先决条件,即拥有地图的所有标记。 您可能拥有从数据库获得的一系列地点,或者您可能从Google Maps API获取标记 (例如,放置搜索)。
之后,您将必须计算这些标记与给定中心之间的距离,并检查距离是否小于您的半径(使用computeDistanceBetween非常容易),因此您将知道哪些标记对您有效。
const markers = [//array of my valid markers with position];
markers.filter( (marker) =>
google.maps.geometry.spherical.computeDistanceBetween(marker.getPosition(), center.getPosition()) < radius; // Filter the markers which distance is bigger than radius;
剩下的工作应该很简单, 将标记放在地图中 ,并使用这些信息做任何你喜欢的事情。
EXTRAS
作为进一步的帮助,有一对可能对您有用的示例/答案:
完整的Google Map API示例 ,非常简单的一步一步指南。
半径搜索使用的地方 ,如何做半径搜索的好答案。
半径搜索示例 ,打开F12并根据需要调试代码,但很容易遵循。
编辑**:我没有意识到这些链接中的2个也在评论中指出。
我建议使用工作线程进行搜索以通过在后台进行搜索来释放UI线程。 如果用户移动圆圈或扩展/收缩圆圈,这也很有用,因为可以放弃先前的搜索/渲染匹配标记,
importScripts("Tier3Toolbox.js");
var currVintage = 0;
var inBounds = false;
var facFilter = [];
var imageProlog = "<div style='height:5em; width:5em; display:inline-block;vertical-align:middle;'>" +
"<img style='height:100%; width: 100%; max-height:100%; max-width:100%' src='";
var imageEpilog = "' ></div>";
var facilityTable, lineBreak;
self.addEventListener('message', function(e)
{
var data = e.data;
switch (data.cmd) {
case 'init':
initThread(data.load);
break;
case 'initFilter':
for (var i=0; i<data.filterTable.length; i++) {
facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
}
break;
case 'filter':
facFilter = [];
for (var i=0; i<data.filterTable.length; i++) {
if (data.filterTable[i].facSelected)
facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
}
break;
case 'search':
var searchVintage = ++currVintage;
var tableSearch = new searcher(searchVintage, data);
break;
case 'reset':
reset();
self.postMessage({'reset': true});
break;
case 'stop':
self.postMessage({'success' : true});
self.close();
break;
default:
self.postMessage({'success' : false, 'msg' : data.msg});
};
}, false);
function initThread(msg)
{
facilityTable = JSON.parse(msg);
reset();
self.postMessage({'success' : true,
'cnt' : facilityTable.length
});
}
function reset()
{
for (var i=0; i<facilityTable.length; i++) {
facilityTable[i].visible=false
}
currVintage = 0;
}
function searcher(searchVintage, msg)
{
var myVintage = searchVintage;
var facIndex = -1;
var msg = msg;
var checkLoop = function()
{
if (myVintage != currVintage)
return;
if (++facIndex == facilityTable.length)
return;
inBounds = geoFencer.call(this, msg);
if (inBounds) {
var facMatch = 0;
var bubbleHTML = "";
for (var i=0; i<facilityTable[facIndex].facilities.length; i++){
var currFac = facilityTable[facIndex].facilities[i];
if (facFilter[currFac.locTypeId] != undefined) {
if (facMatch != 0) {
lineBreak = (facMatch / 3);
if (lineBreak == lineBreak.toFixed(0)) {
bubbleHTML += "<br />";
}
}
facMatch++;
bubbleHTML += imageProlog + facFilter[currFac.locTypeId].icon + imageEpilog;
}
}
if (facMatch == 0) {
inBounds = false;
}
}
if (inBounds != facilityTable[facIndex].visible) {
self.postMessage({'match' : inBounds,
'facIndex' : facIndex,
'scopeVintage': msg.scopeVintage,
'bubbleHTML' : bubbleHTML,
'success' : true
});
facilityTable[facIndex].visible = inBounds;
}
setTimeout(checkLoop,0);
}
var circleCheck = function(msg)
{
var diff = Tier3Toolbox.calculateDistance(
msg.centerLat,
msg.centerLng,
facilityTable[facIndex].searchLat,
facilityTable[facIndex].searchLng);
if (msg.radius > diff)
return true;
return false;
}
var rectangleCheck = function(msg)
{
if (facilityTable[facIndex].searchLat > msg.SWLat &&
facilityTable[facIndex].searchLat < msg.NELat &&
facilityTable[facIndex].searchLng > msg.SWLng &&
facilityTable[facIndex].searchLng < msg.NELng)
return true;
return false;
}
var GEOFENCER = [circleCheck,rectangleCheck];
var geoFencer = GEOFENCER[msg.checker];
setTimeout(checkLoop,0);
return this;
}
提到的“工具箱”功能是: -
function Tier3Toolbox()
{
return this;
}
Tier3Toolbox.EARTH_RADIUS = 6378137; /* Equitorial Radius instead of 6371000 */
Tier3Toolbox.toRad =
function (num) {
return num * Math.PI / 180;
};
Tier3Toolbox.calculateDistance =
function(lat1, lon1, lat2, lon2){
var dLat = this.toRad(lat2 - lat1);
var dLon = this.toRad(lon2 - lon1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(this.toRad(lat1)) *
Math.cos(this.toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var distance = this.EARTH_RADIUS * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return distance;
}
Tier3Toolbox.prototype.callAJAX =
function(url, method, callback, serverArgs)
{
var callback = callback;
var xmlhttp;
var target = url;
var args = (serverArgs != undefined) ? serverArgs : "";
var postArgs = "";
var callbackArgs = new Array();
for (i = 4; i < arguments.length; i++) {
callbackArgs[i - 3] = arguments[i];
}
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
callbackArgs[0] = xmlhttp;
if (method.toUpperCase() == "GET") {
target = target + "?" + args;
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
callback.apply(this, callbackArgs)
} else {
throw new Error("Error making Ajax call to " + target + " Status = " + xmlhttp.status);
}
}
};
xmlhttp.open(method, url, true);
if (method.toUpperCase() == "POST") {
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
postArgs = args;
}
xmlhttp.send(postArgs);
}
Tier3Toolbox.reportError =
function(error)
{
var header = error.header || "Error";
var message = error.message || "";
var topWindow=window.top.document.open();
topWindow.write("<!DOCTYPE html><html><body style='height: 100%;'><hr><h1>" + header + "</h1><hr>");
topWindow.write("<h2>Please contact Server Support for assistance.</h2><br />");
topWindow.write('<p style="color:red">' + message + "</p></body></html>");
topWindow.close();
return;
}
在你的主线你需要添加如下的听众: -
google.maps.event.addDomListener(radarCircle, 'center_changed', reScope);
google.maps.event.addDomListener(radarCircle, 'radius_changed', reScope);
google.maps.event.addDomListener(radarRectangle, 'bounds_changed', reScope);
function createFacilityMarkers(xmlhttp){
facFinder = new Worker("facfinder.js");
facFinder.addEventListener('message', workerInit, false);
facFinder.postMessage({'cmd' : 'init', 'load' : xmlhttp.responseText});
}
function reScope() {
var searchReq = {'cmd':'search', 'scopeVintage':scopeVintage};
if (radarShape.getCenter) {
searchReq.checker = 0;
var currCenter = radarCircle.getCenter();
searchReq.centerLat = currCenter.lat();
searchReq.centerLng = currCenter.lng();
searchReq.radius = radarCircle.getRadius();
} else {
searchReq.checker = 1;
searchReq.SWLat = radarShape.getBounds().getSouthWest().lat();
searchReq.SWLng = radarShape.getBounds().getSouthWest().lng();
searchReq.NELat = radarShape.getBounds().getNorthEast().lat();
searchReq.NELng = radarShape.getBounds().getNorthEast().lng();
}
facFinder.postMessage(searchReq);
}
HTH
干杯理查德
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.