如何使用谷歌地图API制作一个搜索特定半径周围项目的表单?
Posted
技术标签:
【中文标题】如何使用谷歌地图API制作一个搜索特定半径周围项目的表单?【英文标题】:How to make a form which searches an item around a specific radius using google maps API? 【发布时间】:2019-01-04 18:08:03 【问题描述】:我正在处理website,我想在谷歌地图上围绕当前位置或一些手动地址制作一个圆圈。
用户可以选择决定是要绕当前位置还是要提供的随机地址。 (用户可以选择将手动地址放入当前位置,如下图所示)
现在我们还需要确保圆具有特定的半径(距当前位置 0-20/70 公里),并且用户也需要做出决定。 (当前位置下方的线将决定用户可以在这里和那里移动0-70公里的半径)
例如:用户想要创建一个从当前位置到 30KM 的圈子,或者用户想要从某个随机地址创建一个圈子直到 20KM。
我用来制作搜索半径搜索栏的 HTML 代码是:
<div class="input-searchradius">
<input class="form-control search_radius mb-4" type="text" placeholder="search radius">
</div>
问题陈述:
(1) 我想知道我需要进行哪些更改或需要添加代码,以便围绕特定半径搜索项目。我想,我需要整合代码Google Maps circle,但我不确定我该怎么做。
(2) 在website 上点击搜索半径时,底部会出现以下选项/屏幕:
【问题讨论】:
嗯,我没有收到弹出窗口。但我想我帮不了你,它就像你想要构建的Google Maps API,但我对半径等不太熟悉。 1. 假设我在what are you looking for..
占位符中寻找计算器2. 点击search radius
占位符,它将询问距我们当前位置(或我们手动放置的地址)大约 0-70 公里的地理位置(要搜索的项目,比如计算器)。现在忘记弹出窗口。让我们专注于功能。
@user5447339 检查Google Map: Drawing Tool 或Google Map: circle。用户填写完表格(位置、半径)后,在gmap的位置放一个标记,然后根据半径值画一个圆。
@Sphinx 你能给我指点如何处理这个问题吗?我以前从未使用过 google api。
我不熟悉 Google MAP API。您可以按照谷歌地图的指南首先达到您的目标。如果有的话,*** 将是您的家。 :)
【参考方案1】:
让我们尝试为您提供一些初步步骤,我不会编写整个应用程序的代码,而是为您提供一些指导方针,帮助您解决您遇到的小子问题:
在地图中添加圆圈
好吧,为此你有许多不同的输入选项,但最重要的部分是 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
);
中心可能来自click,例如:
// 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);
);
或通过获取某个地址的位置 (This is documented as well),或任何方法(拖放圆圈,拖动标记 blablabla)
添加动态半径
好吧,如果我们知道the radius of the Circle is given in meters,那么就很容易给 addCircle 函数一个正确的半径。例如,20 公里 -> 20 000 米。所以你只需要在调用 addCircle 时能够访问半径(它可以是一个参数,一个全局变量......你的选择)。
我们已经完成了绘图部分,现在让我们在那个圆圈内搜索。
仅获取圆圈内的标记
这里有一个先决条件,即拥有地图的所有标记。您可能有一系列从数据库中获取的地点,或者您可能是 get the markers from 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;
其余的工作应该很简单,place the markers in the map 并根据这些信息做任何你想做的事情。
EXTRAS
作为进一步的帮助,有一对示例/答案可能对您有用:
Full Google Map API example,非常简单的分步指南。
Radius search using places,关于如何进行半径搜索的一个很好的答案。
Example of radius search,喜欢的话可以打开F12调试代码,不过很容易上手。
编辑**:我没有意识到这些链接中的 2 个也在 cmets 中指出。
【讨论】:
谢谢@SirPeople 我有一个类似的question。我想知道你是否可以看看。 给我几分钟/几小时,我会看看 :)【参考方案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
干杯理查德
【讨论】:
谢谢@McMurphy 我有一个类似的question 我想知道你是否可以看看。【参考方案3】:这里遵循@SirPeople 的建议是解决您从用户获取位置输入、更新地图并设置其周围的动态半径的核心问题陈述的完整代码。
这里是 JS Fiddle 链接https://jsfiddle.net/innamhunzai/63vcthp7/3/
JS:
var circle;
var map;
function initMap()
var centerCoordinates = new google.maps.LatLng(37.6, -95.665);
map = new google.maps.Map(document.getElementById('map'),
center: centerCoordinates,
zoom: 4
);
var card = document.getElementById('pac-card');
var input = document.getElementById('pac-input');
var infowindowContent = document.getElementById('infowindow-content');
var autocomplete = new google.maps.places.Autocomplete(input);
var infowindow = new google.maps.InfoWindow();
infowindow.setContent(infowindowContent);
var marker = new google.maps.Marker(
map: map
);
circle = new google.maps.Circle(
map: map,
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
);
autocomplete.addListener('place_changed', function()
document.getElementById("location-error").style.display = 'none';
infowindow.close();
marker.setVisible(false);
var place = autocomplete.getPlace();
if (!place.geometry)
document.getElementById("location-error").style.display = 'inline-block';
document.getElementById("location-error").innerHTML = "Cannot Locate '" + input.value + "' on map";
return;
map.fitBounds(place.geometry.viewport);
marker.setPosition(place.geometry.location);
circle.setCenter(place.geometry.location);
marker.setVisible(true);
circle.setVisible(true);
infowindowContent.children['place-icon'].src = place.icon;
infowindowContent.children['place-name'].textContent = place.name;
infowindowContent.children['place-address'].textContent = input.value;
infowindow.open(map, marker);
);
function updateRadius()
circle.setRadius(document.getElementById('radius').value * 1609.34);
map.fitBounds(circle.getBounds());
**CSS:**
#map
height: 400px;
**HTML**
<html>
<link href="style.css" rel="stylesheet" type="text/css">
<body>
<div class="pac-card" id="pac-card">
<div>
<div id="label">
Location search
</div>
</div>
<div id="pac-container">
<input id="pac-input" type="text" placeholder="Enter a location">
<div id="location-error"></div>
</div>
<div>
<input type="range" id="radius" name="radius" min="0" max="100" onchange="updateRadius()">
</div>
</div>
<div id="map"></div>
<div id="infowindow-content">
<img src="" id="place-icon">
<span id="place-name" class="title"></span><br>
<span id="place-address"></span>
</div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&callback=initMap"
async defer></script>
</body>
</html>
【讨论】:
以上是关于如何使用谷歌地图API制作一个搜索特定半径周围项目的表单?的主要内容,如果未能解决你的问题,请参考以下文章