To start off I'm fairly new to Javascript and the Google Maps API so any help will be greatly appreciated.
I'm building a map with polygons to mark boundary locations and the ability to search an address to see what polygon the address is in. The code works for both Firefox and Chrome, but for some reason when I try to search an address in IE, the map just reloads rather than placing the marker at the appropriate location.
I've included all the functions I use. The microajax Javascript function is used to read the xml file that contains the coordinates of all the polygon shapes. Since the polygons are being rendered in IE, I dont believe this is the cause of the problem so I didnt include it. I'm at a loss for what the problem could be. Thanks in advance.
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="microajax.js"></script>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 30px; padding: 0px }
#map_canvas { height: 100% }
</style>
<div id="map_canvas" style="width:800px; height:600px" text="If map is not present, this browser does not support Google Maps"></div>
<div id="message"></div>
<form onsubmit="showAddress()" action="#">
<input id="search" size="60" type="text" value="" />
<input type="submit" value="Go!" />
<input type="button" onclick="clearmarkers();" value="Clear markers" />
</form>
</head>
<body onload="initialize()">
<noscript><b>JavaScript must be enabled in order for you to use Google Maps.</b>
However, it seems JavaScript is either disabled or not supported by your browser.
To view Google Maps, enable JavaScript by changing your browser options, and then
try again.
</noscript>
<script type="text/javascript">
var gmarkers = [];
var polys = [];
var labels = [];
var glob;
var geo = new google.maps.Geocoder();
var map;
function initialize() {
var ontario = new google.maps.LatLng(50.397, -85.644);
var myOptions = {
zoom: 5,
center: ontario,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
microAjax("xmloutput2.xml", function(data) {
// ========= processing the polylines ===========
var xmlDoc = xmlParse(data)
var lhins = xmlDoc.documentElement.getElementsByTagName("lhin");
// read each line
for (var a = 0; a < lhins.length; a++) {
var label = lhins[a].getAttribute("name");
var colour = lhins[a].getAttribute("colour");
// read each point on that line
var points = lhins[a].getElementsByTagName("point");
var pts = [];
for (var i = 0; i < points.length; i++) {
pts[i] = new google.maps.LatLng(parseFloat(points[i].getAttribute("lat")), parseFloat(points[i].getAttribute("lng")));
}
var poly = new google.maps.Polygon({
paths:pts,
strokeColor:"#000000",
strokeOpacity: 1,
strokeWeight: 2,
fillColor: colour,
fillOpacity: 0
});
poly.setMap(map);
polys.push(poly);
labels.push(label);
}
function showAddress() {
var search = document.getElementById("search").value;
geo.geocode( { 'address': search}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// How many results were found
document.getElementById("message").innerHTML = "Found " +results.length +" results";
// Loop through the results, placing markers
for (var i=0; i<results.length; i++) {
var marker = new google.maps.Marker({
map: map,
position: results[i].geometry.location
});
gmarkers.push(marker);
glob=checkpoint(marker);
if (glob == 99) {
var infowindowoptions = {
content: 'This address is not within a LHIN boundary'
}
infowindow = new google.maps.InfoWindow(infowindowoptions);
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, this);
});
document.getElementById("message").innerHTML += "<br>"+(i+1)+": "+ results[i].formatted_address +" "+ results[i].geometry.location + "Outside of Bounds";
}
else {
var infowindowoptions = {
content: 'This address is in LHIN '+labels[glob]
}
infowindow = new google.maps.InfoWindow(infowindowoptions);
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, this);
});
document.getElementById("message").innerHTML += "<br>"+(i+1)+": "+ results[i].formatted_address +" "+ results[i].geometry.location +
" - LHIN "+(glob+1)+" "+labels[glob];
}
}
map.setCenter(results[0].geometry.location);
map.setZoom(17)
}
else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
function clearmarkers() {
if (gmarkers) {
for (i in gmarkers) {
gmarkers[i].setMap(null);
}
gmarkers.length = 0;
}
}
function checkpoint(marker) {
var LNum;
var point = marker.getPosition();
for (var i=0; i<polys.length; i++) {
if (polys[i].containsLatLng(point)) {
Lnum = i;
i = 999; // Jump out of loop
}
else {
Lnum = 99
}
}
return Lnum
};
// Polygon getBounds extension - google-maps-extensions
// http://code.google.com/p/google-maps-extensions/source/browse/google.maps.Polygon.getBounds.js
if (!google.maps.Polygon.prototype.getBounds) {
google.maps.Polygon.prototype.getBounds = function(latLng) {
var bounds = new google.maps.LatLngBounds();
var paths = this.getPaths();
var path;
for (var p = 0; p < paths.getLength(); p++) {
path = paths.getAt(p);
for (var i = 0; i < path.getLength(); i++) {
bounds.extend(path.getAt(i));
}
}
return bounds;
}
}
// Polygon containsLatLng - method to determine if a latLng is within a polygon
google.maps.Polygon.prototype.containsLatLng = function(latLng) {
// Exclude points outside of bounds as there is no way they are in the poly
var bounds = this.getBounds();
if(bounds != null && !bounds.contains(latLng)) {
return false;
}
// Raycast point in polygon method
var inPoly = false;
var numPaths = this.getPaths().getLength();
for(var p = 0; p < numPaths; p++) {
var path = this.getPaths().getAt(p);
var numPoints = path.getLength();
var j = numPoints-1;
for(var i=0; i < numPoints; i++) {
var vertex1 = path.getAt(i);
var vertex2 = path.getAt(j);
if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng()) {
if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
inPoly = !inPoly;
}
}
j = i;
}
}
return inPoly;
}
Try getting rid of the form and instead set the onClick of the 'Go!' button to showAddress(). I tested this in IE7, Chrome, and Firefox and it worked.
You may want to try using jQuery to run your initialization code and for ajax. Instead of using body.onload, use this:
$(function(){
initialize();
}) ;
And for ajax:
$.ajax({
url: "xmloutput2.xml",
success: function(data){
// handle result
}
});
If the problem is that your form is submitting to the server and causing a page reload, you need to return false from the showAddress() function, and use onsubmit="return showAddress();":
<form onsubmit="return showAddress();" action="#">
<input id="search" size="60" type="text" value="" />
<input type="submit" value="Go!" />
<input type="button" onclick="clearmarkers();" value="Clear markers" />
</form>
...
function showAddress () {
....
return false ;
}
Try specifying version
<script type="text/javascript" src="http://maps.google.com/maps/api/js?v=3.19"></script>
Your getting the experimental version if you do not specify a version. I found the experimental version has problems with IE11
Related
I am working on a website in which I want to make a circle on google map either around current location or some manual address.
Users will have option to decide whether they want to make circle around current location or some random address they will provide. (Users would have the option to put manual address inside current location as shown below in an image)
Now we also need to make sure that circle is of particular radius (0-20/70km from the current location) as well and user needs to decide that as well. (The line beneath the current location will decide the radius which users can move here and there 0-70km)
For example: user want to create a circle from current location till 30KM or user want to create a circle from some random address till 20KM.
The HTML code which I have used in order to make a search bar for search radius is:
<div class="input-searchradius">
<input class="form-control search_radius mb-4" type="text" placeholder="search radius">
</div>
Problem Statement:
(1) I am wondering what changes I need to make or code I need to add so that the items are being searched around a specific radius. I think, I need to integrate the code Google Maps circle but I am not sure how I can do that.
(2) On hit of search radius on the website the following options/screen will appear at the bottom:
Let's try to give you some first steps, I would no code the whole app, but rather give you some guide lines in to how to solve the small subproblems that you have:
Adding a circle in a map
Well, for this you have many different options for input, but the most important part is the addCircle function:
function addCircle(center){
circle = new google.maps.Circle({
map: map, //The existing map
center: center,
radius: 200, //This will be modified afterwards
zindex: 100
});
}
The center could come from a click for example:
// 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);
});
OR by getting the position of a certain address (This is documented as well), OR whatever method (drag and drop the circle, drag the marker blablabla)
Adding a dynamic radius
Well, if we know that the radius of the Circle is given in meters, then is very easy to give the addCircle function the correct radius. For example, 20km -> 20 000 meters. So you just have to be able to access radius when calling addCircle (it can be an argument, a global variable... your choice).
We are done with the drawing part, lets now search within that circle.
Getting only the markers inside the circle
There is a prerequisite here, to have all the markers of your map. You may have an array of places that you get from a database or maybe you get the markers from Google Maps API (Place search for example).
After that you will have to compute the distance between those markers and your given center, and check if the distance is smaller than your radius (with computeDistanceBetween is very easy), so you will know which markers are valid for you.
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;
The rest of the job should be as easy, place the markers in the map and do whatever you like with this information.
EXTRAS
As a further help there are a pair of examples/answers that may be useful for you:
Full Google Map API example, very easy step by step guide.
Radius search using places, a good answer in to how to do radius search.
Example of radius search, open F12 and debug the code if you like, but it is easy to follow.
EDIT**: I did not realize that 2 of these link where also pointed out in the comments.
I recommend using a worker thread to do the searching to free up the UI thread by doing the searching in the background. This is also useful if the user moves the circle or expands/contracts it as the previous search/render of matching markers can be abandoned,
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;
}
The "Toolbox" functions referred to are : -
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;
}
In you mainline you need to add listeners like: -
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
Cheers Richard
Following #SirPeople suggestions here is the complete code that addresses your core problem statement of getting location input from user, update map, and set dynamic radius around it.
here is JS Fiddle link 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="" width="16" height="16" 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>
This is my code, When i am calling removeMarkers(), it's not removing the markers.
function receiver(data, textStatus, XMLHttpRequest) {
var json = JSON.parse(data);
for (var i = 0; i < json.length; i++) {
var lat = json[i]["lat"];
var lng = json[i]["lng"];
// push object into features array
features.push({ position: new google.maps.LatLng(lat,lng) });
}
features.forEach(function(feature) {
var marker1 = new google.maps.Marker({
position: feature.position,
//icon: icons[feature.type].icon,
map: map
});
});
gmarkers.push(marker1);
}
function removeMarkers(){
for(i=0; i<gmarkers.length; i++){
gmarkers[i].setMap(null);
}
}
This is my full code. For displaying places(church) that which i saved in my database along the route from origin to destination. If i changed the origin and destination i want to remove old markers and displaying new markers without refreshing the page.
css
<style>
#map {
height: 100%;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
html
<div id="map" height="460px" width="100%"></div>
<input type="text" id="distance" value="3" size="2">
<input type="text" id="from" />to
<input type="text" id="to" />
<input type="submit" onClick="route()" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=api_ key&libraries=places"></script>
<script src="https://cdn.rawgit.com/googlemaps/v3-utility-library/master/routeboxer/src/RouteBoxer.js" type="text/javascript"></script>
javascript
<script>
var map;
var marker;
var infowindow;
var messagewindow;
var boxpolys = null;
var directions = null;
var routeBoxer = null;
var distance = null; // km
var service = null;
var gmarkers = [];
var boxes = null;
var coordinates=null;
var features = [];
var gmarkers = [];
<?php
echo "
var lat={$lat};
var lng={$lng};
"
?>
function initialize() {
var location = {lat: 10.525956868983068, lng:76.21387481689453};
map = new google.maps.Map(document.getElementById('map'), {
center: location,
zoom: 13
});
service = new google.maps.places.PlacesService(map);
routeBoxer = new RouteBoxer();
directionService = new google.maps.DirectionsService();
directionsRenderer = new google.maps.DirectionsRenderer({
map: map
});
}
function route() {
removeMarkers()
clearBoxes();
distance = parseFloat(document.getElementById("distance").value) * 0.1;
var request = {
origin: document.getElementById("from").value,
destination: document.getElementById("to").value,
travelMode: google.maps.DirectionsTravelMode.DRIVING
}
directionService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsRenderer.setDirections(result);
var path = result.routes[0].overview_path;
boxes = routeBoxer.box(path, distance);
drawBoxes();
findPlaces(0);
} else {
alert("Directions query failed: " + status);
}
});
}
function drawBoxes() {
boxpolys = new Array(boxes.length);
for (var i = 0; i < boxes.length; i++) {
boxpolys[i] = new google.maps.Rectangle({
bounds: boxes[i],
fillOpacity: 0,
strokeOpacity: 1.0,
strokeColor: '#000000',
strokeWeight: 0,
map: map
});
}
}
function findPlaces(searchIndex) {
var request = {
bounds: boxes[searchIndex],
};
coordinates = boxes[searchIndex].toString().match(/[0-9]+\.[0-9]+/g);
$.ajax({
url:"http://localhost/church_finder/index.php/MapController/search_church",
type:'POST',
data:{coordinates:coordinates},
//dataType:'json',
success: receiver
});
if (status != google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT) {
searchIndex++;
if (searchIndex < boxes.length)
findPlaces(searchIndex);
} else {
setTimeout("findPlaces(" + searchIndex + ")", 1000);
}
}
function clearBoxes() {
if (boxpolys != null) {
for (var i = 0; i < boxpolys.length; i++) {
boxpolys[i].setMap(null);
}
}
boxpolys = null;
}
function receiver(data, textStatus, XMLHttpRequest) {
var json = JSON.parse(data);
for (var i = 0; i < json.length; i++) {
var lat = json[i]["lat"];
var lng = json[i]["lng"];
features.push({ position: new google.maps.LatLng(lat,lng) });
}
features.forEach(function(feature) {
var marker1 = new google.maps.Marker({
position: feature.position,
map: map
});
});
gmarkers.push(marker1);
}
function removeMarkers(){
for(i=0; i<gmarkers.length; i++){
gmarkers[i].setMap(null);
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
enter image description here
function removeMarkers(){
features.length=0;
if (gmarkers != []) {
for(var i=0; i<gmarkers.length; i++){
gmarkers[i].setMap(null);
}
}
gmarkers =[];
}
Your app throws loads of errors in the console and this is just a temporary fix to what you are asking for:
change the origin and destination, I want to remove old markers and
displaying new markers without refreshing the page
call your initialize() function with a script tag in your HTML file. This is where you include your API key for the project:
<script defer async src="https://maps.googleapis.com/maps/api/js?
key=YOUR_KEY&callback=initialize">
Where is the map element passed in the map constructor?
Create a div element in your HTML to contain the map and add CSS style to it
#map {
height: 100%;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
}
This is actually in the Google Maps API documentation;
Always set the map height explicitly to define the size of the div
element that contains the map.
Now into your JS code...
What are you using var service for? var service is firstly declared in the global scope with a null value and then assigned to a PlacesService constructor...but service is not defined simply because you have not included the places library in your script tag:
ADD PLACES LIBRARY IF YOU WANT TO USE PLACES API
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?
key=YOUR_API_KEY&_ADD_libraries=places_PLEASE_"></script>
Because var service cannot be run, just remove it (it actually does not do anything but adding lines in your code right now) along with the RouteBoxer()
REMOVE THESE LINES - THEY ARE USELESS RIGHT NOW
service = new google.maps.places.PlacesService(map);
routeBoxer = new RouteBoxer();
If you do this, without refreshing the page, you clear the markers for each subsequent requests. You get loads of errors still because you have both syntax and logic bugs in your app.
Get a BIN here
So I am trying to make a simple application that will allow the user to search for restaurants and have the results show as markers on the map and as text below. The results object that returns from the textSearch doesn't provide detailed information like: phone number, pictures, etc. So i decided to create an array of place id's pushed from the results object, get the place details for each id, then push that into an array. The problem I get is a message from google saying I'm over my quota and I think it's because I'm requesting the place details for every single search result.
Is there a way I can request the place details only for the marker I click? Or is there a better solution to my problem? Thank you in advance for your help.
<!DOCTYPE html>
<html>
<head>
<title>gMap test</title>
<style type="text/css">
#map-canvas{
height:500px;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
<script type="text/javascript">
function performSearch(){
var locationBox;
var address = document.getElementById("address").value;
var searchRadius = metricConversion(document.getElementById("radius").value);
//gMaps method to find coordinates based on address
geocoder.geocode({'address':address}, function(results,status){
if(status == google.maps.GeocoderStatus.OK){
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map:map,
position: results[0].geometry.location
});
var latitude = results[0].geometry.location.A;
var longitude = results[0].geometry.location.F;
locationBox = new google.maps.LatLng(latitude, longitude);
}else{
errorStatus(status);
return;
}
//search request object
var request = {
query: document.getElementById('keyword').value,
location: locationBox,
radius: searchRadius,
//minPriceLvl: minimumPrice,
//maxPriceLvl: maximumPrice,
types: ["restaurant"]
}
//search method. sending request object and callback function
service.textSearch(request, handleSearchResults);
});
};
var latLngArray = [];
var placeIdArray = [];
//callback function
function handleSearchResults(results,status){
if( status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
placeIdArray.push(results[i].place_id)
latLngArray.push(results[i].geometry.location);
};
for(var j = 0; j<placeIdArray.length; j++){
service.getDetails({placeId: placeIdArray[j]},getDetails)
};
}
else{errorStatus(status)};
};
var detailedArray = [];
function getDetails(results,status){
if (status == google.maps.places.PlacesServiceStatus.OK) {
detailedArray.push(results);
for(var i = 0; i<detailedArray.length; i++){
createMarker(detailedArray[i],i);
}
}
else{
errorStatus(status)
};
}
//array of all marker objects
var allMarkers = [];
//creates markers and info windows for search results
function createMarker(place, i) {
var image = 'images/number_icons/number_'+(i+1)+'.png';
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
html:
"<div class = 'markerPop'>" + "<h3>" + (i+1) + ". " + place.name + "</h3><br>" + "<p>Address: "
+ place.formatted_address + "</p><br>" + "<p> Price Range: "+ priceLevel(place.price_level)
+ "</p>" + "</div>",
icon: image
});
allMarkers.push(marker);
marker.infowindow = new google.maps.InfoWindow();
//on marker click event do function
google.maps.event.addListener(marker, 'click', function() {
//service.getDetails({placeId: placeIdArray[j]},getDetails)
//sets infowindow content and opens infowindow
infowindow.setContent(this.html);
infowindow.open(map,this);
});
//create new bounds object
var bounds = new google.maps.LatLngBounds();
//iterates through all coordinates to extend bounds
for(var i = 0;i<latLngArray.length;i++){
bounds.extend(latLngArray[i]);
};
//recenters map around bounds
map.fitBounds(bounds);
};
var map;
var service;
var geocoder;
var infowindow;
function initialize(location){
var mapOptions = {
center: new google.maps.LatLng(37.804, -122.271),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);
service = new google.maps.places.PlacesService(map)
infowindow = new google.maps.InfoWindow();
};
$(document).ready(function(){
initialize();
$('#search').on('click', function(){
removeMarkers();
performSearch();
});
});
//::::::Random Functions:::::::
//Clears all markers between searches
function removeMarkers(){
for(var i = 0; i<allMarkers.length;i++){
allMarkers[i].setMap(null);
};
};
//converts miles to meters for search object
function metricConversion(miles){
var meters;
meters = miles * 1609.34;
return meters;
}
//converts number value to $ sign
function priceLevel(number){
var moneySigns = ""
for(var i =0;i<=number;i++){
moneySigns += "$";
};
return moneySigns;
}
//errors for search results
function errorStatus(status){
switch(status){
case "ERROR": alert("There was a problem contacting Google Servers");
break;
case "INVALID_REQUEST": alert("This request was not valid");
break;
case "OVER_QUERY_LIMIT": alert("This webpage has gone over its request quota");
break;
case "NOT_FOUND": alert("This location could not be found in the database");
break;
case "REQUEST_DENIED": alert("The webpage is not allowed to use the PlacesService");
break;
case "UNKNOWN_ERROR": alert("The request could not be processed due to a server error. The request may succeed if you try again");
break;
case "ZERO_RESULTS": alert("No result was found for this request. Please try again");
break;
default: alert("There was an issue with your request. Please try again.")
};
};
</script>
</head>
<body>
<div id="map-canvas"></div>
<div id="searchBar">
<h3>search options</h3>
Location:<input type="text" id="address" value="enter address here" /><br>
Keyword<input type="text" id="keyword" value="name or keyword" /><br>
Advanced Filters:<br>
Search Radius:<select id="radius">
<option>5</option>
<option>10 </option>
<option>15 </option>
<option>20 </option>
<option>25 </option>
</select>miles<br>
<div id="minMaxPrice">
Min Price<select id="minPrice">
<option>$</option>
<option>$$</option>
<option>$$$</option>
<option>$$$$</option>
</select>
Max Price<select id="maxPrice">
<option>$</option>
<option>$$</option>
<option>$$$</option>
<option>$$$$</option>
</select>
</div>
<input type="button" id="search" value="Submit Search"/><br>
</div>
<div id='searchResults'>
</div>
</body>
</html>
The radarSearch example in the documentation requests the details of the marker on click.
code snippet:
var map;
var infoWindow;
var service;
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(-33.8668283734, 151.2064891821),
zoom: 15,
styles: [{
stylers: [{
visibility: 'simplified'
}]
}, {
elementType: 'labels',
stylers: [{
visibility: 'off'
}]
}]
});
infoWindow = new google.maps.InfoWindow();
service = new google.maps.places.PlacesService(map);
google.maps.event.addListenerOnce(map, 'bounds_changed', performSearch);
}
function performSearch() {
var request = {
bounds: map.getBounds(),
keyword: 'best view'
};
service.radarSearch(request, callback);
}
function callback(results, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
for (var i = 0, result; result = results[i]; i++) {
createMarker(result);
}
}
function createMarker(place) {
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: {
// Star
path: 'M 0,-24 6,-7 24,-7 10,4 15,21 0,11 -15,21 -10,4 -24,-7 -6,-7 z',
fillColor: '#ffff00',
fillOpacity: 1,
scale: 1 / 4,
strokeColor: '#bd8d2c',
strokeWeight: 1
}
});
google.maps.event.addListener(marker, 'click', function() {
service.getDetails(place, function(result, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
var htmlStr = "<b>"+result.name+"</b><br>";
if (result.website) htmlStr += "<a href='"+result.website+"'>"+result.website+"</a><br>";
if (result.adr_address) htmlStr += result.adr_address+"<br>";
infoWindow.setContent(htmlStr);
infoWindow.open(map, marker);
});
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&libraries=places"></script>
<div id="map-canvas"></div>
I had the same issue some time ago. The geocoding function by google is done in order to avoid the user executing it on a large set of data (and then, avoid you to get a large amount of geocoded address easily).
My solution was to execute the geocoding function only when the user choose a particular place, and then, display this particular data (handled by the click on the pin).
I think it would be very useful to initiate a jsfiddle with a working version of your code.
Basically on your function :
google.maps.event.addListener(marker, 'click', function() {
//Execute geocoding function here on marker object
//Complete your html template content
infowindow.setContent(this.html);
infowindow.open(map,this);
});
I have a project whereby a route is generated by the google maps directions service, and I have a loop to obtain all coordinates along it (using a functioned called showPathInfo - see base of query for full HTML):
var tp = result.routes[0].legs[i].steps[j].path[k]; // local variable
var z = new google.maps.LatLng(tp.lat(),tp.lng()); // local variable
I wish to make a call to the elevation service during each loop iteration using:
elevation = getElevation(z); // global variable but NOT an array
where getElevation is a function (see base of query for full HTML).
For some reason, even though the coords are correctly passed to the function, and are rendered appropriately into a getElevationForLocations object (I have checked this by having the getElevation return variables before the getElevationForLocations call); the service returns "undefined" for
return results[0].elevation;
I am interested in getting this solution to work to take advantage of the higher accuracy afforded to individual elevation service requests, and am trying to avoid batch requests with locations[] as a full array or using the getElevationForPath function.
Admittedly there is the problem of a limit to the number of single elevation requests that can be made per second and in total, but I have tried slowing down the code execution and limiting the distances in order to get this to work at least once:
function wait() { setTimeout(function () {
elevation = getElevation(z); // here defined as a global variable
}, 500);}
wait();
Does anyone have any ideas why such a nested call like this cannot work?
The full fiddle html code is as follows:
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>html, body, #map-canvas {height: 100%;margin: 0px;padding: 0px}</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true"></script>
<script>
var rendererOptions = { draggable: true };
var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);;
var directionsService = new google.maps.DirectionsService();
var infowindow = new google.maps.InfoWindow();
var map;
var elevation; // *******************
var elevator;
var start = new google.maps.LatLng(55.60289406109326, -2.88885779678822);
var wpnt1 = new google.maps.LatLng(55.59226543103951, -2.91247397661209);
var wpnt2 = new google.maps.LatLng(55.57330299699533, -2.88813963532448);
var wpnt3 = new google.maps.LatLng(55.58132161006218, -2.84357875585556);
var wpnt4 = new google.maps.LatLng(55.58602383263128, -2.87256672978401);
var wpnt5 = new google.maps.LatLng(55.60450928199337, -2.89154000580311);
var ended = new google.maps.LatLng(55.60289406109326, -2.88885779678822);
function initialize() {
elevator = new google.maps.ElevationService();
var mapOptions = { zoom: 10,center: start };
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById('directionsPanel'));
google.maps.event.addListener(directionsDisplay, 'directions_changed', function() {
document.getElementById('points').innerHTML = "";
showPathInfo(directionsDisplay.getDirections());
});
calcRoute();
} // ***** End of initialise function
function calcRoute() {
var request = {origin: start,destination: ended,
waypoints:[{location: wpnt1}, {location: wpnt2}, {location: wpnt3}, {location: wpnt4}, {location: wpnt5}],
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
function showPathInfo(result) {
var total = 0;
var ns = 0;
var pt = 0;
var myroute = result.routes[0];
document.getElementById('points').insertAdjacentHTML('beforeend', '<th>Point</th><th>Lat</th><th>Lon</th><th>Elevation</th>');
for (var i = 0; i < myroute.legs.length; i++) {
total += myroute.legs[i].distance.value;
ns += myroute.legs[i].steps.length;
for (var j = 0; j < myroute.legs[i].steps.length; j++) {
for (var k = 0; k < myroute.legs[i].steps[j].path.length; k++) {
var tp = myroute.legs[i].steps[j].path[k];
var z = new google.maps.LatLng(tp.lat(),tp.lng());
//function wait() { setTimeout(function () {
elevation = getElevation(z);
//}, 500);} // End of getAndWait
//wait();
document.getElementById('points').insertAdjacentHTML('beforeend',
'<tr><td>' + pt + '</td><td>' +
tp.lat().toFixed(7) + '</td><td>' +
tp.lng().toFixed(7) + '</td><td>' +
elevation + '</td></tr>');
pt += 1;
}
}
}
total = total / 1000.0;
document.getElementById('total').innerHTML = total + ' km';
document.getElementById('legs').innerHTML = myroute.legs.length;
document.getElementById('steps').innerHTML = ns;
}
function getElevation(z) {
var locations = [];
var clickedLocation = z;
locations.push(clickedLocation);
var positionalRequest = { 'locations': locations }
elevator.getElevationForLocations(positionalRequest, function(results, status) {
if (status == google.maps.ElevationStatus.OK) {
// Retrieve the first result
if (results[0]) {
return results[0].elevation;
} else {
return 'No results found';
}
} else {
return 'Elevation service failed due to: ' + status;
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas" style="float:left;width:70%; height:100%"></div>
<div id="directionsPanel" style="float:right;width:30%;height 25%">
<p>Total Distance: <span id="total"></span> Legs: <span id="legs"></span>Steps: <span id="steps"></span></p>
<table id="points"></table>
</div>
</body>
</html>
Postscript
In the end it was the use of a Bluebird promise loop that worked.
<script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.js"></script>
For the record I was not using node.js or any other functionality other than just plain js plus bluebird. Promises are dealt with in detail by many answers in StackOverflow so I recommend reading these and looking through the API: https://github.com/petkaantonov/bluebird/blob/master/API.md .
I am trying to adapt this Google Maps distance calculator to my needs, but am not overly familiar with plain Javascript, and only Jquery.
I am trying to modify one of the destination variables so that it pulls it from a text box instead.
Usually the line reads :
var destinationA = 'pe219px';
But I am trying to change it to the following, usually I would do this with a keyup function to update the value as the person types in jquery, but im not sure what im doing in plain javascript. This is what I have come up with so far, but it doesn't appear to do a lot :
function setValue() {
destinationA=parseInt(document.getElementById('deliverypostcode').value);
}
This is the example I am trying to modify
https://developers.google.com/maps/documentation/javascript/examples/distance-matrix
This is the whole code :
<!DOCTYPE html>
<html>
<head>
<title>Distance Matrix service</title>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map-canvas {
height: 100%;
width: 50%;
}
#content-pane {
float:right;
width:48%;
padding-left: 2%;
}
#outputDiv {
font-size: 11px;
}
</style>
<script>
var map;
var geocoder;
var bounds = new google.maps.LatLngBounds();
var markersArray = [];
var origin1 = new google.maps.LatLng(53.003604, -0.532764);
var origin2 = 'pe219px';
function setValue() {
destinationA=parseInt(document.getElementById('deliverypostcode').value);
}
var destinationB = new google.maps.LatLng(53.003604, -0.532764);
var destinationIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=D|FF0000|000000';
var originIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=O|FFFF00|000000';
function initialize() {
var opts = {
center: new google.maps.LatLng(53.003604, -0.532764),
zoom: 8
};
map = new google.maps.Map(document.getElementById('map-canvas'), opts);
geocoder = new google.maps.Geocoder();
}
function calculateDistances() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [origin1, origin2],
destinations: [destinationA, destinationB],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, callback);
}
function callback(response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
var outputDiv = document.getElementById('outputDiv');
outputDiv.innerHTML = '';
deleteOverlays();
for (var i = 0; i < origins.length; i++) {
var results = response.rows[i].elements;
addMarker(origins[i], false);
for (var j = 0; j < results.length; j++) {
addMarker(destinations[j], true);
outputDiv.innerHTML += origins[i] + ' to ' + destinations[j]
+ ': ' + results[j].distance.text + '<br>';
}
}
}
}
function addMarker(location, isDestination) {
var icon;
if (isDestination) {
icon = destinationIcon;
} else {
icon = originIcon;
}
geocoder.geocode({'address': location}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
bounds.extend(results[0].geometry.location);
map.fitBounds(bounds);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
icon: icon
});
markersArray.push(marker);
} else {
alert('Geocode was not successful for the following reason: '
+ status);
}
});
}
function deleteOverlays() {
for (var i = 0; i < markersArray.length; i++) {
markersArray[i].setMap(null);
}
markersArray = [];
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="content-pane">
<div id="inputs">
<form name="form1" method="post" action="">
<label for="deliverypostcode">Your Postcode</label>
<input type="text" name="deliverypostcode" id="deliverypostcode">
</form>
<p><button type="button" onclick="calculateDistances();">Calculate
distances</button></p>
</div>
<div id="outputDiv"></div>
</div>
<div id="map-canvas"></div>
</body>
</html>
Your function setValue is never called.
What if you delete it and just place the following line at the begining of calculateDistances ?
var destinationA= document.getElementById('deliverypostcode').value;
This works for me. Also, you don't need to parseInt your text input. Geocoding converts strings to a lat/long coordinates.