I'm using AngularJS for Google Maps and want to dynamically center and zoom a map based on multiple markers that are dynamically loaded. This is for a Cordova app using the Ionic Framework.
Here's my view:
<ion-view title="" ng-controller="MapCtrl as vm">
<ion-content class="padding">
<google-map id="mainMap" control="vm.googleMap" draggable="true" center="vm.map.center" zoom="vm.map.zoom" mark-click="false">
<markers idKey="mainMap" fit="vm.map.fit">
<marker idKey="marker.id" ng-repeat="marker in vm.map.markers" coords="marker.coords" options="marker.options">
<marker-label content="marker.name" anchor="2 0" class="marker-labels"/>
</marker>
</markers>
</google-map>
</ion-content>
</ion-view>
Here's my controller:
angular.module('myApp.controllers', [])
.controller('MapCtrl', function($scope, $ionicPlatform) {
var vm = this;
vm.googleMap = {}; // this is filled when google map is initialized, but it's too late
vm.mapMarkers = [];
vm.arrMarkers = [
{
id: "home",
name: "home",
coords: {
latitude:xxxxxxx, //valid coords
longitude:xxxxxxx //valid coords
},
options: {
animation: google.maps.Animation.BOUNCE
}
},
{
id: "placeAId",
name: "Place A",
coords: {
latitude:xxxxxxx, //valid coords
longitude:xxxxxxx //valid coords
}
},
{
id: "placeBId",
name: "Place B",
coords: {
latitude:xxxxxxx, //valid coords
longitude:xxxxxxx //valid coords
}
}
];
vm.map = {
center: { //how to determine where to center???
latitude: xxxxxxx, //valid coords
longitude: xxxxxxx //valid coords
},
zoom: 12, //how to determine zoom dynamically???
fit: true,
markers: vm.arrMarkers
};
var setMapBounds = function () {
var bounds = new google.maps.LatLngBounds();
createMarkers();
var markers = vm.mapMarkers;
for(var i=0; i<markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
var map = vm.googleMap.control.getGMap();
map.setCenter(bounds.getCenter());
map.fitBounds(bounds);
//remove one zoom level to ensure no marker is on the edge.
map.setZoom(map.getZoom()-1);
// set a minimum zoom
// if you got only 1 marker or all markers are on the same address map will be zoomed too much.
if(map.getZoom()> 15){
map.setZoom(15);
}
};
var createMarkers = function() {
var map = vm.googleMap.control.getGMap(); //vm.googleMap.control is undefined because this fire before map is initialized
angular.forEach(vm.restaurants, function(restaurant, index) {
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(restaurant.coords.latitude, restaurant.coords.longitude),
title: restaurant.name
});
vm.mapMarkers.push(marker);
});
};
$ionicPlatform.ready(function() {
setMapBounds();
});
})
So, my question is how do I center and zoom the map using multiple dynamically loaded markers? Also, how do I get an instance of googleMap.control (vm.googleMap.control) before the map is loaded?
Here's my code just in case anyone was wondering how to do this locally. This is a simple solution for what I needed and my indeed go back to angualr-google maps, but as of now this works fine in my application.
angular.module('myApp.controllers', [])
.controller('MapCtrl', function($scope) {
var vm = this;
vm.googleMap = null;
vm.mapMarkers = [];
var onSuccess = function(position) {
vm.userLocation.coords.latitude = position.coords.latitude;
vm.userLocation.coords.longitude = position.coords.longitude;
initializeMap();
};
var onError = function(error) {
alert('code: ' + error.code + '\n' + 'message: ' + error.message);
};
vm.userLocation = {
id: "home",
title: "home",
coords: {
latitude: 33.636727,
longitude: -83.920702
},
options: {
animation: google.maps.Animation.BOUNCE
}
};
vm.places = [
{
id: "78869C43-C694-40A5-97A0-5E709AA6CE51",
title: "Place A",
coords: {
latitude: 33.625296,
longitude: -83.976206
}
},
{
id: "52319278-83AA-46D4-ABA6-307EAF820E77",
title: "Place B",
coords: {
latitude: 33.576522,
longitude: -83.964981
}
}
];
var addMarkers = function() {
var userLocation = new google.maps.Marker({
map: vm.googleMap,
position: new google.maps.LatLng(vm.userLocation.coords.latitude, vm.userLocation.coords.longitude),
//animation: vm.userLocation.options.animation,
title: vm.userLocation.title
});
vm.mapMarkers.push(userLocation);
angular.forEach(vm.places, function(location, index) {
var marker = new google.maps.Marker({
map: vm.googleMap,
position: new google.maps.LatLng(location.coords.latitude, location.coords.longitude),
title: location.title
});
vm.mapMarkers.push(marker);
});
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < vm.mapMarkers.length; i++) {
bounds.extend(vm.mapMarkers[i].getPosition());
}
vm.googleMap.setCenter(bounds.getCenter());
vm.googleMap.fitBounds(bounds);
//remove one zoom level to ensure no marker is on the edge.
vm.googleMap.setZoom(vm.googleMap.getZoom() - 1);
// set a minimum zoom
// if you got only 1 marker or all markers are on the same address map will be zoomed too much.
if (vm.googleMap.getZoom() > 15) {
vm.googleMap.setZoom(15);
}
};
var initializeMap = function() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoom: 12,
center: new google.maps.LatLng(vm.userLocation.coords.latitude, vm.userLocation.coords.longitude)
};
var div = document.getElementById("map_canvas");
//var map = plugin.google.maps.Map.getMap(div, mapOptions);
vm.googleMap = new google.maps.Map(div, mapOptions);
addMarkers();
var width = screen.width;
var height = screen.height;
};
navigator.geolocation.getCurrentPosition(onSuccess, onError);
})
Your previous answer is good but doesn't include usage of the google maps directives you mentioned in the begining of the post. There is a way to do it using those directives, here is how:
Assuming we are in the directive's scope
Define scope.mapControl = {}; - this will have new access methods for map and markers
When defining your markup for the directives - for map and marker - include this control attribute to be added:
<ui-gmap-google-map center='map.center' zoom='map.zoom' control="mapControl">
<ui-gmap-marker ng-repeat="location in locations" coords="location.coordinates" options="location.markerOptions" idkey="location.id" control="mapControl">
<ui-gmap-window options="location.markerWindowOptions" closeclick="closeMarkerWindow(location.id)" show="true">
<div>{{location.description}}</div>
</ui-gmap-window>
</ui-gmap-marker>
</ui-gmap-google-map>
In your directive's event or some method:
var map = scope.mapControl.getGMap();
var markers = scope.mapControl.getGMarkers();
var bounds = map.getBounds();
for (var i = 0; i < markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
map.setCenter(bounds.getCenter());
map.fitBounds(bounds);
map.setZoom(map.getZoom() - 1);
Related
Hi guys i'm working with this code below , but i don't know is is possible
and how i can do to add more one marker and set other DIV to show this position.
Anyone know what can i do or give me a tip
Its a cordova application on visual studio
angular.module('app', ['onsen']).
directive('myMap', function () {
// directive link function
var link = function (scope, element, attrs) {
var map, infoWindow;
var markers = [];
// map config
var mapOptions = {
center: new google.maps.LatLng(-29.3130754, -50.8542323),
zoom: 11,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
// init the map
function initMap() {
if (map === void 0) {
map = new google.maps.Map(element[0], mapOptions);
}
}
// place a marker
function setMarker(map, position, title, content) {
var marker;
var markerOptions = {
position: position,
map: map,
title: title,
icon: 'images/Maps/blue-dot.png'
};
marker = new google.maps.Marker(markerOptions);
markers.push(marker); // add marker to array
google.maps.event.addListener(marker, 'click', function () {
// close window if not undefined
if (infoWindow !== void 0) {
infoWindow.close();
}
// create new window
var infoWindowOptions = {
content: content
};
infoWindow = new google.maps.InfoWindow(infoWindowOptions);
infoWindow.open(map, marker);
});
}
// show the map and place some markers
initMap();
setMarker(map, new google.maps.LatLng(-29.3130754, -50.8542323), 'adress');
};
return {
restrict: 'A',
template: '<div id="gmaps"></div>',
replace: true,
link: link
};
});
Here is a way to add multiple markers on a google maps , u just need an array which contains your required latitude longitude values .
var myLatLng = {lat: -25.363, lng: 131.044};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Hello World!'
});
var myLatLng1={lat: -25.163, lng: 131.644};
var marker2 = new google.maps.Marker({
position: myLatLng1,
map: map,
title: 'Hello World!'
});
you could also have an array which contains the array element conataining the latutude and longitude values .
for (var i = 0; i < locations.length; i++) { //Your location contains the lat long position
var marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
title: 'Hello World!'
});
I have created google maps for Nearby food courts. In this markers are displayed in browser and clickable and giving info window data.But same thing coming to mobile, markers are displayed and when am clicking the marker(tap the marker) info window data is not displayed.I tried with so many forums and changes lot of code and debug but i couldn't find the solution.
foodFactory.js
var foodModule = angular.module('foodModule', []);
foodModule.factory("foodFactory", ['$rootScope', '$window','foodServices', 'localStorageService', '$state', '$ionicLoading','$stateParams',
function($rootScope, $window, foodServices, localStorageService, $state, $ionicLoading, $stateParams, $cordovaGeolocation ) {
var foodCourtmap = {};
var marker = {};
var directionsDisplay = new google.maps.DirectionsRenderer({'draggable': true });
var directionsService = new google.maps.DirectionsService();
foodCourtmap.centerOnMe = function() {
initialize();
};
//intialze the google map it's show current location.
function initialize() {
var infowindow = new google.maps.InfoWindow();
navigator.geolocation.getCurrentPosition(function(pos) {
foodCourtmap.latitude = pos.coords.latitude;
foodCourtmap.longitude = pos.coords.longitude;
var site = new google.maps.LatLng( foodCourtmap.latitude, foodCourtmap.longitude);
var currentmapOptions = {
center: site,
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
//current location address based on Latitude and Longitude
var lat = parseFloat(foodCourtmap.latitude);
var lng = parseFloat(foodCourtmap.longitude);
var latlng = new google.maps.LatLng(lat, lng);
var geocoder = new google.maps.Geocoder();
geocoder.geocode({
'latLng': latlng
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
var contentString = "Location: " + results[1].formatted_address;
var marker = new google.maps.Marker({
position: latlng,
map: map,
title: 'Current Location'
});
google.maps.event.addListener(marker, 'click', function(event) {
infowindow.setContent(contentString);
infowindow.open(map, marker);
});
}
}
});
var map = new google.maps.Map(document.getElementById("food_map_canvas"), currentmapOptions);
// Places
var request = {
location:site,
radius: '5000',
name: ['restaurent']
};
var service = new google.maps.places.PlacesService(map);
service.search( 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]);
}
}
else
{
alert('No results found');
}
}
var image = new google.maps.MarkerImage('img/Restaurant.png');
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
title: place.name+","+place.vicinity,
position: place.geometry.location,
icon:image
});
var contentString = place.name+","+place.vicinity;
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(map, marker);
});
}
foodCourtmap.map = map;
});
};
$rootScope.createFoodCourt = function() {
foodCourtmap.centerOnMe();
}
return {
init: function() {
foodCourtmap.centerOnMe();
return foodCourtmap;
}
};
}
]);
food.html
<ion-view>
<ion-content scroll="false">
<div id="food_map_canvas" data-tap-disabled="true" style="float:right;width:100%; height:100%"></div>
</ion-content>
</ion-view>
So please anyone help in these regards.
The mousedown event was an improvement, however, on iOS the events still fired intermittently for me. After more investigation I found a solution that works 100% of the time by setting optimized: false when creating the marker in addition to using the mousedown event.
E.g.
var newMarker = new google.maps.Marker({
position: latLong,
map: map,
icon: 'https://maps.google.com/mapfiles/ms/icons/green-dot.png',
optimized: false
});
https://code.google.com/p/gmaps-api-issues/issues/detail?id=3834
I had the same issue. The problem was 'click' event is not triggering when we touch on the mobile screen. So I changed to 'mousedown' event. Now I am able to add markers
I wanted to automatically center the map to the user's location once loaded so I used $scope.$apply() once geolocation is loaded as seen in my TestCtrl in controller.js here:
$scope.drawMap = function(position) {
$scope.$apply(function() {
$scope.myLocation.lng = position.coords.longitude;
$scope.myLocation.lat = position.coords.latitude;
$scope.map = {
center: {
latitude: $scope.myLocation.lat,
longitude: $scope.myLocation.lng
},
zoom: 14,
events: {
click: $scope.clickCallback
}
};
});
};
navigator.geolocation.getCurrentPosition($scope.drawMap);
$scope.test = function(){
alert("hola");
};
The $scope.clickCallback is used to push new markers to the map on click event.
// inside TestCtrl
var markers = [], counter = 1;
$scope.clickCallback = function(map, eventName, event){
var lat = event[0].latLng.lat();
var lng = event[0].latLng.lng();
markers.push(createNewMarker(counter, lat, lng));
$scope.$apply(function(){
$scope.newMarker = markers;
});
counter++;
};
As you can see, there's another $scope.$apply there to apply the new marker/s.
The createNewMarker() is where the markers (ui-gmap-markers) models is defined.
// still inside TestCtrl
var createNewMarker = function(i, lat, lng, idKey) {
if (idKey == null) {
idKey = "id";
}
var foo = "<h4>New Marker</h4><form><input type='text' placeholder='Event name' name='name'></input> <input type='button' value='submit'></input><input type='button' ng-click='test()' value='Delete marker'></input></form>";
var bar = $compile(foo)($scope);
var ret = {
latitude: lat,
longitude: lng,
show: true,
options: {
draggable: true,
animation: google.maps.Animation.DROP,
},
windows: {
title: "New Marker",
},
windowsOptions: {
content: foo,
}
};
ret[idKey] = i;
return ret;
};
Now the marker is showing fine when I click on the map including the window, but when I click on the Delete marker button, my $scope.test() function isn't firing up. I tried using $compile but it returns a bunch of error about $scope.
Here's my template:
<ion-content scroll="false">
<ui-gmap-google-map center='map.center' zoom='map.zoom' bounds="map.bounds" events="map.events">
<ui-gmap-markers models="newMarker" coords="'self'" icon="'icon'" options="'options'">
<ui-gmap-windows show="show" options="'windowsOptions'">
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
</ion-content>
Anyone familiar with this scenario? I'm using Ionic Framework btw.
It does not have to be this complex.
As a creator of ngMap, I would recommend this,
http://ngmap.github.io/drawings.html#/marker-remove#marker-remove
To set the current location, just use current-location
<map center="current-location" zoom="12" on-click="addMarker()">
<marker ng-repeat="pos in positions" position="{{pos.lat}}, {{pos.lng}}"></marker>
</map>
http://plnkr.co/edit/e1SioHQ6NTSYCp0EbR0x?p=preview
We are trying to using this Codepen within our latest Ionic Framework/AngularJS project and can't seem to figure this issue out.
We want to be able to click 'Find Us' and have the Google Map Marker display our current location.
If anyone can see where we're going wrong please let us know.
Thank you.
// Google Map
.controller('MapCtrl', function($scope, $ionicLoading, $compile) {
function initialise() {
var myLatlng = new google.maps.LatLng(53.068165,-4.076803);
var mapOptions = {
zoom: 15,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
}
var map = new google.maps.Map(document.getElementById('map'), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
});
$scope.map = map;
}
google.maps.event.addDomListener(window, 'load', initialise);
$scope.centerOnMe = function() {
if(!$scope.map) {
return;
}
$scope.loading = $ionicLoading.show({
showBackdrop: true
});
navigator.geolocation.getCurrentPosition(function(pos) {
$scope.map.setCenter(new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude));
$scope.loading.hide();
},
function(error) {
alert('Unable to get location: ' + error.message);
});
};
});
Here's a good example of this.
Codepen link
.controller('MarkerRemoveCtrl', function($scope, $ionicLoading) {
$scope.positions = [{
lat: 43.07493,
lng: -89.381388
}];
$scope.$on('mapInitialized', function(event, map) {
$scope.map = map;
});
$scope.centerOnMe= function(){
$ionicLoading.show({
template: 'Loading...'
});
navigator.geolocation.getCurrentPosition(function(position) {
var pos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
$scope.positions.push({lat: pos.k,lng: pos.B});
console.log(pos);
$scope.map.setCenter(pos);
$ionicLoading.hide();
});
};
});
I did use a directive for google maps, just to keep everything in angular-land.
Here is a CodePen of an Ionic app with Google Maps
angular.module('ionic.example', ['ionic'])
.controller('MapCtrl', function($scope, $ionicLoading, $compile) {
function initialize() {
var myLatlng = new google.maps.LatLng(43.07493,-89.381388);
var mapOptions = {
center: myLatlng,
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
//Marker + infowindow + angularjs compiled ng-click
var contentString = "<div><a ng-click='clickTest()'>Click me!</a></div>";
var compiled = $compile(contentString)($scope);
var infowindow = new google.maps.InfoWindow({
content: compiled[0]
});
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Uluru (Ayers Rock)'
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,marker);
});
$scope.map = map;
}
google.maps.event.addDomListener(window, 'load', initialize);
$scope.centerOnMe = function() {
if(!$scope.map) {
return;
}
$scope.loading = $ionicLoading.show({
content: 'Getting current location...',
showBackdrop: false
});
navigator.geolocation.getCurrentPosition(function(pos) {
$scope.map.setCenter(new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude));
$scope.loading.hide();
}, function(error) {
alert('Unable to get location: ' + error.message);
});
};
$scope.clickTest = function() {
alert('Example of infowindow with ng-click')
};
});
when you find the current location of your phone first you find out the latitude and longitude.So First,Add the plugin your project
1.cordova plugin add cordova-plugin-geolocation
2.module.controller('GeoCtrl', function($cordovaGeolocation,$http) {
var posOptions = {timeout: 10000, enableHighAccuracy: false};
$cordovaGeolocation
.getCurrentPosition(posOptions)
.then(function (position) {
var lat = position.coords.latitude //here you get latitude
var long = position.coords.longitude //here you get the longitude
$http.get('http://maps.googleapis.com/maps/api/geocode/json?latlng='+lat+','+long+'&sensor=true').then(function(data){ $rootScope.CurrentLocation=data.data.results[0].formatted_address;//you get the current location here
}, function(err) {
// error
});
}, function(err) {
// error
});
}):
I have found example if someone need however I need to get first coordinates from address so later can adjust it. Someone knows how to do it?
var geocoder = new google.maps.Geocoder();
function geocodePosition(pos) {
geocoder.geocode({
latLng: pos
}, function(responses) {
if (responses && responses.length > 0) {
updateMarkerAddress(responses[0].formatted_address);
} else {
updateMarkerAddress('Cannot determine address at this location.');
}
});
}
function updateMarkerStatus(str) {
document.getElementById('markerStatus').innerHTML = str;
}
function updateMarkerPosition(latLng) {
document.getElementById('info').innerHTML = [
latLng.lat(),
latLng.lng()
].join(', ');
}
function updateMarkerAddress(str) {
document.getElementById('address').innerHTML = str;
}
function initialize() {
var latLng = new google.maps.LatLng(1.54232,-1.4353423);
var map = new google.maps.Map(document.getElementById('mapCanvas'), {
zoom: 8,
center: latLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new google.maps.Marker({
position: latLng,
title: 'Point A',
map: map,
draggable: true
});
// Update current position info.
updateMarkerPosition(latLng);
geocodePosition(latLng);
// Add dragging event listeners.
google.maps.event.addListener(marker, 'dragstart', function() {
updateMarkerAddress('Dragging...');
});
google.maps.event.addListener(marker, 'drag', function() {
updateMarkerStatus('Dragging...');
updateMarkerPosition(marker.getPosition());
});
google.maps.event.addListener(marker, 'dragend', function() {
updateMarkerStatus('Drag ended');
geocodePosition(marker.getPosition());
});
// Onload handler to fire off the app.
google.maps.event.addDomListener(window, 'load', initialize);
if your browser support the geolocation you want get coordinate with this function :
navigator.geolocation.getCurrentPosition(function(position) {
geolocationCoordinates = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
//position.coords.latitude = latitude coordonates;
//position.coords.longitude = longitude coordonates;
}
after, you can create a new map whith this coordonates.
This code is functional with all browser supporting the geolocation.