I'm using Google Maps for AngularJS to add a map to my project in AngularJS. Everything works great, except the case when at certain point I want the map center to be the exactly the same position as the clicked marker. So, on a click event I set the center of the map in AngularJS controller. Everything is OK, but when I drag or zoom the map, the marker position becomes the "new" center of the map. Does anybody know why is this happening? It's like the marker coords are binded in bi-directional way... Any help is appreciated! Thanks in advance
Here's the code:
// angular js controller
// map init [displays markers for all railway terminals in DB]
$scope.map = {
center: {
latitude: 48.22476,
longitude: 16.41356
},
zoom: 4
};
$scope.markers = []; // later filled with data from DB
// some code in between ...
// selection in table with termnals
$scope.selectTerminal = function (terminal) {
$scope.selected.terminal = terminal;
if (terminal.placeId != $scope.currentSelectedId) {
$scope.currentSelectedId = $scope.selected.terminal.placeId;
$scope.getTerminalDetails($scope.selected.terminal.placeId);
$scope.map.center = terminal.address.coords; // THIS LINE GIVES ME TROUBLE
$scope.map.zoom = 12;
}
};
So, the map center is set according to the coordinates of the selected terminal on select action (it is the new center of the map), and the zoom level increases. The thing is when i try to reset the map, or try to zoom or drag the map, the marker coordinates get the new map center coords, but it shouldn't. That's why I say 'two-way binding', I just can't figure this thing out.
Using your example you can do this.
$scope.map = {
center: {
latitude: 48.22476,
longitude: 16.41356
},
zoom: 4,
markersEvents: {
click: function(marker, eventName, terminal) {
$scope.map.center.latitude = terminal.coords.latitude;
$scope.map.center.longitude = terminal.coords.longitude;
}
}
};
remember in the html marker introduce events="map.markersEvents"
Related
I've a google map with some markers, but when I zoom in and out the marker icon size changes, is there any way to make that size fixed?
const [markers,setMarkers] = useState([])
function generaMarker(elementolo,index){
var mark = <Marker draggable={modify===true?true:false} onDragEnd={(e)=>modify===true?handleSpostamentoMarker(e,index):null} onClick={(e)=>eliminate===true?deleteMarker(e,index):handleClickEl(elementolo)} label={elementolo.Nome} title={elementolo.Nome} icon={{url:getIcon(elementolo),s : new window.google.maps.Size(50,50),labelOrigin: new window.google.maps.Point(25,60)
}} position={new window.google.maps.LatLng(elementolo.Posizione.Lat,elementolo.Posizione.Lng)}/>
var nonDarmele = markers;
nonDarmele.push(mark);
setMarkers(nonDarmele)
return mark;
}
I use this function to render the markers and memorize them in the arrsy
if I write setMarkers((prev)=>[...prev,mark]) it crashes for the re renders even if the markers array is not rendered
I've tried also using a listener to the map zoom changes for setting new Marker icon sizes but I get that setIcon() method doesen't exists
function handleMarkerSize(map){
var zoom = map.getZoom()
var markerWidth = (zoom/9)*20;
var markerHeight = (zoom/9)*34;
//scaledSize: new window.google.maps.Size(50,50)
markers.forEach((mark)=>{
console.log("ooo",mark)
mark.props.icon = {
url: mark.props.icon.url,
scaledSize: new window.google.maps.Size(markerWidth,markerHeight),
labelOrigin: new window.google.maps.Point(25,60)
}
})
}
I'm using #react-google-maps/api
The map and markers visualization works fine, after rendering all the Markers there is no re render (only if in the function generaMarker() I use setMarkers with prev, and that make it crash)
Thanks for your help
I am able to load markers from a local database I include in my Ionic app that is just a simple array of lat/lon coords. The trouble is when I try and load them from a JSON file on the web. Any help would be appreciated. Thanks!
this is the call I use:
get('assets/data/markers.json')
And that all works fine for populating the map from a local data file.
Now my issue is that I would like to display markers from a JSON file that is located at :
http://app.toronto.ca/cc_sr_v1_app/data/edc_eventcal_APR?limit=500
Although when I change the get request to include that link as such:
get('http://app.toronto.ca/cc_sr_v1_app/data/edc_eventcal_APR?limit=500')
It gives me the following error message:
I believe I am not parsing the coords correctly in my marker function, yet I am unsure how to do this with the JSON array. Here is a visual of what the location structure looks like in the file:
My home.ts marker map/marker functionality:
displayGoogleMap(){
let latLng = new google.maps.LatLng(43.653908,-79.384293);
let mapOptions = {
center:latLng,
zoom:12,
mapTypeId : google.maps.MapTypeId.ROADMAP
}
this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
}
getMarkers(){
//this.http.get('assets/data/markers.json').map((res)=>res.json()).subscribe(data=>{
this.http.get('http://app.toronto.ca/cc_sr_v1_app/data/edc_eventcal_APR? limit=500').map((res)=>res.json()).subscribe(data=>{
this.addMarkersMap(data);
});
}
addMarkersMap(markers){
for(let marker of markers){
var loc = {lat: marker.latitude , lon: marker.longitude};
console.log(loc);
marker = new google.maps.Marker({
position: loc,
map: this.map,
//title:marker.name,
//label:marker.content
});
}
You are accessing non-existing key from marker object. Try to change below function.
addMarkersMap(markers)
{
for(let marker of markers)
{
var loc = {lat: marker.calEvent.locations[0]['coords'].lat , lon: lat: marker.calEvent.locations[0]['coords'].lng};
console.log(loc);
marker = new google.maps.Marker({
position: loc,
map: this.map
});
}
}
I'm playing with the angular-leaflet-directive, and getting the marker names from a mouse click is straight forward. I just listen for the leafletDirectiveMarker.click event and then access args.markerName.
angular-leaflet-directive also works with markercluster, so I can cluster markers that have the same coordinates or ones that are close by. However, I would like to do the following, but it is not clear from the documentation on how to do it:
Make user double-click on cluster to zoom in. Currently doing a single click on a cluster will zoom in on the markers. see example.
How to listen for click event on cluster and get all marker names in the cluster.
The documentation for clustermarker has a cluster event:
markers.on('clusterclick', function (a) {
console.log('cluster ' + a.layer.getAllChildMarkers().length);
});
But I'm not sure what event I should be listening to using angular-leaflet-directive.
As far as your first question goes, you'll have to hook the doubleclick and pass it the fire('click') command after overriding the usual click event. Probably more trouble than its really worth, especially on mobile - and not something I can easily solve.
Regarding your second question, I have just solved it.
$scope.openMarker is a reference to an ng-click event in my jade template that is attached to an ng-repeat which pulls images and their id's from the database.
$scope.openMarker = function(id) {
var _this = [];
_this.id = id;
leafletData.getMarkers()
.then(function(markers) {
$scope.london = {
lat: $scope.markers[_this.id].lat,
lng: $scope.markers[_this.id].lng,
zoom: 19
};
var _markers = [];
_markers.currentMarker = markers[_this.id];
_markers.currentParent = _markers.currentMarker.__parent._group;
_markers.visibleParent = _markers.currentParent.getVisibleParent(markers[id]);
_markers.markers = markers;
return _markers;
}).then(function(_markers){
if (_markers.visibleParent !== null) {
_markers.visibleParent.fire('clusterclick');
} else {
_markers.currentMarker.fire('click');
}
return _markers;
}).then(function(_markers){
_markers.currentParent.zoomToShowLayer(_markers.markers[ _this.id ], function() {
$scope.hamburg = {
lat: $scope.markers[_this.id].lat,
lng: $scope.markers[_this.id].lng,
zoom: 19
};
if (_markers.currentMarker !== null) {
_markers.currentMarker.fire('click');
} else {
_markers.visibleParent.fire('clusterclick');
_markers.currentMarker.fire('click');
}
});
});
};
You can read more about how I came to this solution here at github.
Much like many people, I too had a long search with no results. While experimenting with another method, I came across this:
$timeout(function(){
leafletData.getLayers().then(function(layers) {
$scope.markerClusterGrp = layers.overlays.locations;
var clusters = $scope.markerClusterGrp.getLayers();
$scope.markerClusterGrp.on('clustermouseover', function (a) {
var clusterObjects = a.layer.getAllChildMarkers();
console.log(clusterObjects);
});
$scope.markerClusterGrp.on('clusterclick', function (a) {
var clusterObjects = a.layer.getAllChildMarkers();
console.log(clusterObjects);
});
});
},1000);
It works the same, the difference is that it requires a timeout in order to wait for the layer to render with all markers (my understanding, correct me if wrong :-) ).
I hope this helps anyone searching for an angular solution. Just remember to include $timeout in your controller dependencies.
I have a dynamically generated list of markers within my Google Map. I want the map's center to be the center of all the markers and zoomed out just enough so that all markers are in view.
In terms of calculating the map center, perhaps this could be possible by iterating through all the latitudes and longitudes and finding the central point. However, I cannot figure out the best way to calculate what the zoom should be.
Is this possible to achieve?
My map is being used in the template like this:
<ui-gmap-google-map events="map.events" center="map.center" zoom="map.zoom" draggable="true" options="options">
<ui-gmap-marker ng-repeat="home in filteredHomes = (resCtrl.filteredHomes | orderBy : $storage.params.orderby : $storage.params.reverseOrder)" coords="{latitude: home.location.latitude, longitude: home.location.longitude}" idkey="home.homeId">
</ui-gmap-marker>
</ui-gmap-google-map>
UPDATE
Attempted Angular implementation from advice from #Tiborg:
uiGmapGoogleMapApi.then(function(maps) {
$scope.map = {
center: $scope.$storage.params.views.map.location,
zoom: $scope.$storage.params.views.map.zoom,
events: {
click: function() {
var bounds = new google.maps.LatLngBounds();
for (var i in $scope.filteredHomes) {
bounds.extend($scope.filteredHomes[i].location);
}
$scope.map.fitBounds(bounds);
}
}
};
});
This produces the console error: TypeError: undefined is not a function (evaluating 'a.lat()')
Use the LatLngBounds class in Google Maps API, like this:
var bounds = new google.maps.LatLngBounds();
for (var i in markers) // your marker list here
bounds.extend(markers[i].position) // your marker position, must be a LatLng instance
map.fitBounds(bounds); // map should be your map class
It will nicely zoom and center the map to fit all your markers.
Of course, this is the pure javascript, not the angular version, so if you have problems implementing it in angular (or you don't have access to the map instance from where you get the markers), let me know.
angular-google-maps has taken care of this feature. All you need to do is add fit="true" attribute in your markers directive (ui-gmap-markers).
Example : <ui-gmap-markers models="map.markers" fit="true" icon="'icon'">
Please refer the document http://angular-ui.github.io/angular-google-maps/#!/api
The answer has been posted for another problem: https://stackoverflow.com/a/23690559/5095063
After that you have just to add this line:
$scope.map.control.getGMap().fitBounds(bounds);
Thanks to all the replies, I got this code which is working perfectly for me:
var bounds = new google.maps.LatLngBounds();
for (var i = 0, length = $scope.map.markers.length; i < length; i++) {
var marker = $scope.map.markers[i];
bounds.extend(new google.maps.LatLng(marker.latitude, marker.longitude));
}
$scope.map.control.getGMap().fitBounds(bounds);
I hope it will help to someone.
Also use timeout to make sure it is digested properly
uiGmapIsReady.promise()
.then(function (map_instances) {
var bounds = new google.maps.LatLngBounds();
for (var i in $scope.map.markers) {
var marker = $scope.map.markers[i];
bounds.extend(new google.maps.LatLng(marker.latitude, marker.longitude));
}
$timeout(function() {
map_instances[0].map.fitBounds(bounds);
}, 100);
});
I am trying to build an application based on backbone.js and leaflet.
Users could drag the map and see markers on the map.
Markers can be selected by clicking on them. When selected they have to change their icon and the marker detailed information shown on a (not popup).
my backbone model consists of several entities:
Marker model contains
latitude, longitude
type,
title,
isSelected
Map model contains:
center of the map,
markers collection,
selected marker
anyone has any idea how i could make this kind of functionality?
how can i make leaflet markers as backbone views?
Backbone views and the leaflet object model are not a perfect fit, because the markers aren't contained within a DOM element, which is what Backbone.View.el is supposed to represent. Markers do of course have an element (accessible via marker._icon), but it doesn't exist until the marker is rendered to the map.
That said, you can represent the markers with Backbone views, you just can't use the events or any el related functionality. I've implemented similar views successfully using OpenLayers, which has the same "problem", and it works fine.
I think this is easiest to explain with code:
//MarkerView has no element
App.Views.MarkerView = Backbone.View.extend({
initialize: function(options) {
//pass map instance to the marker
this.map = options.map;
//create the marker object
this.marker = L.marker([this.model.get('longitude'), this.model.get('latitude')]);
},
render: function() {
//append marker to the map
this.marker.addTo(this.map);
//can't use events hash, because the events are bound
//to the marker, not the element. It would be possible
//to set the view's element to this.marker._icon after
//adding it to the map, but it's a bit hacky.
this.marker.on('click', this.onClick);
},
onClick: function() {
alert("click");
}
});
//MapView renders a map to the #map element
App.Views.MapView = Backbone.View.extend({
id:"#map",
render: function() {
//render map element
var map = this.map = L.map(this.$el.attr('id'))
.setView([this.model.get('centerLon'), this.model.get('centerLat') ], 13)
.addLayer(L.tileLayer(this.model.get('layerUrl'), { maxZoom: 18 }));
//render each marker
this.markerViews = this.model.get('markers').map(function(marker) {
return new App.Views.MarkerView({model:marker, map:map}).render();
});
}
});
Here's a demo on JSFiddle.