AMD version of Google Maps V3 for use with require.js? - google-maps-api-3

Has anybody used Googlemaps V3 with something like require.js where it needs to be in AMD version? Is there one already done somewhere?

In require.js you can use the async plugin, then call it like such:
define([
'async!http://maps.google.com/maps/api/js?sensor=false'
], function(){
//Create your map.
});

You can also do it using jQuery.Deferred() and some global variables (not ideal, but I needed it so I could optimize my files using grunt rjs, which didn't work for async):
// gmapsDone.js
window._mapsLoaded = $.Deferred();
window.gmapsLoaded = function(data) {
delete window.gmapsLoaded;
_mapsLoaded.resolve();
};
define(["http://maps.google.com/maps/api/js?v=3&sensor=false&callback=gmapsLoaded"], function(gmaps) {
"use strict";
return window._mapsLoaded.done;
});
Then, to use it:
define(["gmapsDone"], function(gmapsDone) {
function load() {
// Do something
}
gmapsDone(load);
});
https://gist.github.com/taktran/5389668
Inspired by http://blog.pixelingene.com/2011/10/using-jquery-dot-deferred-and-requirejs-to-lazy-load-google-maps-api/

I recently helped a friend solve this issue with a take off on the $.Deferred approach mentioned above. This plays nice with the optimizer and doesn't cause multiple script loads.
The Module
var google_maps_loaded_def = null;
define(['jquery'],function($) {
if(!google_maps_loaded_def) {
google_maps_loaded_def = $.Deferred();
window.google_maps_loaded = function() {
google_maps_loaded_def.resolve(google.maps);
}
require(['http://maps.googleapis.com/maps/api/js?sensor=true&callback=google_maps_loaded'],function(){},function(err) {
google_maps_loaded_def.reject();
//throw err; // maybe freak out a little?
});
}
return google_maps_loaded_def.promise();
});
Available as a Gist:
https://gist.github.com/MattSurabian/7868115
Usage
To Use the above module and take advantage of the fact that the promise resolves with google.maps:
define([ 'app/lib/google-maps-loader' ], function(GoogleMapsLoader){
GoogleMapsLoader.done(function(GoogleMaps){
// your google maps code here!
var geocoder = new GoogleMaps.Geocoder();
}).fail(function(){
console.error("ERROR: Google maps library failed to load");
});
});
Alternatively, just reference the google.maps object normally
define([ 'app/lib/google-maps-loader' ], function(GoogleMapsLoader){
GoogleMapsLoader.done(function(){
// your google maps code here!
var geocoder = new google.maps.Geocoder();
}).fail(function(){
console.error("ERROR: Google maps library failed to load");
});
});
I wrote a short blog post about this method here, which may be of some use: RequireJS Projects and Asynchronously Loading the Google Maps API

I put together a Google Maps AMD loader plugin, which adds some functionality on top of the async! loader.
require.config({
googlemaps: {
params: {
key: 'abcd1234', // sets api key
libraries: 'geometry' // set google libraries
}
}
});
require(['googlemaps!'], function(gmaps) {
// google.maps available as gmaps
var map = new gmaps.Map('map-canvas');
});

Related

Accessing Elements on electron webview using spectron

I am trying to automate a electron app which loads its content on to an webview. I am using spectron and webdriverio for it.
here is the code i am using.
it('should assess webview', function() {
var self = this;
return this.app.client.waitUntilWindowLoaded()
.windowHandles().then(function(session) {
self.app.client.switchTab(session.value[1])
.click("#my-id")
.then(console.log.bind(console))
.catch(console.log.bind(console));
});
});
This doesn't seem to work. i am not sure where i am going wrong. But i used
it('should assess webview', function() {
var self = this;
return this.app.client.waitUntilWindowLoaded()
.windowHandles().then(function(session) {
self.app.client.switchTab(session.value[1])
.getSource()
.then(console.log.bind(console))
.catch(console.log.bind(console));
});
});
the above code to ensure whether the webview window handle is correct. And it is. Kindly help. Thanks
I have checked the code, using spectron and running webview inside simulating this behaviour, your code works fine. Re-written the codes. Hope this helps.
it('should assess webview', function() {
var self = this;
return this.app.client.waitUntilWindowLoaded()
.windowHandles().then(function(session) {
// Need to return the promise back, if promise is
// it would wait for the state or else app will exit.
return self.app.client.switchTab(session.value[1])
.click("#my-id") // check whether selector is present in DOM
.then(console.log.bind(console))
.catch(console.log.bind(console));
});
});
or
it('should assess webview', function() {
var self = this;
return this.app.client.waitUntilWindowLoaded()
.windowHandles()
.then(function(session) {
// switchTab & window will both focus
// window or tab which is active
return this.window(session.value[1])
})
.click("#my-id") // check whether selector is present in DOM
.then(console.log.bind(console))
.catch(console.log.bind(console));;
});

Duplicate data on push/add to firebase using angularfire

Is there a way (maybe using rules) to duplicate data on add/push to firebase?
What I want to archive is when I do an add to a firebase array I want to duplicate the data to another array.
So this is my firebase structure:
my-firebase: {
items: [ ... ],
queue: [ ... ]
}
And this is how I have my services defined:
.factory('Service1',['$firebaseArray', function($firebaseArray) {
var items = new Firebase('my-firebase.firebaseio.com/items');
return $firebaseArray(items);
}])
.factory('Service2',['$firebaseArray', function($firebaseArray) {
var queue = new Firebase('my-firebase.firebaseio.com/queue');
return $firebaseArray(queue);
}])
And here is how I use them:
.controller('controller', function($scope, Service1, Service2) {
$scope.save = function() {
Service1.$add({name: "test1"});
Service2.$add({name: "test1"});
}
};
And want I to have a single call not a duplicate call/code but having the result in both arrays (items and queue).
Thanks so much!
Always remember that AngularFire is a relatively thin wrapper around Firebase's JavaScript SDK that helps in binding data into your AngularJS views. If you're not trying to bind and something is not immediately obvious, you'll often find more/better information in the documentation of Firebase's JavaScript SDK.
The API documentation for $firebaseArray.$add() is helpful for this. From there:
var list = $firebaseArray(ref);
list.$add({ foo: "bar" }).then(function(ref) {
var id = ref.key();
console.log("added record with id " + id);
list.$indexFor(id); // returns location in the array
});
So $add() returns a promise that is fulfilled when the item has been added to Firebase. With that knowledge you can add a same-named child to the other list:
var queue = new Firebase('my-firebase.firebaseio.com/queue');
$scope.save = function() {
Service1.$add({name: "test1"}).then(function(ref) {
queue.child(ref.key().set({name: "test1"});
});
}
This last snippet uses a regular Firebase reference. Since AngularFire builds on top of the Firebase JavaScript SDK, they work perfectly together. In fact: unless you're binding these $firebaseArrays to the $scope, you're better off not using AngularFire for them:
var items = new Firebase('my-firebase.firebaseio.com/items');
var queue = new Firebase('my-firebase.firebaseio.com/queue');
$scope.save = function() {
var ref = queue.push();
ref.set({name: "test1"})
queue.child(ref.key().set({name: "test1"});
}
To my eyes this is much easier to read, because we're skipping a layer that wasn't being used. Even if somewhere else in your code, you're binding a $firebaseArray() or $firebaseObject() to the same data, they'll update in real-time there too.
Frank's answer is authoritative. One additional thought here is that AngularFire is extremely extensible.
If you want data pushed to two paths, you could simply override the $add method and apply the update to the second path at the same time:
app.factory('DoubleTap', function($firebaseArray, $q) {
var theOtherPath = new Firebase(...);
return $firebaseArray.$extend({
$add: function(recordOrItem) {
var self = this;
return $firebaseArray.prototype.$add.apply(this, arguments).then(function(ref) {
var rec = self.$getRecord(ref.key());
var otherData = ...do something with record here...;
return $q(function(resolve, reject) {
theOtherPath.push(rec.$id).set(otherData);
});
});
}
});
});

Meteor run a function when a mongo collection gets updated

I am trying to do a simple prototype using Meteor (I am very new to Meteor).
I have the following in an isClient block
Template.imageList.helpers({
images: function() {
return Images.find({});
},
}
);
Then for quick demo purposes I am inserting data with meteor mongo and the following
db.images.insert({ imgSrc: "http://mysite/img1.png", createdAt: new Date() })
This works and I can see the change reflected on the ui but I need to also run a client side javascript function when this occurs. I have been trying things like pub/sub and Tracker but can't get anything to work.
Any guidance would be great.
Using meteor-collections-hooks its the more easy way to accomplish this.
meteor add matb33:collection-hooks
For example.
Images = new Mongo.Collection('Images')
example = function(){
console.log("updated")
}
if (Meteor.isClient) {
Images.before.update(function(userId, doc, fieldNames, modifier, options){
example();
})
}
the example() function will run each time the Images collection get updated.
Use observeChanges :
Images.find().observeChanges({
added: function (id, fields) {
runFunction();
},
changed: function (id, fields) {
runFunction();
},
removed: function (id) {
runFunction();
}
});
See here for more: http://docs.meteor.com/#/full/observe_changes
Run function on the client's template helper, like:
Template.imageList.helpers({
images: function() {
imgs = Images.find({});
yourFunction();
return images;
}
});
Or use Tracker.autorun wrapper:
Tracker.autorun(
Images.find({});
yourFunction();
)

Using Imagemagick with a file from a mongo collection

I'm building a simple database for small pixel-art files. The images are saved directly to the database:
Template.pixUpload.events({
'change .myPixInput': function(event, template) {
event.preventDefault();
var file = event.target.files[0]; //assuming 1 file only
if (!file) return;
var reader = new FileReader();
reader.onload = function(event){
MyPix.insert({
binary: reader.result,
createdAt: new Date
});
}
reader.readAsDataURL(file);
}
})
The idea is to be able to modify the images on their way back to the browser, scale them on the fly (if things don't get too slow). So I'm trying to read the image from the db, and scale it with Imagemagick, before displaying it. It doesn't work – and I can't find anything helpful I would be able to understand:
Template.pixList.helpers({
'thumbnail': function() {
var bin = this.binary;
var thumb = new FileReader();
Imagemagick.convert(['bin', '-filter', 'point', '64x64', 'thumb']);
return thumb;
}
})
im using GM Package Right now, take a look at full repo here
First Install All FSCollecton Packages.
GridFS (Because you say you want to store the file inside MongodB).
Graphicsmagick meteor add cvs:graphicsmagick
Second Declare collections on /lib/collection.js
kaiStackExample = new FS.Collection("kaiStackExample ", {
stores: [new FS.Store.GridFS("kaiStackExample ",{
beforeWrite:function(fileObj){
return {
extension: 'png',
type: 'image/png'
};
},
transformWrite:function(fileObj, readStream, writeStream){
// Here you can choose, for example 10x10 (thumbnail), etc.
gm(readStream).resize(600).stream('PNG').pipe(writeStream);
}
})]
});
and our basic Subscribe, on the same /lib/collection.js
if(Meteor.isClient) {
Meteor.subscribe('kaiStackExample');
}
Ok, at this point we have the GridFS and GM, to verify both
server console.
=> GraphicsMagick found
Client console.
kaiStackExample.find().fetch();
should return [];
Third SECURITY
kaiStackExample.allow({
insert:function(userId,doc){
//here we can do stuff like, only permit user with accounts insert on the collection
if(!Meteor.userId()){
return false;
}else{
return true
},
update:function(userId,doc){
if(userId === doc.authorId{
return true;
}else{
return false; // if user don't own the document can update it.
}
}
});
Four Template and Events
HTML markup
<template name="exampleKai">
Select File
<input type="file" id="fileExampleKai">
<button type="submit" id="buttonExampleKai">Click to upload</button>
</template>
Js Code
Template.exampleKai.events({
'click #buttonExampleKai':function(event,template){
event.preventDefault();
var file = $('#fileExampleKai').get(0).files[0];
fsFile = new FS.File(file);
fsFile.metadata = {
coolMetadata:"Yes You can add some metadata too"
}
if(file === undefined){
alert("Please upload a file to continue")
}else{
kaiStackExample.insert(fsFile,function(err,succes){
if(err){
console.log(err.reason);
}else{
console.log("ok we insert yeaaa")
}
});
}
}
});
Like i say this works for me, and i think its your best option for editing size,type,etc Take a look hope it help you
Even though Meteor is very good at keeping the client and server environments in sync, that doesn't mean it can do everything on the client that it can do on the server and vice versa. Converting images using ImageMagick would be one example of what you can only do on the server.
If I were to build something like this, I'd look into using CollectionFS for syncing files. They also have a section in the README that describes how to manipulate images before saving them, which seems to be just what you're after.

Can I publish only Collections object in meteor?

On the introducing article of DDP, I read that anything can be published, but I've read somewhere ( for example in this Stackoverflow comment Publish arbitrary data and automatically update HTML ) that only Collections can be published.
So where is the truth? If we can publish other things than Collections, I would liek to see an example as I can't find one so far.
From the docs: http://docs.meteor.com/#meteor_publish
Publish functions can return a Collection.Cursor, in which case Meteor will publish that cursor's documents. You can also return an array of Collection.Cursors, in which case Meteor will publish all of the cursors.
So at the moment you can only return a Collection via a cursor (result of a Collection.find()).
To return other data you need to hack into the sockjs stream (the socket library meteor uses to communicate to the server). Be aware this does not guarantee compatibility with future versions of meteor. Sockjs is the library used for meteor to communicate between the server (the wire)
from Publish arbitrary data and automatically update HTML*
client side js
sc = new Meteor._Stream('/sockjs');
sc.on('message', function(payload) {
var msg = JSON.parse(payload);
Session.set('a_random_message', JSON.stringify(msg.data));
});
Template.hello.greeting = function () {
return Session.get('a_random_message');
};
server side js
ss = new Meteor._StreamServer();
ss.register(function (socket) {
var data = {socket: socket.id, connected: new Date()}
var msg = {msg: 'data', data: data};
// Send message to all sockets (which will be set in the Session a_random_message of the client
_.each(ss.all_sockets(), function(socket) {
socket.send(JSON.stringify(msg));
});
});
You can also look at Meteor Streams too. See below.
assume you have added meteor streams via atmosphere - mrt add streams
sc = new Meteor.Stream('hello');
if(Meteor.isServer) {
Meteor.setInterval(function() {
sc.emit('a_random_message', 'Random Message: ' + Random.id());
}, 2000);
Meteor.permissions.read(function() { return true });
}
if(Meteor.isClient) {
sc.on('a_random_message', function(message) {
Session.set('a_random_message', message);
});
Template.hello.greeting = function () {
return Session.get('a_random_message');
};
}

Resources