Google maps and asynchronous javascript - javascript

In my controller, I have this function to get the coordinates of an address:
function get_coor(city, callback)
{
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { "address": city }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
var location = results[0].geometry.location;
callback(location.lat(), location.lng());
}
else
{
callback(); // callback for error
}
});
}
Doing this works fine and outputs the correct latitude:
get_coor('Amsterdam', function(lat, lng) {
console.log('here is my lat:' + lat);
});
I want to use these coordinates in my google map, so I made it like this:
get_coor('Amsterdam', function(lat, lng) {
$scope.map = {center: {latitude: lat, longitude: lng }, zoom: 4 };
$scope.options = {scrollwheel: false};
$scope.marker = {
coords: {
latitude: lat,
longitude: lng
},
show: false,
id: 0
};
$scope.windowOptions = {
visible: false
};
$scope.onClick = function() {
$scope.windowOptions.visible = !$scope.windowOptions.visible;
};
$scope.closeClick = function() {
$scope.windowOptions.visible = false;
};
});
The map is centered correctly, so $scope.map = {center: {latitude: lat, longitude: lng }, zoom: 4 }; seems to work fine, but the marker is placed on it's default location, not Amsterdam. When I view the source, the coordinates of the marker are the right coordinates.
My guess is that it has something to do with asynchronous javascript, but I'm very new to this... Anyone who can help?
UPDATE:
Refreshing the page puts the marker on the right position, but it persists on first load.

Since geocoder.geocode function executes asynchronously and ui-gmap-marker is a child directive, you should call $apply() explicitly in that case:
$scope.marker = {
coords: {
latitude: location.lat(),
longitude: location.lng()
},
title: 'Amsterdam',
show: true,
id: 1
};
$scope.$apply();
Working example
var appMaps = angular.module('appMaps', ['uiGmapgoogle-maps']);
appMaps.controller('mainCtrl', function ($scope, uiGmapGoogleMapApi, uiGmapIsReady) {
$scope.windowOptions = {
visible: false
};
$scope.onClick = function () {
$scope.windowOptions.visible = !$scope.windowOptions.visible;
};
$scope.closeClick = function () {
$scope.windowOptions.visible = false;
};
$scope.options = { scrollwheel: false };
$scope.map = { center: { latitude: 30, longitude: 0 }, zoom: 4 };
var resolveAddress = function (address, callback) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ "address": address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
var location = results[0].geometry.location;
callback(location);
}
else {
callback(null);
}
});
}
uiGmapGoogleMapApi.then(function (gapi) {
resolveAddress('Amsterdam', function (location) {
$scope.$apply(function () {
$scope.map.center = { latitude: location.lat(), longitude: location.lng() };
$scope.marker = {
coords: {
latitude: location.lat(),
longitude: location.lng()
},
title: 'Amsterdam',
show: true,
id: 1
};
});
});
});
});
.angular-google-map-container {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
<script src="https://code.angularjs.org/1.3.14/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
<script src="http://rawgit.com/angular-ui/angular-google-maps/2.0.X/dist/angular-google-maps.js"></script>
<div ng-app="appMaps" id="map_canvas" ng-controller="mainCtrl">
<ui-gmap-google-map center="map.center" zoom="map.zoom" draggable="true" options="options" bounds="map.bounds">
<ui-gmap-marker idkey="marker.id" coords="marker.coords" options="marker.options" click="onClick()" events="marker.events" />
</ui-gmap-google-map>
</div>

Related

Google Maps Infowindow issue after Geocode adaptation

I switched my code from the lat-lang system to the geocode API in order to resolve addresses, but unfortunately, the Google Maps Infowindows don't work properly. Only a few of them are displayed, with wrong information.
Here there is my code.
<script type="text/javascript">
if(document.getElementById("{idMap}")) {
let geocoder;
let map;
let locations = [
[ "Location 1" , "Via Pavia 57, 80021" ] ,
[ "Location 2" , "Via Palermo 24, 80021" ] ,
[ "Location 3" , "Via Milano 15, 80021" ] ,
];
function initializeMap() {
geocoder = new google.maps.Geocoder();
let infowindow = new google.maps.InfoWindow();
let bounds = new google.maps.LatLngBounds();
let mapSettings = {
zoomControl: false,
mapTypeControl: false,
scaleControl: false,
streetViewControl: false,
rotateControl: false,
fullscreenControl: false,
};
map = new google.maps.Map(document.getElementById("{idMap}"), mapSettings);
for (i = 0; i < locations.length; i++) {
codeAddress(locations[i][1], i, bounds);
}
}
function codeAddress(address, index, bounds) {
geocoder.geocode({ address: address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
let latLng = {
lat: results[0].geometry.location.lat(),
lng: results[0].geometry.location.lng(),
};
if (status == "OK") {
let marker = new google.maps.Marker({
position: latLng,
map: map,
icon: "https://maps.google.com/mapfiles/ms/icons/blue-dot.png",
});
bounds.extend(marker.position);
map.fitBounds(bounds);
map.panToBounds(bounds);
if(locations[0][index] && locations[0][index].length > 0) {
let infowindow = new google.maps.InfoWindow({
content: locations[0][index],
});
marker.addListener("click", function () {
infowindow.open(map, marker);
});
}
} else {
console.log(
"Geocode was not successful for the following reason: " + status
);
}
}
});
}
window.initMap = null;
window.initMap = initializeMap();
}
</script>
All the markers are correctly positioned, the issue is only related to the infoWindow.
I fixed the issue, passing the id from the marker to the location array, in this way it works:
let infowindow = new google.maps.InfoWindow({
content: locations[marker.id][1],
});

Google maps intermittently loads without styles

I have a google map that loads without styles maybe 1 out of 30 refreshes and I think it's the way / order in which I'm loading the map json and the map data. I'm not quite sure the best way to do this so the styles are always there. I don't think this requires any async functions but not sure.
import MarkerClusterer from '#google/markerclusterer';
const currentPage = $('body').attr('id');
const hasMap = currentPage === 'homePage' || currentPage === 'venuesPage';
let infoArr = [];
let infowindow;
let latLng;
let mapStyles;
let marker;
let markerAddress;
let markerCluster;
let markerCount = -1;
let markerIcon;
let markerInfo;
let markers = [];
let zoomFactor = 4;
$.get('../../data/mapStyles.json').done(data => {
mapStyles = data;
});
$.get('/data/venues.json').done((data) => {
if (hasMap) { // does this need to be hasMap && mapStyles?
initializeMap(data);
}
});
let mcOptions = {
gridSize: 40,
maxZoom: 16,
zoomOnClick: true,
minimumClusterSize: 2,
styles: [
{
height: 53,
url: '/img/meta/m1.png',
width: 53,
},
{
height: 56,
url: '/img/meta/m2.png',
width: 56,
},
{
height: 66,
url: '/img/meta/m3.png',
width: 66,
},
{
height: 78,
url: '/img/meta/m4.png',
width: 78,
},
{
height: 90,
url: '/img/meta/m5.png',
width: 90,
},
],
};
function initializeMap(data) {
if ($(window).width() < 768) {
zoomFactor = 3;
}
let map = new google.maps.Map(document.getElementById('mapContainer'), {
zoom: zoomFactor,
center: new google.maps.LatLng(40.0, -102.0),
styles: mapStyles,
zoomControl: true,
mapTypeControl: false,
scaleControl: false,
streetViewControl: false,
rotateControl: false,
fullscreenControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP,
});
markerIcon = '/img/svgs/icon_map_marker_venue.svg';
data.forEach((venue) => {
let {
lat,
long,
name,
streetAddress,
city,
state,
slug,
} = venue;
if (lat !== '') {
latLng = new google.maps.LatLng(lat, long);
marker = new google.maps.Marker({
position: latLng,
icon: markerIcon,
});
markerAddress = `${streetAddress}<br>${city}, ${state}`;
markerInfo = `<a class="map-marker" href="/venues/venue-detail/index.php?${slug}"><h5>${name}</h5>${markerAddress}</a>`;
markers.push(marker);
infoArr.push(markerInfo);
markerCount += 1;
}
google.maps.InfoWindow.prototype.isOpen = function () {
let map = this.getMap();
return (map !== null && typeof map !== 'undefined');
};
infowindow = new google.maps.InfoWindow({});
google.maps.event.addListener(marker, 'click', (function (marker, markerCount) {
return function () {
if (!infowindow.isOpen()) {
infowindow.setContent(infoArr[markerCount]);
infowindow.open(map, marker);
} else {
infowindow.close();
}
};
}(marker, markerCount)));
});
markerCluster = new MarkerClusterer(map, markers, mcOptions);
}
I did the the json gets like this and it works:
$.when($.get('../../data/mapStyles.json').done(styleData => {
mapStyles = styleData;
}), $.get('/data/venues.json').done(vData => {
venueData = vData;
})).then(() => {
initialize(venueData);
});

How to change the view/location in Google api StreetViewPanorama

I am trying to change the location of panorama but it shows different location and some times it doesn't show anything.
Location 1
Location 2
Can I recreate the panorama view without loading the page?
Thanks
var panorama;
$(document).ready(function () {
$(".locationLink").click(function () {
var index = $(this).attr('index');
var by = $(this).attr('by');
changeLocation(index, by);
});
});
var locationsList = [{
lat: 40.7784525,
lng: -73.9589767,
heading: 31.35,
pitch: 0,
zoom: 0,
panoId: 'F:AF1QipMFjDabjIiv8AgkMaSMFFZixaBiLARqUl3aQ-_2'
},
{
lat: 40.778483,
lng: -73.9589043,
heading: 346.96,
pitch: 0,
zoom: 0,
panoId: 'F:AF1QipPd-l5QzKcGCTya5oHQXuGhamem2v2QfV9N9J16'
}];
function changeLocation(index, by) {
var location = locationsList[index];
var fenway = { lat: location.lat, lng: location.lng };
if (by === 'pano')
panorama.setPano(location.panoId);
if (by === 'latlng')
panorama.setPosition(fenway);
}
function initStreetViewPanorama(params) {
panorama = new google.maps.StreetViewPanorama(document.getElementById('pano'), {
pano: params.panoId,
zoom: params.zoom,
pov: { heading: params.heading, pitch: params.pitch },
addressControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT
}
});
}
initStreetViewPanorama(locationsList[0]);
html,body { height:100%;}
#pano { width:100%; height:99%; }
<div>
Location 1 |
Location 2
<span><b> Change by Lat/Long </b></span>
Location 1 |
Location 2
</div>
<br>
<div id="pano">
</div>
<script src="https://maps.googleapis.com/maps/api/js?">
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Google Maps API V3: Exclude single marker from clustering

I am using the google maps api and using grid clustering for the markers. I wanted to know if there is a way to exclude a single marker from clustering. I want a "You are here" marker that is always visible. I tried using a different array for just that marker and not including it the cluster function but that didn't work.
Does anyone have a solution for this?
Here is how i am doing the clustering
$(document).on('click', '#mapbut', function() {
var items, distances, you_are_here = [], markers_data = [], markers_data2 = [], fred, clust1, markss;
you_are_here.push({
lat : Geo.lat,
lng : Geo .lng,
animation: google.maps.Animation.DROP,
title : 'Your are here',
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 10
},
infoWindow: {
content: '<p>You are Here</p>'
}
});
function loadResults (data) {
if (data.map.length > 0) {
items = data.map;
for (var i = 0; i < items.length; i++)
{
var item = items[i];
var distances = [];
var dist2;
if (item.Lat != undefined && item.Lng != undefined)
{
markers_data.push({
lat : item.Lat,
lng : item.Lng,
title : item.Site,
infoWindow: {
content: '<p>' + item.Site + '</p><p>' + Math.round(item.distance) + ' miles away</p>'
}
});
}
}
}
map.addMarkers(markers_data);
map = new GMaps({
el: '#map',
lat: Geo.lat,
lng: Geo.lng,
zoom: 10,
mapTypeControl: false,
zoomControl: true,
zoomControlOptions: {
position: google.maps.ControlPosition.LEFT_CENTER
},
markerClusterer: function(map) {
options = {
gridSize: 50
}
clust1 = new MarkerClusterer(map,[], options);
return clust1;
},
scaleControl: true,
streetViewControl: false
});
map.addMarkers(you_are_here);
The GMaps clusters all the markers you add to it with the addMarker method (if you provide a MarkerClusterer).
One option: add your "special" marker (the one that you don't want clustered) to the map manually, so it isn't added to the MarkerClusterer:
The GMaps.map property is a reference to the Google Maps Javascript API v3 map object. So this will add a marker to the map without letting the GMaps library know about it:
you_are_here = new google.maps.Marker({
position: {lat: Geo.lat,lng: Geo.lng},
animation: google.maps.Animation.DROP,
title: 'Your are here',
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 10
},
map: map.map
});
proof of concept fiddle
code snippet:
var Geo = {
lat: 40.7281575,
lng: -74.07764
};
$(document).on('click', '#mapbut', function() {
var items, distances, you_are_here = [],
markers_data = [],
markers_data2 = [],
fred, clust1, markss;
function loadResults(data) {
if (data.map.length > 0) {
items = data.map;
for (var i = 0; i < items.length; i++) {
var item = items[i];
var distances = [];
var dist2;
if (item.Lat != undefined && item.Lng != undefined) {
markers_data.push({
lat: item.Lat,
lng: item.Lng,
title: item.Site,
infoWindow: {
content: '<p>' + item.Site + '</p><p>' + Math.round(item.distance) + ' miles away</p>'
}
});
}
}
}
map = new GMaps({
el: '#map',
lat: Geo.lat,
lng: Geo.lng,
zoom: 8,
mapTypeControl: false,
zoomControl: true,
zoomControlOptions: {
position: google.maps.ControlPosition.LEFT_CENTER
},
markerClusterer: function(map) {
options = {
gridSize: 50,
imagePath: "https://cdn.rawgit.com/googlemaps/v3-utility-library/master/markerclustererplus/images/m"
}
clust1 = new MarkerClusterer(map, [], options);
return clust1;
},
scaleControl: true,
streetViewControl: false
});
map.addMarkers(markers_data);
you_are_here = new google.maps.Marker({
position: {
lat: Geo.lat,
lng: Geo.lng
},
animation: google.maps.Animation.DROP,
title: 'Your are here',
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 10
},
infoWindow: {
content: '<p>You are Here</p>'
},
map: map.map
});
// map.addMarkers(you_are_here);
}
loadResults(data);
});
var data = {
map: [{
Lat: 40.7127837,
Lng: -74.005941,
Site: "New York, NY",
distance: 1
}, {
Site: "Newark, NJ",
Lat: 40.735657,
Lng: -74.1723667,
distance: 2
}]
};
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script src="https://rawgit.com/HPNeo/gmaps/master/gmaps.js"></script>
<script src="https://cdn.rawgit.com/googlemaps/v3-utility-library/master/markerclustererplus/src/markerclusterer.js"></script>
<input id="mapbut" type="button" value="map" />
<div id="map"></div>
To get around this is relatively simple, just after I send the markers array to MarkerClusterer I then add my location.
// Setup cluster markers
var markerCluster = new MarkerClusterer( gmap.map, options )
// add my location
gmap.addMarker({
lat: data.latitude,
lng: data.longitude
...
})
Thanks

Gmaps maps showing listings by Yellow pages

I have created the map using Gmaps.js and passed the location and near by places to it but its showing listings by yellowpages.ca whenever I click a place following picture explains the problem. I am new in Google maps api.
var map;
var loc;
$(document).ready(function(){
map = new GMaps({
el: '#map',
lat: -12.043333,
lng: -77.028333,
zoom:15,
});
GMaps.geocode({
address: $('#address').val().trim(),
callback: function(results, status){
if(status=='OK'){
var latlng = results[0].geometry.location;
lat=latlng.lat();
lng=latlng.lng();
map.setCenter(latlng.lat(), latlng.lng());
map.addMarker({
lat: latlng.lat(),
lng: latlng.lng(),
icon:$('#mainPin').val().trim(),
});
loc=new google.maps.LatLng(latlng.lat(),latlng.lng());
}}});
});
function showplaces(place,urll){
map.removeMarkers();
GMaps.geocode({
address: $('#address').val().trim(),
callback: function(results, status){
if(status=='OK'){
var latlng = results[0].geometry.location;
map.setCenter(latlng.lat(), latlng.lng());
map.addMarker({
lat: latlng.lat(),
lng: latlng.lng(),
icon:$('#mainPin').val().trim(),
});
map.addLayer('places', {
location : loc,
radius : 500,
types : [place],
search: function (results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
map.addMarker({
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng(),
title : place.name,
icon:urll,
});
}
}
}
});
}
}
});
if(place=='shopping_mall')
{
GMaps.geocode({
address: $('#address').val().trim(),
callback: function(results, status){
if(status=='OK'){
var latlng = results[0].geometry.location;
map.setCenter(latlng.lat(), latlng.lng());
map.addMarker({
lat: latlng.lat(),
lng: latlng.lng(),
icon:$('#mainPin').val().trim(),
});
map.addLayer('places', {
location : loc,
radius : 500,
types : ['shoe_store','store','department_store'],
search: function (results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
map.addMarker({
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng(),
title : place.name,
icon:urll,
});
}
}
}
});
}
}
});
}
else if(place=='movie_theater')
{
GMaps.geocode({
address: $('#address').val().trim(),
callback: function(results, status){
if(status=='OK'){
var latlng = results[0].geometry.location;
map.setCenter(latlng.lat(), latlng.lng());
map.addMarker({
lat: latlng.lat(),
lng: latlng.lng(),
icon:$('#mainPin').val().trim(),
});
map.addLayer('places', {
location :loc,
radius : 500,
types : ['movie_theater','zoo','stadium','night_club'],
search: function (results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
map.addMarker({
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng(),
title : place.name,
icon:urll,
});
}
}
}
});
}
}
});
}
}
What you see there are the attributions, it's required to show them.
Of course it's not required to show them multiple times.
The issue is(you may call it bug, I would call it a bad implementation ... heaven knows why so many people use these 3rd-party maps-libraries which only introduce bugs instead of useful features).
The "bug": each time you call map.addLayer('places') a new instance of google.maps.places.PlacesService will be created. Each instance will print separate attributions.
Gmaps.js doesn't have options to:
define where the attributions will be placed
use a single instance of the placesService
My suggestion would be to give up this "library" .
When you can't do without it check at the begin of showplaces if there is an object map.singleLayers.places . When it does it is the placesService-instance. Use this instance for a nearbySearch instead of using map.addLayer('places') .

Categories

Resources