MarkerClusterer & jQuery UI Map: clusters not showing - google-maps-api-3

I am using the jquery-ui-map plugin together with markerclusterer.
Markers are loaded from an external JSON file. This works great to add the markers and content for each info window. No problems so far.
jQuery, jQuery UI Map and MarkerClusterer scripts are properly referenced in my document. However, I can't seem to cluster the markers.
Here my script to show the map. Have I overseen something?
$('#map_canvas').gmap().bind('init', function(event, map) {
$.getJSON( MY_JSON_URL, function(data) {
$.each( data.posts, function(i, marker) {
$('#map_canvas').gmap('addMarker', {
'position': new google.maps.LatLng(marker.custom_fields._cmb_tatort_map_latitude, marker.custom_fields._cmb_tatort_map_longitude)
}).click(function() {
$('#map_canvas').gmap('openInfoWindow', {
//some content here
}, this );
});
});
});
$('#map_canvas').gmap('set', 'MarkerClusterer', new MarkerClusterer($('#map_canvas').gmap('get', 'map'), $('#map_canvas').gmap('get', 'markers')));
});

You need to create the marker clusterer after the markers have been added to the map, not before.
$('#map_canvas').gmap().bind('init', function(event, map) {
$.getJSON( MY_JSON_URL, function(data) {
$.each( data.posts, function(i, marker) {
$('#map_canvas').gmap('addMarker', {
'position': new google.maps.LatLng(marker.custom_fields._cmb_tatort_map_latitude, marker.custom_fields._cmb_tatort_map_longitude)
}).click(function() {
$('#map_canvas').gmap('openInfoWindow', {
//some content here
}, this );
});
});
$('#map_canvas').gmap('set', 'MarkerClusterer', new MarkerClusterer($('#map_canvas').gmap('get', 'map'), $('#map_canvas').gmap('get', 'markers')));
});
});

Related

Why isn't this template reactive?

Why isn't this reactive? And more importantly how can it be made reactive?
I'd like the data to be saved in Mongo and used in the template. I could use a ReactiveVar or ReactiveDict. Do I need two copies of the data?
Doesn't Suspects.findOne('bruce') return a reactive object already? I tried putting the human answer directly on Bruce, but it didn't trigger an update.
The events fire, log(this) shows bruce's answer was changed, but the template doesn't re-render. What's the good way to do this?
http://meteorpad.com/pad/KoH5Qu7Fg3osMQ79e/Classification
It's Meteor 1.2 with iron:router added:
<head>
<title>test</title>
</head>
<template name="question">
{{#unless isAnswered 'human'}} <!-- :-< I'm not reacting here -->
<div>Sir, are you classified as human?</div>
<button id="no">No, I am a meat popsicle</button>
<button id="smokeYou">Smoke you</button>
{{else}}
<div> Classified as human? <b>{{answers.human}}</b></div>
{{/unless}}
</template>
And the JavaScript:
// Why isn't this reactive?
if (Meteor.isClient) {
Template.question.helpers({
isAnswered: function (question) { // :-< I'm not reactive
var suspect = Template.instance().data;
return (typeof suspect.answers[question] !== 'undefined');
}
});
Template.question.events({
'click #no': function () {
this.answers.human = "No"; // :-< I'm not reactive
console.log(this);
},
'click #smokeYou': function() {
this.answers.human = "Ouch"; // :-< I'm not reactive
console.log(this);
}
});
}
// Collection
Suspects = new Meteor.Collection('suspects');
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
Suspects.upsert('bruce', { quest: 'for some elements', answers: {}});
});
Meteor.publish('suspects', function() {
return Suspects.find({});
});
}
// Iron Router
Router.route('/', {
template: 'question',
waitOn: function() {
return Meteor.subscribe('suspects');
},
data: function() {
return Suspects.findOne('bruce');
}
});
Thanks :-)
The events are not actually updating the reactive data source (the db record). Instead of doing:
Template.question.events({
'click #no': function () {
this.answers.human = "No";
}
});
The event needs to perform a database action, either through a direct update or through a Meteor.call() to a Meteor.method. For example:
'click #no': function(){
Suspects.update('bruce', {'answers': {'human': 'no'}});
}
If you use this pattern, you will also need to set the correct allow and deny rules to permit the update from client code. http://docs.meteor.com/#/full/allow. Methods generally end up being a better pattern for bigger projects.
Also, I'm not sure off the top of my head that Template.instance().data in your helper is going to be reactive. I would use Template.currentData() instead just to be sure. http://docs.meteor.com/#/full/template_currentdata
Very close you just need to use ReactiveVar by the sound of it it pretty much explains what it's :) http://docs.meteor.com/#/full/reactivevar
and here's how to use it
if (Meteor.isClient) {
Template.question.onCreated(function () {
this.human = new ReactiveVar();
});
Template.question.helpers({
isAnswered: function (question) {
return Template.instance().human.get();
}
});
Template.question.events({
'click #no': function (e, t) {
t.human.set('No');
console.log(t.human.get());
},
'click #smokeYou': function(e, t) {
t.human.set('Ouch');
console.log(t.human.get());
}
});
}
UPDATE: if you're using a cursor I usually like to keep it on the template level not on iron router:
if (Meteor.isClient) {
Template.question.helpers({
isAnswered: function (question) {
return Suspects.findOne('bruce');
}
});
Template.question.events({
'click #no': function (e, t) {
Suspects.update({_id: ''}, {$set: {human: 'No'}});
},
'click #smokeYou': function(e, t) {
Suspects.update({_id: ''}, {$set: {human: 'Ouch'}});
}
});
}

Google map resize not solving partial display issue within a modal dialogue

I known this question has been raised and answered many times but I can't seem to make the suggested solutions work for me...
I'm displaying a google map within a simplemodal dialogue.
Outside the modal dialogue the map displays correctly.
However, once inside a modal wrapper only part of the map is shown on the first iteration (see below).
The solution would appear to involve binding a 'resize' event to the map but it isn't working for me...
First iteration:
On opening the modal for the first iteration, my map displays with the partial section displaced over to the top RHS and overlaid on the full map.
On closing the first dialogue the screen returns to it's initial state.
Second and subsequent iterations:
On subsequent iterations the map displays correctly but on closing the background color of the map canvas is visible.
HTML:
<body>
<button class="modalMap">With Modal </button>
<button class="nonModalMap">Without Modal </button>
<div id="mapCanvas"></div>
</body>
CSS:
#simplemodal-overlay {background-color:#000;}
#simplemodal-container {color:#999; background-color:#fff;}
#simplemodal-container a{color:#ddd;}
.modalMap:hover,.nonModalMap:hover {
cursor:pointer;
}
#mapCanvas {
position:relative;
width:480px;height:300px;
}
JS:
$(document).ready(function(){
var myMap;
$('.modalMap').click(function(){
buildMap();
$('#mapCanvas').modal(
{onOpen:function(dialog){
dialog.overlay.fadeIn('fast',function(){
dialog.data.hide();dialog.container.fadeIn('fast',function(){
dialog.data.slideDown('fast');
});
});
}
,onClose:function(dialog){
dialog.data.fadeOut('fast',function(){
dialog.container.hide('fast',function(){
dialog.overlay.slideUp('fast',function(){
$.modal.close();
});
});
});
}
});
});
/* But without the modal the map displays correctly... */
$('.nonModalMap').click(function(){
buildMap();
});
});
function buildMap() {
var kpl = {
Place: function (data, map) {
var self = this;
this.data = data;
var coords = data.geo_coords.split(',');
this.position = new google.maps.LatLng(coords[0], coords[1]);
this.marker = new google.maps.Marker({
position: this.position,
map: map
});
google.maps.event.addListener(this.marker, 'click', function() {
if (self.data.url) {
window.location.href = self.data.url
}
});
},
MapManager: function (div, data) {
this.map = new google.maps.Map(div, {
zoom: 15,
center: new google.maps.LatLng(53.818298, -1.573263),
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false,
backgroundColor: '#cccccc',
streetViewControl: false,
navigationControl: true,
mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}
});
saveCenter = this.map.center;
this.places = [];
for (var i in data) {
if (data.hasOwnProperty(i)) {
this.places.push(new kpl.Place(data[i], this.map));
}
}
}
};
myMap = new kpl.MapManager($('#mapCanvas').get(0), [{
url: "mailto:info#????.com",
geo_coords: "53.818298, -1.573263",
name: "Kensington Property LS6"
}]);
}
/* plus the simplemodal library... */
I've recreated the code in jsfiddle - http://jsfiddle.net/redApples/j23ue0n1/32/
Can anybody rescue my sanity...?

Google maps circle overlay . how to call a function on after drag complete?

Guys after a long R&D I was able to draw a circle and put markers which are inside that area of circle based on position and radius.
I'm calling a function which triggers whenever the radius or the position of the circle changes..
It is working fine( function triggers and it fetches the markers from the database.) but the function is called when the circle is being dragged(some 100 times). i want that function to called OnDragComplete.. i didn't find any such events Google API..
below is my code.. Any help would be greatly appreciated.
google.maps.event.addListener(distanceWidget, 'distance_changed', function() {
displayInfo(distanceWidget);
searchLocations();
});
google.maps.event.addListener(distanceWidget, 'position_changed', function() {
displayInfo(distanceWidget);
searchLocations();
});
You could add a "dragging" property to the widget on the mouse events and check it in your other functions:
google.maps.event.addListener(distanceWidget, 'mousedown', function() {
distanceWidget.dragging = true;
});
google.maps.event.addListener(distanceWidget, 'mouseup', function() {
distanceWidget.dragging = false;
});
google.maps.event.addListener(distanceWidget, 'position_changed', function() {
if (distanceWidget.dragging === false) {
displayInfo(distanceWidget);
searchLocations();
}
});
I too faced this issue. we can use drag and dragend event listener inside
DistanceWidget function and use marker instance to listen
function DistanceWidget(map) {
this.set('map', map);
this.set('position', map.getCenter());
var marker = new google.maps.Marker({
lat: $('input[name=lat]').val(),
lng: $('input[name=lng]').val(),
draggable: true,
crossOnDrag: false,
cursor: 'crosshair',
title: 'Drag to change circle radius!',
icon: 'assets/front/images/pin.png',
});
google.maps.event.addListener(marker, 'drag', function(e) {
console.log('starting');
});
google.maps.event.addListener(marker, 'dragend', function(e) {
// Trigger once u drop the widget marker
console.log('end');
});
}

Check streetview exists when displaying it in infowindow

following this example http://www.keypointpartners.com/test/mab/fromxml1.html and Google Maps API v3 documentation (https://developers.google.com/maps/documentation/javascript/streetview) I've put together a map that loads markers from an XML file and display a tabbed infowindow for each loaded marker. Wishing to check if a location actually has a streetview available, I've modified my createMarker to this:
function createMarker(latlng, name, html) {
//var contentString = html;
var contentString = [
'',
'',
name,
'',
'',
'Località',
'Struttura',
'Voli',
//'Opzioni',
'Streetview',
'',
html,
''
].join('');
// Create a marker
var marker = new google.maps.Marker({
position: latlng,
title: name,
map: inc_map
});
// Add a listener to the marker to populate and open the infowindow
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(inc_map, marker);
google.maps.event.addListener(infowindow, 'domready', function() {
inc_sv.getPanoramaByLocation(marker.position, 50, processSVData);
//console.log("Adding tabs");
$('#tabs').tabs();
});
});
Tha callback function used by getPanoramaByLocation is as follows:
function processSVData(data, status) {
if (status == google.maps.StreetViewStatus.OK) {
google.maps.event.addListener(infowindow, 'domready', function() {
$('#stv-lnk').click(function() {
var panoramaOptions = {
position: data.location.latLng,
visible: true,
linksControl: false,
panControl: false,
addressControl: false,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL
},
enableCloseButton: false
};
var panorama = new google.maps.StreetViewPanorama(document.getElementById("stvpano"), panoramaOptions);
inc_map.setStreetView(panorama);
});
});
} else {
google.maps.event.addListener(infowindow, 'domready', function() {
$('#stv-lnk').click(function() {});
document.getElementById("stvpano").innerHTML = "Streetview non è disponibile per questo luogo"
});
}
}
Now, what happens is that first streetview tab doesn't show anything, while next clicked streetview tabs show previous tab's streetview. Comparing to the abovementioned example from API docs, I build a separate StreetViewPanorama object for each tab (while the example uses a global panorama var to hold it).
Is this my mistake? Or...?
Link at the actual page: http://turom-mice.it/condorincentive/incentive.html
Any help/suggestion greatly appreciated!
Cheers,
rash*
EDIT: ok, I solved one of the problems. I was nesting too many eventListener: I removed the ones inside function processSVData and each infowindow nows show the correct streetview. The code now looks like this:
function processSVData(data, status) {
if (status == google.maps.StreetViewStatus.OK) {
$('#stv-lnk').click(function() {
var panoramaOptions = {
position: data.location.latLng,
visible: true,
linksControl: false,
panControl: false,
addressControl: true,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL
},
enableCloseButton: false
};
var panorama = new google.maps.StreetViewPanorama(document.getElementById("stvpano"), panoramaOptions);
inc_map.setStreetView(panorama);
});
} else {
$('#stv-lnk').click(function() {
inc_map.setStreetView(null);
document.getElementById("stvpano").innerHTML = "Streetview non è disponibile per questo luogo"
});
}
}
Now, the problem is that the 'else' branch seems doing nothing: when a location has no streetview available, you see last shown streetview, no matter I've set it to null and put some warning text inside the div (I should show a link to a substitute gallery page though). question is: is this correct? Or...?
As usual, any help/hint/suggestion...
Ciao,
rash*
EDIT 2: ok, solved completely. The else branch didn't manage the click event, so putting it back in place solved. The code just above has been edited to reflect the solution.
Thanks anyway, waiting for an answer made me re-think the whole thing. Hope this could be of some help to anybody.
rash*

How to asynchronously load a google map in AngularJS?

Now that I have found a way to initialize Google Maps with the help of Andy Joslin in this SO initialize-google-map-in-angularjs, I am looking for a way to asynchronous load a Google Map Object.
I found an example of how to do this in the phonecat project.
Notice how the JS files are loaded in this example: index-async.html
In my Jade Scripts partial that is loaded into my program I tried:
script(src='js/lib/angular/angular.js')
script(src='js/lib/script/script.min.js')
script
$script([
'js/lib/angular/angular-resource.min.js',
'js/lib/jquery/jquery-1.7.2.min.js',
'http://maps.googleapis.com/maps/api/js?key=AIzaSyBTmi_pcXMZtLX5MWFRQgbVEYx-h-pDXO4&sensor=false',
'js/app.js',
'js/services.js',
'js/controllers.js',
'js/filters.js',
'js/directives.js',
'bootstrap/js/bootstrap.min.js'
], function() {
// when all is done, execute bootstrap angular application
angular.bootstrap(document, ['ofm']);
});
When I do this and go to load the map page I get:
A call to document.write() from an asycrononously-loaded
external script was ignored.
This is how Google Maps is being loaded now as a service:
'use strict';
var app = angular.module('ofm.services', []);
app.factory('GoogleMaps', function() {
var map_id = '#map';
var lat = 46.87916;
var lng = -3.32910;
var zoom = 15;
var map = initialize(map_id, lat, lng, zoom);
return map;
});
function initialize(map_id, lat, lng, zoom) {
var myOptions = {
zoom : 8,
center : new google.maps.LatLng(lat, lng),
mapTypeId : google.maps.MapTypeId.ROADMAP
};
return new google.maps.Map($(map_id)[0], myOptions);
}
It appears that this should be returning a promise from what I recall reading. But this AngularJS is very new to me.
here's my solution I came up without using jQuery:
(Gist here)
angular.module('testApp', []).
directive('lazyLoad', ['$window', '$q', function ($window, $q) {
function load_script() {
var s = document.createElement('script'); // use global document since Angular's $document is weak
s.src = 'https://maps.googleapis.com/maps/api/js?sensor=false&callback=initialize';
document.body.appendChild(s);
}
function lazyLoadApi(key) {
var deferred = $q.defer();
$window.initialize = function () {
deferred.resolve();
};
// thanks to Emil Stenström: http://friendlybit.com/js/lazy-loading-asyncronous-javascript/
if ($window.attachEvent) {
$window.attachEvent('onload', load_script);
} else {
$window.addEventListener('load', load_script, false);
}
return deferred.promise;
}
return {
restrict: 'E',
link: function (scope, element, attrs) { // function content is optional
// in this example, it shows how and when the promises are resolved
if ($window.google && $window.google.maps) {
console.log('gmaps already loaded');
} else {
lazyLoadApi().then(function () {
console.log('promise resolved');
if ($window.google && $window.google.maps) {
console.log('gmaps loaded');
} else {
console.log('gmaps not loaded');
}
}, function () {
console.log('promise rejected');
});
}
}
};
}]);
If you using jQuery in your AngularJS app, check out this function which returns a promise for when the Google Maps API has been loaded:
https://gist.github.com/gbakernet/828536
I was able to use this in a AngularJS directive to lazy-load Google Maps on demand.
Works a treat:
angular.module('mapModule') // usage: data-google-map
.directive('googleMap', ['$window', function ($window) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
// If Google maps is already present then just initialise my map
if ($window.google && $window.google.maps) {
initGoogleMaps();
} else {
loadGoogleMapsAsync();
}
function loadGoogleMapsAsync() {
// loadGoogleMaps() == jQuery function from https://gist.github.com/gbakernet/828536
$.when(loadGoogleMaps())
// When Google maps is loaded, add InfoBox - this is optional
.then(function () {
$.ajax({ url: "/resources/js/infobox.min.js", dataType: "script", async: false });
})
.done(function () {
initGoogleMaps();
});
};
function initGoogleMaps() {
// Load your Google map stuff here
// Remember to wrap scope variables inside `scope.$apply(function(){...});`
}
}
};
}]);
Take a look of this i think its more reliable
var deferred = $q.defer();
var script = document.createElement('script');
$window.initMap = function() {
//console.log("Map init ");
deferred.resolve();
}
script.src = "//maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=places&callback=initMap";
document.body.appendChild(script);
return deferred.promise;

Resources