Draw a route on google map on click - javascript

What I am trying to do is on click google maps, place a marker, and draw a route between these markers. This works but the problem I'm facing is as follows: (please view the images of map)
(1) When I click three times on google map, the route is drawn perfectly. (meaning first I click A then B and then C location)
(2) Then if I click a forth time on google map, the location must be D but the map looks as follows:
Here the B location is replaced or hidden and in place of B, C is displayed and same...
(3) If I click a fifth time on google map, the location should be E, but the map looks like:
In short, if I click five times on google map, the route should be 'A,B,C,D,E'. Instead it is displayed as 'A,E,F,G,H'.
The full code is as follows:
<script>
var waypts=[];
var ways=[];
function initialize() {
var geocoder = new google.maps.Geocoder();
var mapOptions = {
zoom: 11,
center: new google.maps.LatLng(23.0171240, 72.5330533),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map_canvas'),mapOptions);
google.maps.event.addListener(map, 'click', function(e) {
placeMarker(e.latLng, map);
var input=e.latLng;
var lat = parseFloat(input.lat());
var lng = parseFloat(input.lng());
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var add=results[1].formatted_address;
waypts.push({
location:add,
stopover:true
});
//alert(JSON.stringify(waypts));
if(waypts.length>2) {
for ( var i = 1; i <= waypts.length - 2 ; i++) {
ways.push({
location:waypts[i].location,
stopover:true
});
}
}
makeroute(waypts);
}
});
});
<!-- ************** for route between markers ******************* -->
function makeroute(waypts){
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers: false, //false it if you want a marker from the direction service
polylineOptions: {
strokeColor: 'green', //"black",
strokeOpacity: 1.0,
strokeWeight: 3
}
});
var start = waypts[0].location;//"Bopal, Ahmedabad, Gujarat, India";
var end = waypts[waypts.length-1].location;//"Nikol, Ahmedabad, Gujarat, India";
if(waypts.length>1) {
var request = {
origin:start,
destination:end,
waypoints:ways,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
directionsDisplay.setMap(map);
google.maps.event.addDomListener(window, 'load', initialize);
}
}
}
function placeMarker(position, map) {
var marker = new google.maps.Marker({
position: position,
//map: map
});
// map.panTo(position);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
LATER UPDATE
I use directionsDisplay.setPanel(document.getElementById('a')); for the full route information.
It display when ever I click on google map, the routes is repeat. Meaning on the first click A, on second click A to B, on third A to B to C not B to C etc. It also display that some points merged. For example B and C have same location and on the map C is only displayed.

You need to clear out the waypoints array ("ways") each time you add a new point. Each time you add a point, the start point stays the same but the old end point needs to be added to the waypoints array, and the new point is the end point. Currently you never clear out the "ways" array. Changing this:
if(waypts.length>2) {
for ( var i = 1; i <= waypts.length - 2 ; i++) {
ways.push({
location:waypts[i].location,
stopover:true
});
}
}
makeroute(waypts);
To this:
if(waypts.length>2) {
ways = [];
for ( var i = 1; i <= waypts.length - 2 ; i++) {
ways.push({
location:waypts[i].location,
stopover:true
});
}
}
makeroute(waypts);
Works for me.

Related

Google Maps geocode() loop to place markers

I have an array with location data with one of the items being an address - ie. "123 Main Street, San Francisco, California". I want to take that address, turn it into coordinates, then use those coordinates to plot a marker on the map. To do this, I know I need to use geocode(), so I added that part into my loop.
If I were to use latitude and longitude in my array instead of the address, I can get this to work fine. But, since I added geocode() into my loop, I can only get the first location in the array to display a marker.
I have seen some similar questions on here that suggest using callback() but I did not understand it. I've also seen a suggestion to add a delay to geocode() of 0.5 seconds which worked for the poster, but comments said it may not load all locations on slower internet speeds.
How can I fix this to show all locations in the correct way?
// Create the map with markers.
function createmap(zoomlevel, centerpos, showDot)
{
// Create the map canvas with options.
var map = new google.maps.Map(document.getElementById('map-canvas'), {
scrollwheel: false,
draggable: true,
mapTypeControl: false,
zoom: zoomlevel,
center: new google.maps.LatLng(40.577453, 2.237408), // Center the map at this location.
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker, i;
// For each location in the array...
for (i = 0; i < locations.length; i++)
{
// Get the coordintes for the address.
var geocoder = new google.maps.Geocoder();
var address = locations[i][5]; // ***This variable will output the address.***
geocoder.geocode( { 'address': address }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var location_latitude = results[0].geometry.location.lat();
var location_longitude = results[0].geometry.location.lng();
// Create the map marker icon (SVG file).
var marker_icon = {
url: '//'+domain+'/__NEW__/_backend/assets/img/map-marker.svg',
anchor: new google.maps.Point(25,50),
scaledSize: new google.maps.Size(50,50)
}
// Place the marker on the map.
var marker = new google.maps.Marker({
position: new google.maps.LatLng(location_latitude, location_longitude),
map: map,
icon: marker_icon
});
}
});
}
}
This is how I am placing map markers on Google Maps:
<script type="text/javascript">
let map;
let parameters;
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: { lat: #Model.Latitude , lng: #Model.Longitude },
zoom: #Model.Zoom,
});
#foreach (var asset in dbService.Assets)
{
#if (asset.State != Models.AssetState.deleted)
{
#:parameters = 'Id = #asset.Id\n' + 'Temperature = #asset.Temperature\n' + 'Moisture = #asset.Moisture\n';
#:setMarker('#asset.Latitude', '#asset.Longitude', '#asset.State');
}
}
}
function getIconByState(state) {
if (state == 'non_functional') {
return 'non-functional.png';
}
else if (state == 'under_maintenance') {
return 'under-maintenance.png';
}
else if (state == 'functional') {
return 'functional.png';
}
}
function setMarker(lat, lng, state) {
var markerjs = new google.maps.Marker({
icon: getIconByState(state),
position: new google.maps.LatLng(lat, lng),
});
markerjs.setMap(map);
let infowindow = new google.maps.InfoWindow({
content: parameters,
});
markerjs.addListener("click", () => {
infowindow.open(map, markerjs);
});
}
</script>
//this is how to use the callback
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR-API-KEY&callback=initMap&libraries=&v=weekly"
defer></script>
In this code, I use the latitude and longitude to place a marker on the Map.
If you want to extract the latitude and longitude from an address, then use geocoder API in the following way:
<script type="text/javascript">
function setCoordinates() {
let address = document.getElementById('zip').value;
if (address) {
let geocoder = new google.maps.Geocoder();
if (geocoder) {
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
document.getElementById('latitude').value = results[0].geometry.location.lat();
document.getElementById('longitude').value = results[0].geometry.location.lng();
}
else {
console.log('geocoding failed');
}
});
}
}
else {
alert('Please enter postal code to use this functionality');
}
}
</script>

Google Maps API v3 Markers only load sometimes

I have a map-making tool that is built with the Google Maps API V3. It allows users to enter two or more locations and produce a map and route. I also have a checkbox that, when clicked, shows markers indicating nearby points of interest.
When I first built the tool, I think it worked well every time. Recently, though, I've noticed that the markers do not always appear when the checkbox is clicked. The map and routing work fine, but the markers only work occasionally. This error seems to occur when they don't work:
Uncaught ReferenceError: map is not defined
It references a section of the "cmarkers" section of javascript (see below).
Background detail: This is part of a Rails web app and a webpage / layout called "Itineraries". When you land on the itineraries webpage and click on the "Map Maker" icon, the map-making tool appears. It's loaded in an i-frame, it's called "map.html.erb", and the map view lives in /views/itineraries. All of the javascript for the map maker lives in the Itineraries layout file, however.
Based on reviewing these posts, I think it might be something in the way that I've ordered or initialized the code, and I think the main culprit is likely in that "cmarkers" section of the code.
Google Maps API Sometimes Not Showing Markers
Google maps api(v3) doesn't show markers
Google Maps API v3 javascript Markers don't always load
I've tried several different changes, but each has either not worked or stopped the map from initializing. Here is the javascript; please note that the API key and other small sections are redacted. Below it is the code for the markers.
<script src="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&sensor=false"></script>
<script type='text/javascript'>
$(function(){
var directionsDisplay;
var map;
function overlaysClear() {
if (markersArray) {
for( var i = 0, n = markersArray.length; i < n; ++i ) {
markersArray[i].setVisible(false);
}
}
}
function overlaysShow() {
if (markersArray) {
for( var i = 0, n = markersArray.length; i < n; ++i ) {
markersArray[i].setVisible(true);
}
}
}
$("#showmapview").click(function() {
overlaysClear();
$('#mapeach').attr('checked', false);
});
$('#mapeach').change(function() {
if( $('#mapeach').attr("checked")) {
overlaysShow();
}
else {
overlaysClear();
}
});
cmarkers();
google.maps.event.addDomListener(window, 'load', initialize);
});
var directionsService = new google.maps.DirectionsService();
var markersArray = [];
var arrInfoWindows = null;
function initialize() {
var rendererOptions = {
draggable: true,
panel:document.getElementById('directions_panel')
};
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var chicago = new google.maps.LatLng(41.850033, -87.6500523);
var mapOptions = {
zoom: 6,
center: chicago,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
directionsDisplay.setMap(map);
}
function calcRoute() {
var start = document.getElementById("start").value;
var end = document.getElementById("end").value;
var waypts = [];
var checkboxArray = document.getElementById("waypoints");
for (var i = 0; i < checkboxArray.length; i++) {
waypts.push({
location:checkboxArray[i].value,
stopover:true
});
}
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: optimize,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
}
});
};
function cmarkers() {
$.getJSON( "/mapeach.js", {}, function( data ) {
$.each( data, function( i, item ) {
var loc = item.mainlocation;
$("#markers").append('<li>' + loc.nickname + '</li>');
var marker = new google.maps.Marker({
position: new google.maps.LatLng(+loc.latitude, +loc.longitude),
map: map,
title: loc.nickname,
});
markersArray.push(marker);
var infowindow = new google.maps.InfoWindow({
content: '<a class="clink" href="/spots/'+ loc.id +'/'+ loc.nickname +'" target="_blank">'+ loc.nickname +'</a>'
});
google.maps.event.addListener(marker, 'click', function() {
if (arrInfoWindows != null) {
arrInfoWindows.close();
}
infowindow.open(map,marker);
arrInfoWindows = infowindow;
});
});
});
};
</script>
The mapeach.js file is formatted as below:
[{"mainlocation":{"latitude":"40.706352","nickname":"First Location","id":100000,"longitude":"-73.987650"}},{"mainlocation":{"latitude":"34.061148","nickname":"Second Location","id":100001,"longitude":"-118.273067"}}]
I was able to solve this problem by moving the cmarkers code inside the initialize. I think that the javascript wasn't making clear that the map variable in the initialize was also the map variable in the cmarkers function (sorry if the language isn't precise; I'm not great in js). See below:
function initialize() {
var rendererOptions = {
draggable: true,
panel:document.getElementById('directions_panel')
};
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var chicago = new google.maps.LatLng(41.850033, -87.6500523);
var mapOptions = {
zoom: 6,
center: chicago,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
directionsDisplay.setMap(map);
cmarkers();
function cmarkers() {
$.getJSON( "/mapeach.js", {}, function( data ) {
$.each( data, function( i, item ) {
var loc = item.mainlocation;
$("#markers").append('<li>' + loc.nickname + '</li>');
var marker = new google.maps.Marker({
position: new google.maps.LatLng(+loc.latitude, +loc.longitude),
map: map,
title: loc.nickname,
});
markersArray.push(marker);
var infowindow = new google.maps.InfoWindow({
content: '<a class="clink" href="/spots/'+ loc.id +'/'+ loc.nickname +'" target="_blank">'+ loc.nickname +'</a>'
});
google.maps.event.addListener(marker, 'click', function() {
if (arrInfoWindows != null) {
arrInfoWindows.close();
}
infowindow.open(map,marker);
arrInfoWindows = infowindow;
});
});
});
};
Special credit to this post for giving me the idea: can't see google marker

Google Map API is Extremely Slow

So I'm setting up a dynamic Google map on all of the pages on the site to show the locations you can see on every page to help users understand the locations.
It works, but works EXTREMELY slow, so slow that if it has about 40+ it can take around 1 minute to load the map and if it's more locations than that on a page it just get stuck and does not load the map.
Here is a link to see the map:
http://www.exchange-currency.org/wakefield/
And Here's the code as it is on the website, you can also see the code with view source but note the addresses are from a string with php, you can see the output on the view source of the page.
<script type="text/javascript" src="http://maps.google.com/maps/api/js?q=<?php the_title(); ?>&key=AIzaSyDeyknfWm0qmejgXZh_VXihNcHbidewODQ"></script>
<script type="text/javascript">
var delay = 10;
var infowindow = new google.maps.InfoWindow();
var latlng = new google.maps.LatLng();
var mapOptions = {
zoom: 4,
center: latlng,
scrollwheel: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var geocoder = new google.maps.Geocoder();
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var bounds = new google.maps.LatLngBounds();
function geocodeAddress(address, next) {
geocoder.geocode({address:address}, function (results,status)
{
if (status == google.maps.GeocoderStatus.OK) {
var p = results[0].geometry.location;
var lat=p.lat();
var lng=p.lng();
createMarker(address,lat,lng);
}
else {
if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
nextAddress--;
delay++;
} else {
}
}
next();
}
);
}
function createMarker(add,lat,lng) {
var contentString = add;
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat,lng),
map: map,
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(map,marker);
});
bounds.extend(marker.position);
}
var locations = [<?php echo $locationAddresses; ?>];
var nextAddress = 0;
function theNext() {
if (nextAddress < locations.length) {
setTimeout('geocodeAddress("'+locations[nextAddress]+'",theNext)', delay);
nextAddress++;
} else {
map.fitBounds(bounds);
}
}
theNext();
</script>
What can I do to make it work in a normal speed so its actually usable?
Here's a link to a page with more locations so you'll see what I'm talking about:
http://www.exchange-currency.org/montreal/
Thanks!
Edit:
Also if there is a way to make it load async and with clusters instead of multiple markers that would be great, can't seem to get it figured out =/

Show nearby Places in Google Maps in Meteor

I am trying to get nearby places like gym, atm on google maps. For this I have used dburles:google-maps package. I followed the instructions on Google Maps API and did the following. The map is generated, and the center marker is shown but I am not able to generate the places markers. Can anyone point out what I am doing wrong?
This is the JS code.
Template.map.helpers({
exampleMapOptions: function() {
// Make sure the maps API has loaded
if (GoogleMaps.loaded()) {
// Map initialization options
var data=Test.findOne().address.geopoint;
var lat=data[1];
var lng=data[0];
console.log([lat,lng]);
return {
center: new google.maps.LatLng(lat, lng),
zoom: 14
};
}
}
});
Template.map.onCreated(function() {
var self = this;
GoogleMaps.ready('exampleMap', function(map) {
var marker;
// Create and move the marker when latLng changes.
self.autorun(function() {
var data=Test.findOne().address.geopoint;
var lat=data[1];
var lng=data[0];
if (! lat && ! lng)
return;
// If the marker doesn't yet exist, create it.
if (! marker) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
map: map.instance
});
}
// The marker already exists, so we'll just change its position.
else {
marker.setPosition([lat,lng]);
}
// Center and zoom the map view onto the current position.
map.instance.setCenter(marker.getPosition());
map.instance.setZoom(14);
var pyrmont = new google.maps.LatLng(lat,lng);
// map = new google.maps.Map(document.getElementById('exampleMap'), {
// center: pyrmont,
// zoom: 15
// });
var request = {
location: pyrmont,
radius: '5000',
types: ['store']
};
service = new google.maps.places.PlacesService(map);
service.nearbySearch(request, callback);
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createMarker(results[i]);
}
}
}
});
});
});
Solved the issue by replacing map with map.instance in places search.

How to use an existing marker for Google Maps API directionService instead of defining a new one?

I'm using Google Maps API to show directions to a location.
On page load, I set a marker on the map: (FYI: I haven't included the coordinates, but you can assume they are defined)
var destination = [xxx, yyy, 11, xxx, yyy]; //x-coord,y-coord,zoom,x-center,x-center
var dublin = [xxx, yyy, 11, xxx, yyy]; //x-coord,y-coord,zoom,x-center,x-center
var directionsService = new google.maps.DirectionsService();
var directionsDublin;
function initialize() {
directionsDublin = new google.maps.DirectionsRenderer();
var centerMap = new google.maps.LatLng(destination[3],destination[4]);
map = new google.maps.Map(document.getElementById('map-canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: centerMap,
zoom: destination[2]
});
marker1 = new google.maps.Marker({
position: new google.maps.LatLng(destination[0], destination[1]),
map: map
});
marker1.setAnimation(google.maps.Animation.DROP);
}
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, this);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
So the code above displays the map with a marker on it.
I now have a button #tNorth. Clicking it will show a route from a defined location. Clicking again will remove the route and return to the original view.
$(document).ready(function() {
$( "#tNorth" ).on( "click", function() {
if ($("#north").css('display') != 'none') {
//set zoom and center
map.setZoom(destination[2]);
map.setCenter(new google.maps.LatLng(destination[3], destination[4]));
//remove the route
directionsDublin.setMap(null);
//remove the text
$("#north").css('display':'none');
}
else {
//create travel route
var request2 = {
origin: new google.maps.LatLng(dublin[0], dublin[1]),
destination: new google.maps.LatLng(destination[0], destination[1]),
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
//display route on map
directionsDublin.setMap(map);
directionsService.route(request2, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDublin.setDirections(result);
}
});
//add the text
$("#north").css('display':'block');
}
});
});
This is my first use of the Maps API so I'm pretty happy!!
However, when the route is displayed, it places 2 new markers on the page. Since the destination marker is already on the page, it gets overlayed by the new marker.
Is there a way for me to, instead of defining destination: new google.maps.LatLng(destination[0], destination[1]), that I could instead define something like destination: marker1??
It would be nicer than displaying two markers over each other...
Use {suppressMarkers:true} in the DirectionRendererOptions to prevent the DirectionsRenderer from adding markers to the map (it will still show the route)
directionsDublin = new google.maps.DirectionsRenderer({suppressMarkers:true});

Categories

Resources