Clear Google Maps initial State - javascript

I'm using ngMap on a project where I have different maps on different views. I have one initial page where I show a map and draw a polygon and some markers. My controller is like this:
$scope.showInitialMap = function( map ) {
/*Resize image to show on map*/
var iconGood = {
url: 'modules/cars/img/ambulance_ok.png',
scaledSize: new google.maps.Size( 40, 40 ),
origin: new google.maps.Point( 0, 0 ),
anchor: new google.maps.Point( 0, 0 )
};
/*Get all cars*/
$scope.tracks = Tracks.getTaxisRealTime( function() {
angular.forEach( $scope.tracks, function( c ) {
var infowindow = new google.maps.InfoWindow( {
content: contentString
} );
/*Set marker position fo each car*/
var marker = new google.maps.Marker( {
position: {
lat: c.Latitude,
lng: c.Longitude
},
icon: iconGood,
map: map
} );
} );
/*draw map*/
setArea( map );
} );
};
and I just add it to the view like this:
<section data-ng-controller="MapsCtrl" ng-init="InitTaxiHistory()">
<ng-map center="[19.54, -96.91]" zoom="13" style="height: 600px;" min-zoom="12">
</ng-map>
</section>
The problem is that when I go to a different view where I also show a map, it keeps the same state where I left the previous map.
How do I reset the map? Or how create 2 different instances for a map?

Creating new instance of Google Map will make question complex and not recommended at all.
see relevant issues:
What is the Proper Way to Destroy a Map Instance?
How to destroy or reset map?
Solution
And for your situation, you can deal with each ng-map with making googlemap show different things according to your current controller.
<ng-map>
<marker ng-repeat="marker in tracks" position="{{marker. Latitude}}, {{marker. Longitude}}"></marker>
<ng-map>
the markers will be removed automitically if there isn't data in $scope.tracks and if $scope.tracks is undefined.
Plunker demo.

Since NgMap extends google.maps.Map object to store all the objects (markers, shapes) you could clear the map by calling setMap() method:
$scope.clearMap = function () {
//clear markers
for (var k in $scope.map.markers) {
$scope.map.markers[k].setMap(null);
}
//clear shapes
for (var k in $scope.map.shapes) {
$scope.map.shapes[k].setMap(null);
};
};
Example
var app = angular.module('appMaps', ['ngMap']);
app.controller('mapCtrl', function ($scope, NgMap) {
$scope.cities = [
{ id: 1, name: 'Oslo', pos: [59.923043, 10.752839] },
{ id: 2, name: 'Stockholm', pos: [59.339025, 18.065818] },
{ id: 3, name: 'Copenhagen', pos: [55.675507, 12.574227] },
{ id: 4, name: 'Berlin', pos: [52.521248, 13.399038] },
{ id: 5, name: 'Paris', pos: [48.856127, 2.346525] }
];
NgMap.getMap().then(function (map) {
$scope.map = map;
});
$scope.clearMap = function () {
//clear markers
for (var k in $scope.map.markers) {
$scope.map.markers[k].setMap(null);
}
//clear shapes
for (var k in $scope.map.shapes) {
$scope.map.shapes[k].setMap(null);
};
};
$scope.showMap = function () {
//clear markers
for (var k in $scope.map.markers) {
$scope.map.markers[k].setMap($scope.map);
}
//clear shapes
for (var k in $scope.map.shapes) {
$scope.map.shapes[k].setMap($scope.map);
};
};
});
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/scripts/ng-map.js"></script>
<div ng-app="appMaps" ng-controller="mapCtrl">
<button ng-click="clearMap()">Clear All</button>
<button ng-click="showMap()">Show All</button>
<map center="[59.339025, 18.065818]" zoom="4">
<marker id='ID{{city.id}}' ng-repeat="city in cities" position="{{city.pos}}" >
</marker>
<shape name="rectangle" bounds="[ [57.190, 16.149], [59.899, 20.443] ]"></shape>
</map>
</div>

Related

How to add [UP] -3 [DOWN] controls to switch between layers on a custom map?

I've been googling for days now, and getting kind of frustrated.. I hope anyone can help me!
What I'm trying to achieve is the controls (as shown below), which if pressing the DOWN button for example, it will show the map layer which is one "floor" below the current, and set the "0" to "-1".
<---
My current map looks like this, and I want to be able to go up and down on "floors".
This is the GROUND level
And this is -1 floor, the level beneath the above image
I have all the images etc, I have basic understanding of Leaflet, but I can't figure out how to add this control and make it load the desired level.
Anyone that could help me, or lead me in the right direction?
Kind Regards,
Andreas.
I created a working controler for you (but it is not designed):
L.LayerControl = L.Control.extend({
options: {
position: 'topright',
layerIdx: 0,
//control position - allowed: 'topleft', 'topright', 'bottomleft', 'bottomright'
},
initialize: function(layers, options) {
this.layers = layers;
L.setOptions(this, options);
},
onAdd: function (map) {
this.map = map;
var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control layercontrol');
var buttonUp = L.DomUtil.create('a', '', container);
buttonUp.innerHTML = '^';
this.text = L.DomUtil.create('a', '', container);
this.text.innerHTML = this.layers[this.options.layerIdx].name;
this.text.style.fontWeight = '900';
var buttonDown = L.DomUtil.create('a', '', container);
buttonDown.innerHTML = 'v';
L.DomEvent.disableClickPropagation(container);
L.DomEvent.on(buttonUp, 'click', this._clickUp, this);
L.DomEvent.on(buttonDown, 'click', this._clickDown, this);
this._removeAllLayers();
this.map.addLayer(this.layers[this.options.layerIdx].layer);
return container;
},
_clickUp : function () {
if(this.layers.length -1 > this.options.layerIdx){
this.map.fire('layercontrolUp', {layer: this.layers[this.options.layerIdx].layer, name: this.layers[this.options.layerIdx].name});
this.options.layerIdx++;
this.text.innerHTML = this.layers[this.options.layerIdx].name;
this._removeAllLayers();
this.map.addLayer(this.layers[this.options.layerIdx].layer);
}
},
_clickDown : function () {
if(0 < this.options.layerIdx){
this.map.fire('layercontrolDown', {layer: this.layers[this.options.layerIdx].layer, name: this.layers[this.options.layerIdx].name});
this.options.layerIdx--;
this.text.innerHTML = this.layers[this.options.layerIdx].name;
this._removeAllLayers();
this.map.addLayer(this.layers[this.options.layerIdx].layer);
}
},
_removeAllLayers: function(){
//removing all layers from the map where added from the control
this.layers.forEach(function(controlLayer){
this.map.removeLayer(controlLayer.layer);
});
}
});
var fg1 = new L.FeatureGroup();
fg1.addLayer(L.marker([51.5, -0.09]).bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup());
var fg2 = new L.FeatureGroup();
fg2.addLayer(L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).bindPopup("I am a circle."));
var fg3 = new L.FeatureGroup();
fg3.addLayer(L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).bindPopup("I am a polygon."));
var layerControlLayers = [
{
name: 'KG1',
layer: fg1
},
{
name: 'KG2',
layer: fg2
},
{
name: 'EG',
layer: fg3
},
]
//layerIdx: start counting with 0 = KG1
new L.LayerControl(layerControlLayers, {layerIdx: 2}).addTo(map)
map.on('layercontrolUp', function(e){
console.log(e);
});
map.on('layercontrolDown', function(e){
console.log(e);
});

Using google map in Vue / Laravel

Trying to implement google map into Vue component. But having a hard time. Actually, there is no error. But no map also :) Okay, what I tried so far down below.
In laravel blade I set my api.
<script async defer src="https://maps.googleapis.com/maps/api/js?key={{env('GOOGLE_MAPS_API')}}&callback=initMap"></script>
Then in Vue component;
data() {
return {
mapName: "map",
//some other codes
}
},
mounted() {
this.fetchEstates();
},
methods: {
fetchEstates(page = 1) {
axios.get('/ajax', {
params: {
page
}}).then((response) => {
// console.log(response);
this.estates = response.data.data;
//some other codes....
//some other codes....
},
computed: {
//some other functions in computed...
//
initMap: function(){
var options =
{
zoom : 6,
center : {
lat:34.652500,
lng:135.506302
}
};
var map = new google.maps.Map(document.getElementById(this.mapName), options);
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
url: "/pages/estates.id",
label: {
text: this.estates.price,
color: "#fff",
},
position: {
lat: this.estates.lat,
lng: this.estates.lng
}
});
google.maps.event.addListener(marker, 'click', function () {
window.location.href = this.url;
});
}
<div id="map"></div>
and last marker url id bind is in controller like this,
public function details($id)
{
$estates = allestates::where('id', $id)->first();
return view('pages.details', compact('estates'));
}
Do I missing something in Vue js? Thank you!
From our discussion in the comments, I realise that your issue is because this.estates is still not defined when initMap() is executed. Remember that you are using an asynchronous operation (via axios) to populate this.estates, so it is undefined at runtime. What you can do is:
Keep the map initialisation logic in initMap()
Move all the Google Map marker creation until after the axios promise has been resolved. You can abstract all that into another method, e.g. insertMarkers()
Also, remember that you need to define estates in the app/component data, otherwise it will not be reactive.
Here is an example:
data() {
return {
mapName: "map",
// Create the estate object first, otherwise it will not be reactive
estates: {}
}
},
mounted() {
this.fetchEstates();
this.initMap();
},
methods: {
fetchEstates: function(page = 1) {
axios.get('/ajax', {
params: {
page
}}).then((response) => {
this.estates = response.data.data;
// Once estates have been populated, we can insert markers
this.insertMarkers();
//pagination and stuff...
});
},
// Iniitialize map without creating markers
initMap: function(){
var mapOptions =
{
zoom : 6,
center : {
lat:34.652500,
lng:135.506302
}
};
var map = new google.maps.Map(document.getElementById(this.mapName), mapOptions);
},
// Helper method to insert markers
insertMarkers: function() {
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
url: "/pages/estates.id",
label: {
text: this.estates.price,
color: "#fff",
},
position: {
lat: this.estates.lat,
lng: this.estates.lng
}
});
google.maps.event.addListener(marker, 'click', function () {
window.location.href = this.url;
});
}
},
Update: It also turns out that you have not addressed the issue of the data structure of this.estates. It appears that you are receiving an array from your endpoint instead of objects, so this.estates will return an array, and of course this.estates.lat will be undefined.
If you want to iterate through the entire array, you will have to use this.estates.forEach() to go through each individual estates while adding the marker, i.e.:
data() {
return {
mapName: "map",
// Create the estate object first, otherwise it will not be reactive
estates: {}
}
},
mounted() {
this.fetchEstates();
this.initMap();
},
methods: {
fetchEstates: function(page = 1) {
axios.get('/ajax', {
params: {
page
}}).then((response) => {
this.estates = response.data.data;
// Once estates have been populated, we can insert markers
this.insertMarkers();
//pagination and stuff...
});
},
// Iniitialize map without creating markers
initMap: function(){
var mapOptions =
{
zoom : 6,
center : {
lat:34.652500,
lng:135.506302
}
};
var map = new google.maps.Map(document.getElementById(this.mapName), mapOptions);
},
// Helper method to insert markers
insertMarkers: function() {
// Iterate through each individual estate
// Each estate will create a new marker
this.estates.forEach(estate => {
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
url: "/pages/estates.id",
label: {
text: estate.price,
color: "#fff",
},
position: {
lat: estate.lat,
lng: estate.lng
}
});
google.maps.event.addListener(marker, 'click', function () {
window.location.href = this.url;
});
});
}
},
From what I can see in the screenshot you posted, this.estates is an array of objects? If that's the case you need to iterate through the array using forEach
this.estates.forEach((estate, index) => {
console.log(estate.lat);
//handle each estate object here
});
or use the first item in the array like so this.estates[0].lat, if you're only interested in the first item.

Why are markers not displayed?

I am trying to display markers after the map is displayed. I am unable to do so.. regardless of any error. I have assured that the snapshot is with the data and marker array is nicely created. is there any logical error?? please help.
var apps = angular.module('appa',['firebase','uiGmapgoogle-maps']);
apps.controller('mainCtrl', function($firebaseObject,$scope){
var ref = firebase.database().ref();
var marker = [];
ref.once("value")
.then(function(snapshot)
{
snapshot.forEach(function(child)
{
var mark = {
id: child.child("Id").val(),
coords: {
latitude: child.child("Lat").val(),
longitude: child.child("Long").val()
},
options: { title: child.child("Alt").val() }
};
marker.push(mark);
});
});
$scope.map = {
center:
{
latitude: 67,
longitude: 24
},
zoom: 3
};
});
<body ng-app="apps">
<div id="map_canvas" ng-controller="mainCtrl">
<ui-gmap-google-map center="map.center" zoom="map.zoom">
<ui-gmap-marker ng-repeat="m in marker" coords="m.coords" options="m.options" idkey="m.id">
</ui-gmap-marker>
</ui-gmap-google-map>
</div>
<!--example-->
</body>
oh! I hot the answer my self. It was a simple mistake. I did not defined marker array in $scope. Therefore views were not getting what var marker is. I corrected it

Meteor google map display markers depending on checkbox filter

I have a map that currently displays all markers. I would like to update the markers on the map when a checkbox is clicked.
To load the markers I do
Caves.find({$or: [{ backmount: {$exists: false}},{backmount: true}]}).observe({
And if the checkbox is clicked it should change the filter to
Caves.find({ backmount: false}).observe({
I am not sure how to put that into my code.
This is the code to load the markers
Template.map.onCreated(function() {
GoogleMaps.loadUtilityLibrary('js/geolocationmarker-compiled.js');
GoogleMaps.loadUtilityLibrary('js/infobox.js');
var markers = {};
GoogleMaps.ready('map', function(map) {
var latLng = currentPosition();
Tracker.autorun(function() {
map.instance.setCenter(new google.maps.LatLng(latLng.lat, latLng.lng));
var GeoMarker = new GeolocationMarker(map.instance);
});
Caves.find({$or: [{ backmount: {$exists: false}},{backmount: true}]}).observe({
added: function(doc) {
var infobox = new InfoBox({
content: $("#infobox")[0],
disableAutoPan: false,
pixelOffset: new google.maps.Size(-140,0),
zIndex: null,
infoBoxClearance: new google.maps.Size(1,1),
boxStyle: {
background: "url('images/tipbox.gif') no-repeat",
opacity: 0.75,
width: "280px"
}
});
var marker = new google.maps.Marker({
draggable: false,
animation: google.maps.Animation.DROP,
position: new google.maps.LatLng(doc.location.coordinates.latitude,doc.location.coordinates.longitude),
id: doc._id,
map: map.instance
});
marker.addListener('click', function() {
infobox.open(map.instance, this);
});
markers[doc._id] = marker;
},
changed: function(newDoc, oldDoc) {
markers[newDoc._id].setPosition({ lat: newDoc.lat, lng: newDoc.lng});
},
removed: function(oldDoc) {
markers[oldDoc._id].setMap(null);
google.maps.event.clearInstanceListeners(markers[oldDoc._id]);
delete markers[oldDoc._id];
}
});
});
});
And I have a template with the checkbox (#sidemountOnly)
<template name="mapFilters">
<div class="row">
<div class="col-md-12">
<ul class="filemanager-options">
<li>
<div class="ckbox ckbox-default">
<input type="checkbox" id="sidemountOnly" value="1">
<label for="sidemountOnly">Sidemount Only</label>
</div>
</li>
</ul>
</div>
</div>
</template>
Thanks a lot for your help
I can answer my own question. I used a session variable where I change the subsription. Some of the related code:
Create an event:
Template.mapFilters.events({
"change #sidemountOnly": function(event) {
Session.set("sidemountOnly",event.target.checked);
}
})
Pass to subscription inside autorun
Tracker.autorun(function() {
getBox();
Meteor.subscribe("primaryCoordinates", Session.get('box'), Session.get('sidemountOnly'));
var GeoMarker = new GeolocationMarker(map.instance);
});
Create filter in publish on the server side
Meteor.publish('primaryCoordinates', function(box,sidemountOnly) {
var filter = {};
if(sidemountOnly) {
filter = {backmount: false};
} else {
filter = {$or: [{ backmount: {$exists: false}},{backmount: true}]};
}
var find = { $and: [{
location: {
$geoWithin: {
$box: box
}
}},filter]
};
return Caves.find(find);
});

Angular-google-maps: How to show Title and Description dynamically on markers

I am using Angular-google-maps, HTML code follows
<ui-gmap-google-map center='mapData.map.center' zoom='mapData.map.zoom'
events="mapEvents">
<ui-gmap-markers models="mapData.map.markers" coords="'self'">
</ui-gmap-markers>
</ui-gmap-google-map>
in JS calling
angular.extend(this, $controller('MapsMixinController',
{$scope:$scope, map:mapData.data[0].map}));
MapsMixinController as follows. Calling this controller from js code. Markers are showing & on click able to mark.
MapsMixinController.js
/**
* Controller providing common behaviour for the other map controllers
*/
angular
.module('app')
.controller('MapsMixinController', ['$scope', 'GeolocationService', 'uiGmapGoogleMapApi', 'map',
function($scope, GeolocationService, GoogleMapApi, map) {
var _this = this;
$scope.mapEvents = {
click: function(mapModel, eventName, originalEventArgs) {
var e = originalEventArgs[0];
if (e.latLng) {
$scope.mapData.map.markers.push({
id: new Date().getTime(),
latitude: e.latLng.lat(),
longitude: e.latLng.lng()
});
// This event is outside angular boundary, hence we need to call $apply here
$scope.$apply();
}
}
};
// Returns a default map based on the position sent as parameter
this.getDefaultMap = function(position) {
return {
markers: [],
center: {
latitude: position.coords.latitude,
longitude: position.coords.longitude
},
zoom: 14
};
};
// Initialize the google maps api and configure the map
GoogleMapApi.then(function() {
GeolocationService().then(function(position) {
$scope.mapData.map = map || _this.getDefaultMap(position);
}, function() {
$scope.error = "Unable to set map data"; // TODO use translate
});
});
}
]);
How can I show title on mouse hover on markers? And on click how to show description on markers?
You can add title property alone with latitude and longtitude property while creating marker data.
/**
* Controller providing common behaviour for the other map controllers
*/
angular
.module('app')
.controller('MapsMixinController', ['$scope', 'GeolocationService', 'uiGmapGoogleMapApi', 'map',
function($scope, GeolocationService, GoogleMapApi, map) {
var _this = this;
$scope.mapEvents = {
click: function(mapModel, eventName, originalEventArgs) {
var e = originalEventArgs[0];
if (e.latLng) {
$scope.mapData.map.markers.push({
id: new Date().getTime(),
latitude: e.latLng.lat(),
longitude: e.latLng.lng(),
title: "Mouse over text"
});
// This event is outside angular boundary, hence we need to call $apply here
$scope.$apply();
}
}
};
// Returns a default map based on the position sent as parameter
this.getDefaultMap = function(position) {
return {
markers: [],
center: {
latitude: position.coords.latitude,
longitude: position.coords.longitude
},
zoom: 14
};
};
// Initialize the google maps api and configure the map
GoogleMapApi.then(function() {
GeolocationService().then(function(position) {
$scope.mapData.map = map || _this.getDefaultMap(position);
}, function() {
$scope.error = "Unable to set map data"; // TODO use translate
});
});
}
]);

Categories

Resources