Google Maps Api v3 - new MarkerClusterer works too slow? - google-maps-api-3

to create map clusterer, i use:
markerClustererGPC = new MarkerClusterer(myMap.map, markersGPC, GPCOptions);
but sometimes it does not works, and markerClustererGPC is sometimes undefined.
i search on this problem, and realise that (it looks like) server is sometimes too fast, and cluster is not defined due to that.
if server is a bit older (slower), it works without problems.
am i right about this? what can i do to avoid this problem, to make my code proper to work on any server?

i think because google map is not loaded completed so your map is unidentified.
Try add this:
var isLoad = false;
google.maps.event.addListener(map,'tilesloaded',
function () {
if (!isLoad) {
isLoad = true;
LoadClusterFunction();
}
});
after your call for creating map (map is variable for google map)

Related

Meteor Dashboard and publication/subscription

EDIT: as the original question was too vague I have updated it to make it more concrete
I'd like to create a dashboard in Meteor that shows some statistics about my collections (e.g. how many docs, how many users...). I have been trying the past days but can't seem to find a good/intelligent way.
I initially just did the following:
Template.dashboard.helpers({
getProductsCount: function() {
return Products.find().count();
}
});
This did not work. I think because it counts the number of products from minimongo, but not sure.
Then I did the following:
In the template helper, call a method and get the value to show on the dashboard page (does not work)
Was told not to use pub/sub mechanism for this type of metric
Worked via Session variables (did work, but feels a bit strange to store this kind of metric data in Session variables
So then I read in another SO response about Reactive Variables and tried the following:
Template.dashboard.helpers({
getProductsCount: function() {
return Template.instance().myAsyncValue.get();
}
});
Template.dashboard.created = function() {
var self = this;
self.myAsyncValue = new ReactiveVar("Waiting for response from server");
Meteor.call('getProductsCount', function(error, asyncValue){
if (error)
console.log(error);
else
self.myAsyncValue.set(asyncValue);
});
};
This works, but I find this extremely difficult for something as simple as showing a product count (or any other metric). Not sure I understand the reason why I should use sth as reactive variables?
Then -out of curiosity- I tried the following (using meteor add simple:reactive-method) and it works:
Template.customerDashboard.helpers({
getProductsCount: function () {
return ReactiveMethod.call("getProductsCount");
}
});
So the question really is why having to use Reactive variables and methods for sth as simple as this. Can someone explain?
If you want to show the count only in the view, the best way is to return the count number only. you do not need publish/subscribe at all. you can use server methods. and if you want to show data also, you can go for pub-sub. and your approach is correct.

Firebase remove+limited query caching bug?

If I read a value from Firebase and then remove it, a subsequent limited read (e.g. dataRef.limit(10).once("value") ) will still see the removed value.
If I do an unlimited read, then I won't see the removed value, and a subsequent limited read will also no longer see the removed value.
var gFirebase = new Firebase("https://brianshmrian.firebaseio.com/");
function CreateValue()
{
gFirebase.child("TestBug/Key").set("Value");
}
function ReadValue(limit)
{
var dataRef = gFirebase.child("TestBug");
if (limit)
dataRef = dataRef.limit(10);
dataRef.once("value",function(snapshot)
{
alert((limit?"Limited read\n":"Normal read\n") + snapshot.val());
});
}
function RemoveValue()
{
gFirebase.child("TestBug/Key").remove();
}
In this example code, if I do a CreateValue(), then a ReadValue(), then a RemoveValue(), then a ReadValue(true), the object will still be reported to me in the last ReadValue(). However, if I do a ReadValue(false), I'll no longer see the value, and a subsequent ReadValue(true) will not see the value either.
See here to try it for yourself: http://jsfiddle.net/brianshmrian/5WWR6/
So is this a bug? Or am I making a mistake?
EDIT
Ok, that seems like a not too painful workaround. The code below solves my problem for now:
// Need to do this before the remove to avoid caching problem
dataRef.on("value", function(snapshot)
{
setTimeout(function() { dataRef.off(); }, 3000);
});
dataRef.remove();
I can't find any issues with the code. There is always the gotcha that locally cached data is returned synchronously, but I don't see that as an issue here; there's no way for the read to be getting called before the remove has completed. It looks like a pretty straightforward bug.
I was able to circumvent the behavior by setting up the limit(10).on('value') before calling the add/delete operations. So I think that if you establish your query ref first, you'll be okay.
Example: http://jsfiddle.net/katowulf/6wQFF/2/ (the pre tag is set up on load)

change collection before publishing

I would like to add a property to the objects that get published to the client.
My publish function looks like that
Meteor.publish("forms", function() {
return Forms.find();
});
I would like to do something like this
Meteor.publish("forms", function() {
var forms = Forms.find();
forms.forEach(function (form) {
form.nbForms = 12;
}
return forms;
});
What I would like is that all the documents in forms have a new count attribute which gets sent to the client.
But this obviously does not work.
thank you for your help
Not sure it will work in your case but you might use the new transform collection function introduced with Meteor 0.5.8
When declaring your collection, add this function as the second parameter :
Forms = new Meteor.Collection("forms", {
transform: function(f) {
f.nbForms = 12;
return f;
}
});
But this will be on both server and client. I don't know if there is a way to define a transform function in a publish context.
I think you need to do something similar to this Meteor counting example in Publish:
How does the messages-count example in Meteor docs work?
I also posted a question here that may help once it's answered. Meteor has a this.added which may work, but I'm currently uncertain how to use it. Hence the question below:
Meteor, One to Many Relationship & add field only to client side collection in Publish?

What is the best way to update cluster icon using gmaps4rails

I am a big fan of gmaps4rails gem and it has been working well and very flexible.
However, I cannot seem to clear and update the Cluster marker easily and I cannot find similar solutions on Stackoverflow that is using this gem.
In my javascript, I am using the following methods to filter out visible markers. But Gmaps.map.clearClusterer doesn't seem to respond to click event. I am able to show and hide markers properly but not able to clear cluster markers nor update the cluster markers with new number. What should I do differently?
var VisibleMarker=function(){
var filtered=_.filter(Gmaps.map.markers,function(marker){
return marker.building_type == SELECT;
}); //end of _.filter
return filtered
}//end of VisibleMarker
var applyFilters=function(){
var VisibleArray=VisibleMarker()
_.each(Gmaps.map.markers,function(marker){
Gmaps.map.hideMarker(marker)
})
Gmaps.map.clearClusterer()
_.each(VisibleArray,function(marker){
Gmaps.map.showMarker(marker)
})
Gmaps.map.createClusterer(VisibleArray)
};//end of applyFilters
UPDATE:
How should I properly call the addMarkers() method in the MarkerClusterer Class?
http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/docs/reference.html
I used this line:
Gmaps.map.addMarkers(VisibleArray)
But it calls this function instead:
Gmaps4Rails.prototype.addMarkers = function(new_markers) {
this.markers = this.markers.concat(new_markers);
this.create_markers();
return this.adjustMapToBounds();
};

How to work with async code in Mongoose virtual properties?

I'm trying to work with associating documents in different collections (not embedded documents) and while there is an issue for that in Mongooose, I'm trying to work around it now by lazy loading the associated document with a virtual property as documented on the Mongoose website.
The problem is that the getter for a virtual takes a function as an argument and uses the return value for the virtual property. This is great when the virtual doesn't require any async calls to calculate it's value, but doesn't work when I need to make an async call to load the other document. Here's the sample code I'm working with:
TransactionSchema.virtual('notebook')
.get( function() { // <-- the return value of this function is used as the property value
Notebook.findById(this.notebookId, function(err, notebook) {
return notebook; // I can't use this value, since the outer function returns before we get to this code
})
// undefined is returned here as the properties value
});
This doesn't work since the function returns before the async call is finished. Is there a way I could use a flow control library to make this work, or could I modify the first function so that I pass the findById call to the getter instead of an anonymous function?
You can define a virtual method, for which you can define a callback.
Using your example:
TransactionSchema.method('getNotebook', function(cb) {
Notebook.findById(this.notebookId, function(err, notebook) {
cb(notebook);
})
});
And while the sole commenter appears to be one of those pedantic types, you also should not be afraid of embedding documents. Its one of mongos strong points from what I understand.
One uses the above code like so:
instance.getNotebook(function(nootebook){
// hey man, I have my notebook and stuff
});
While this addresses the broader problem rather than the specific question, I still thought it was worth submitting:
You can easily load an associated document from another collection (having a nearly identical result as defining a virtual) by using Mongoose's query populate function. Using the above example, this requires specifying the ref of the ObjectID in the Transaction schema (to point to the Notebook collection), then calling populate(NotebookId) while constructing the query. The linked Mongoose documentation addresses this pretty thoroughly.
I'm not familiar with Mongoose's history, but I'm guessing populate did not exist when these earlier answers were submitted.
Josh's approach works great for single document look-ups, but my situation was a little more complex. I needed to do a look-up on a nested property for an entire array of objects. For example, my model looked more like this:
var TransactionSchema = new Schema({
...
, notebooks: {type: [Notebook]}
});
var NotebookSchema = new Schema({
...
, authorName: String // this should not necessarily persist to db because it may get stale
, authorId: String
});
var AuthorSchema = new Schema({
firstName: String
, lastName: String
});
Then, in my application code (I'm using Express), when I get a Transaction, I want all of the notebooks with author last name's:
...
TransactionSchema.findById(someTransactionId, function(err, trans) {
...
if (trans) {
var authorIds = trans.notebooks.map(function(tx) {
return notebook.authorId;
});
Author.find({_id: {$in: authorIds}, [], function(err2, authors) {
for (var a in authors) {
for (var n in trans.notebooks {
if (authors[a].id == trans.notebooks[n].authorId) {
trans.notebooks[n].authorLastName = authors[a].lastName;
break;
}
}
}
...
});
This seems wildly inefficient and hacky, but I could not figure out another way to accomplish this. Lastly, I am new to node.js, mongoose, and stackoverflow so forgive me if this is not the most appropriate place to extend this discussion. It's just that Josh's solution was the most helpful in my eventual "solution."
As this is an old question, I figured it might use an update.
To achieve asynchronous virtual fields, you can use mongoose-fill, as stated in mongoose's github issue: https://github.com/Automattic/mongoose/issues/1894

Resources