I'm trying to display an embeded Google Map based on the location of an Event object.
This is the basic app:
App = Em.Application.create();
App.Event = Em.Object.extend({
lat: -33.8665433,
lng: 151.1956316
});
App.EventController = Ember.ObjectController.extend();
App.ApplicationController = Ember.ObjectController.extend();
App.EventView = Ember.View.extend({
templateName: 'event'
});
App.ApplicationView = Ember.View.extend({
templateName: 'application'
});
App.Router = Ember.Router.extend({
enableLogging: true,
root: Ember.Route.extend({
event: Ember.Route.extend({
route: '/',
connectOutlets: function (router) {
router.get('eventController').set('content', App.Event.create());
router.get('applicationController').connectOutlet('event');
}
})
})
});
App.initialize();
With the following templates:
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="event">
{{lat}} {{lng}}
// Embeded Google Map
</script>
Where would I initialize the map? Additionally, if lat/lang change, how would I catch it and redraw the map?
Working View Code (Modified from sabithpocker's answer)
App.EventView = Ember.View.extend({
templateName: 'event',
map: null,
latitudeBinding: 'controller.content.lat',
longitudeBinding: 'controller.content.lng',
didInsertElement: function () {
var mapOptions = {
center: new google.maps.LatLng(this.get('latitude'), this.get('longitude')),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(this.$().get(0), mapOptions);
this.set('map', map); //save for future updations
this.$().css({ width: "400px", height: "400px" });
},
reRenderMap: function () {
if (this.get('map')) {
var newLoc = new google.maps.LatLng(this.get('latitude'), this.get('longitude'));
this.get('map').setCenter(newLoc);
}
}.observes('latitude', 'longitude') //these are bound to lat/lng of Event
});
Here is a quick idea, not following ember app structure, just an idea.
App.EventView = Ember.View.extend({
templateName: 'event',
map : null,
latitudeBinding : 'App.Event.lat',
longitudeBinding : 'App.Evet.lng',
didInsertElement : function(){
var mapOptions = {
center: new google.maps.LatLng(this.get('latitude'), this.get('longitude')),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(this.$().get(0),mapOptions);
this.set('map',map); //save for future updations
},
reRenderMap : function(){
var newLoc = new google.maps.LatLng(this.get('latitude'), this.get('longitude'));
this.get('map').setCenter(newLoc)
}.observes('latitude','longitude') //these are bound to lat/lng of Event
});
Also I think App.Event should be:
App.Event = Em.Object.extend({
lat: null,
lng: null,
init : function(){
this.set('lat', -33.8665433);
this.set('lng', 151.1956316);
}
});
to avoid the so-called chromosomal mutation in Ember
Related
Hi I'm new to stackoverflow (and coding) but I am working on a web-application where I want to add dynamic markers and infowindows based on an extracted JSON file. There are over 200 markers, so they need to be dynamic. I have code that works to add markers but as soon as I add infoWindows it doesn't. Can anybody see why? The output dropped to just one marker and no infoWindow.
Here is my code:
function initMap() {
var myLatLng = {
lat: 26.967,
lng: -99.25
};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
$.ajax({
type: 'GET',
url: 'https://us-central1-cloud-calendar-project.cloudfunctions.net/InfoWindow',
success: function(data) {
data = JSON.parse(data)
infowindow = new google.maps.InfoWindow();
for (element in data) {
new google.maps.Marker({
position: {
lat: data[element].lat,
lng: data[element].lon
},
map: map,
title: element
});
infowindow.setContent(data[element].country);
marker.addListener('click', function() {
infowindow.open(map, marker);
});
}
}
});
}
I saw a post on stackoverflow with a similar question and tried it that way as well but didnt get any markers.
function initMap() {
var myLatLng = {
lat: 26.967,
lng: -99.25
};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
$.ajax({
type: 'GET',
url: 'https://us-central1-cloud-calendar-project.cloudfunctions.net/InfoWindow',
success: function(data) {
var json = data = JSON.parse(data);
for (var i = 0; i < json.length; i++) {
point = new google.maps.LatLng(json[i].lat, json[i].lon);
contentString = json[i].Country;
addMarkers(point, contentString);
}
}
});
function addMarkers(point, contentString) {
marker = new google.maps.Marker({
position: point,
map: map
});
infowindow = new google.maps.InfoWindow({
content: contentString
});
marker.push(marker);
infos.push(infowindow);
for (var j = 0; j < markers.length; j++) {
google.maps.event.addListener(markers[j], 'click', function() {
infos[j].open(map, markers[j]);
})
}
}
}
The output of my JSON file looks like this:
{
"AA": {
"celsius": 32.27777777777778,
"country": "AA",
"day": "25",
"lat": 12.5,
"lon": -70.017,
"month": "03"
},
...
}
There are a few issues in your code. You should read Using Closures in Event Listeners.
You should set the infowindow content on marker click (not within the loop, as you did)
You should declare the marker variable which is missing
Any variable you are using must be declared, for example for (element in data) should be for (var element in data)
function initMap() {
var myLatLng = {
lat: 26.967,
lng: -99.25
};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
$.ajax({
type: 'GET',
url: 'https://us-central1-cloud-calendar-project.cloudfunctions.net/InfoWindow',
success: function(data) {
data = JSON.parse(data)
console.log(data);
infowindow = new google.maps.InfoWindow();
for (var element in data) {
var marker = new google.maps.Marker({
position: {
lat: data[element].lat,
lng: data[element].lon
},
map: map,
title: element
});
google.maps.event.addListener(marker, 'click', (function(marker, element) {
return function() {
var content = 'Country: ' + data[element].country;
content += '<br>Temperature (°C): ' + data[element].celsius;
infowindow.setContent(content);
infowindow.open(map, marker);
}
})(marker, element));
}
}
});
}
initMap();
#map {
height: 180px;
}
<div id="map"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap" async defer></script>
I want to show Google map with draggable marker in my page . Here is my code:
header.php :
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3&sensor=true"></script>
map.js:
app.directive('mapDirective',function(){
return {
templateUrl: 'map.html',
restrict: 'EA',
require: '?ngModel',
scope:{
myModel: '=ngModel'
},
link: function(scope , element, attrs , ngModel){
var mapOptions;
var googleMap;
var searchMarker;
var searchLatLng;
scope.searchLocation = {
latitude: 48.137273,
longitude: 11.575251
};
ngModel.$render = function(){
console.log("hhh");
searchLatLng = new google.maps.LatLng(scope.myModel.latitude, scope.myModel.longitude);
mapOptions = {
center: searchLatLng,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
googleMap = new google.maps.Map(element[0],mapOptions);
searchMarker = new google.maps.Marker({
position: searchLatLng,
map: googleMap,
draggable: true
});
google.maps.event.addListener(searchMarker, 'dragend', function(){
scope.$apply(function(){
scope.myModel.latitude = searchMarker.getPosition().lat();
scope.myModel.longitude = searchMarker.getPosition().lng();
});
}.bind(this));
};
scope.$watch('myModel', function(value){
var myPosition = new google.maps.LatLng(scope.myModel.latitude, scope.myModel.longitude);
searchMarker.setPosition(myPosition);
}, true);
}
}
});
map.html:
<div>
<div style="display: block; height: 200px; width: 100%; ">
</div>
</div>
index.html:
<map-directive ng-model="testModel"></map-directive>
Actually , I got this error :
TypeError: Cannot read property 'latitude' of undefined
How to solve it?
EDITED:
I change my maps.js:
app.directive('mapDirective',function(){
return {
templateUrl: '/app/user/ngApp/templates/libsView/templates/directives/map.html',
restrict: 'EA',
require: '?ngModel',
scope:{
myModel: '=ngModel'
},
controller: function ($scope) {
$scope.searchLocation = {
latitude: 48.137273,
longitude: 11.575251
};
},
link: function(scope , element, attrs , ngModel){
var mapOptions;
var googleMap;
var searchMarker;
var searchLatLng;
ngModel.$render = function(){
console.log("hhh");
searchLatLng = new google.maps.LatLng(scope.myModel.latitude, scope.myModel.longitude);
mapOptions = {
center: searchLatLng,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
googleMap = new google.maps.Map(element[0],mapOptions);
searchMarker = new google.maps.Marker({
position: searchLatLng,
map: googleMap,
draggable: true
});
google.maps.event.addListener(searchMarker, 'dragend', function(){
scope.$apply(function(){
scope.myModel.latitude = searchMarker.getPosition().lat();
scope.myModel.longitude = searchMarker.getPosition().lng();
});
}.bind(this));
};
scope.$watch('myModel', function(value){
var myPosition = new google.maps.LatLng(scope.myModel.latitude, scope.myModel.longitude);
searchMarker.setPosition(myPosition);
}, true);
}
}
});
But it doesn't change.
myModel variable should contains latitude and longitude values. which should be set from
<map-directive ng-model="testModel"></map-directive>
You need to create a object as below in your controller and assign this object to directive as above html.
var testModel = {
latitude:1.2323,
longitude:2.3434
};
Well I'm having this problem, load the map once and everything works perfect. The second time or once update the map does not load ok, but not centered load when navigating on you can see the marks that are made but is deformed or simply lost.
I have tried several ways to solve this problem, first and most common I found was to use google.maps.event.trigger(map 'resize') but it did not work then and logic, try that whenever loading map is executed, create a new map, with the same data and focused but neither worked for me. It may be also the way I use the map. I am using the plugin of the camera in my application, the user takes a photo and this should detect where I draw the picture and display the map. Each time the view is opened, the plug of the camera, in the process of taking and show the picture is where I call the appropriate functions to load the map and this has me a bit tricky immediately loaded I have a good time locked in this problem, I found solutions serve me but only for the browser, the device does not work. I am using ionic framework and plugins cordova.
Controller :
.controller("CamaraCtrl", function($scope,$rootScope, Camera,$cordovaGeolocation,$state,$location,$ionicSideMenuDelegate) {
var posOptions = {timeout: 10000, enableHighAccuracy: false};
$cordovaGeolocation
.getCurrentPosition(posOptions)
.then(function (position) {
var latitud_actual = position.coords.latitude
var longitud_actual = position.coords.longitude
$scope.latitud = latitud_actual;
$scope.longitud = longitud_actual;
//$scope.map = new google.maps.Map(document.getElementById("mapa_ubicacion"), mapOptions);
}, function(err) {
// error
});
function initialize() {
var mapOptions = {
center: new google.maps.LatLng($scope.latitud, $scope.longitud),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
$scope.setMarker(map, new google.maps.LatLng($scope.latitud, $scope.longitud), 'Yo', '');
$scope.map = map;
}
$scope.setMarker = function(map, position, title, content) {
var marker;
var markerOptions = {
position: position,
map: map,
title: title
};
marker = new google.maps.Marker(markerOptions);
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);
});
}
$scope.mostrar_form = false;
$scope.mostrar_boton_view = false;
$scope.getPhoto = function() {
Camera.getPicture().then(function(imageURI) {
console.log(imageURI);
$scope.lastPhoto = imageURI;
$scope.mostrar_form = true;
$scope.mostrar_boton_view = false;
google.maps.event.addDomListener(window, 'load', initialize);
initialize();
}, function() {
$scope.mostrar_boton_view = true;
}, {
quality: 75,
targetWidth: 320,
targetHeight: 320,
saveToPhotoAlbum: false
});
};
$scope.getPhoto();
})
The only solution I found was to create a function that executes the map again. It should not be as optimal but at least it solved my problem.
$scope.centrar = function(){
var mapOptions = {
center: new google.maps.LatLng($scope.latitud, $scope.longitud),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
$scope.setMarker(map, new google.maps.LatLng($scope.latitud, $scope.longitud), 'Yo', '');
$scope.map = map;
}
I am having problems with a map of google play. In the first instance the entire load properly, but the second map is not loaded. I thought that this would be solved some methods but nothing. I have taken this to clear the map.
var map = document.getElementById("mapa_ubicacion");
google.maps.event.trigger(map, 'resize');
This map is loaded each time the person takes a picture with the camera of the mobile device is why many times you could occupy.
$scope.cargarUbicacion = function () {
var posOptions = {timeout: 10000, enableHighAccuracy: false};
$cordovaGeolocation
.getCurrentPosition(posOptions)
.then(function (position) {
var latitud_actual = position.coords.latitude
var longitud_actual = position.coords.longitude
var mapOptions = {
center: new google.maps.LatLng(latitud_actual, longitud_actual),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
map = new google.maps.Map(document.getElementById("mapa_ubicacion"), mapOptions);
$scope.setMarker(map, new google.maps.LatLng(latitud_actual, longitud_actual), 'Yo', '');
}, function(err) {
// error
});
var watchOptions = {
frequency : 1000,
timeout : 3000,
enableHighAccuracy: false // may cause errors if true
};
var watch = $cordovaGeolocation.watchPosition(watchOptions);
watch.then(
null,
function(err) {
// error
},
function(position) {
var latitud_actual = position.coords.latitude
var longitud_actual = position.coords.longitude
var mapOptions = {
center: new google.maps.LatLng(latitud_actual, longitud_actual),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
map = new google.maps.Map(document.getElementById("mapa_ubicacion"), mapOptions);
$scope.setMarker(map, new google.maps.LatLng(latitud_actual, longitud_actual), 'Yo', '');
});
watch.clearWatch();
}
Try to create a single map instance in an initial function in your controller and add the map object to the scope. Then only update the map location in your methods. This helped me to solve a similar problem.
$scope.init = function() {
var mapOptions = {
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
var map = new google.maps.Map(document.getElementById("mapa_ubicacion"), mapOptions);
$scope.map = map;
}
$scope.init();
})
In your methods do the following:
//set map center with your coords on $scope.map
$scope.setMarker($scope.map, new google.maps.LatLng(latitud_actual, longitud_actual), 'Yo', '');
I am trying to use Google maps with backbone.js. So I created a view as below. But this isn't working for me. Any inputs?
(function($){
var CreateMap = Backbone.View.extend({
tagName: "div",
initialize: function() {
_.bindAll(this, 'render');
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.el, myOptions);
this.render();
},
render: function() {
return this;
}
});
var mapview = new CreateMap({el: $("#map_canvas")});
})(jQuery);
As PhD noted, you need to have render actually do something. Here's my own working example, which assumes there is some existing <div id="map"></div> on the page:
APP = {};
APP.Map = Backbone.Model.extend({
defaults: {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
});
APP.map = new APP.Map();
APP.MapView = Backbone.View.extend({
id: 'map',
initialize: function(){
this.map = new google.maps.Map(this.el, this.model.attributes);
this.render();
},
render: function(){
$('#map').replaceWith(this.el);
}
});
APP.mapView = new APP.MapView({model: APP.map});
Instead of passing the #map_canvas div, set it up so you inject mapview.render().el into your DOM. You could do this in a backbone router class.
Calling the render function from your initialization function is not necessary.
If after this you still don't see anything, add a className to your view and make sure you have the right CSS width/height styles linked to that class.
Are you passing in Backbone to the scope of your wrapping function?