Yesterday I thought up a fun idea for an app that would help me learn a bit about the media capture APIs available in HTML5. I also wanted to finish an end to end Meteor application as I have only really followed tutorials before or worked on something along with other developers.

I was able to create and launch the app in just over an hour. So you can say hello to Working Wall.

Screenshot of Working Wall Screenshot of Working Wall

I take absolutely no credit for being able to get something up and running this fast, it was all thanks to Meteor and Heroku. I wanted to walk you through my process to show how easy it is.

I am going to assume you have both Meteor installed and a Heroku account, both are free and easy to set up. I don't mention them here purely to keep this post as neat as possible.

Meteor

I created the app with a simple Meteor call, this sets up some really basic boiler plate.

meteor create working-wall

Next up I edited the three files that were created called working-wall.css, working-wall.html, and working-wall.js.

The CSS is for the styling, the HTML is for the templating and the JS is for the actual Mongo workings. Here are my completed HTML and JS files (at the time of writing, there are some bugs to fix and improvements to make that may have happened by the time you read this).

Disclaimer: This isn't production ready code, I haven't put a thought to security or testing, I just wanted something up that I could play with.

working-wall.html



<head>
  <title>Working Wall</title>
</head>

<body>
  <header>
    <h1>Here are some folk working on interesting stuff!</h1>
    <p>Or maybe just some cats&hellip;</p>
    <p>Accept the request to use your camera. Click on your picture to take a snapshot</p>
  </header>
  {{> pictures}}
  <footer>
    Made by <a href="http://twitter.com/tosbourn">Toby</a> | Inspired by <a href="http://www.tiiny.com">Tiiny</a> | <a href="https://github.com/tosbourn/working-wall">Source Code</a>
  </footer>
</body>

<template name="pictures">
  <ul>
    <li class="main-picture">
    <video autoplay height="150px"></video>
    <canvas style="display:none;"></canvas>
    </li>
    {{#each pictures}}
      <li><img src="{{url}}" /></li>
    {{/each}}
  </ul>
</template>

Nothing too exciting, the HTML at the top sets a header and footer and calls the template named pictures. All this template does is set up the "webcam" area and loop through all the pictures displaying them.

Pictures = new Mongo.Collection("pictures");

if (Meteor.isClient) {

 Template.pictures.helpers({
 pictures: function () {
 return Pictures.find({}, {sort: {'date_added': -1}, limit: 50});
 }
 });

 Template.pictures.rendered = function() {
 var video = document.querySelector('video');
 var canvas = document.querySelector('canvas');
 var ctx = canvas.getContext('2d');
 var localMediaStream = null;

 function snapshot() {
 if (localMediaStream) {
 ctx.drawImage(video, 0, 0, 400, 150);
 Pictures.insert({url: canvas.toDataURL('image/png'), date_added: new Date});
 video.src = window.URL.createObjectURL(localMediaStream);
 }
 }

 video.addEventListener('click', snapshot, false);

 navigator.getUserMedia = navigator.getUserMedia ||
 navigator.webkitGetUserMedia ||
 navigator.mozGetUserMedia ||
 navigator.msGetUserMedia;

 navigator.getUserMedia({video: true}, function(stream) {
 video.src = window.URL.createObjectURL(stream);
 localMediaStream = stream;
 }, function(){
 console.log("error getting image");
 });
 }
}

if (Meteor.isServer) {
 Meteor.startup(function () {});
}

This is a little more interesting;

We set up a new collection called Pictures.

Next we check if we are in the client or the server. If we are in the client set up a helper called pictures – this is what we iterate over in the template. It is doing a grab of the latest 50 images sorted descending by date.

This next part is a bit ugly and could definitely be refactored, we are saying when the pictures template is rendered run the following JavaScript, this sets up the browser asking the user to give us access to the webcam and then looks for a click on the video element, once clicked it captures the current frame into a canvas and then converts that into raw png data.

I did experiment with creating webp images, these were a lot smaller but didn't render on every browser.

Meteor handles storing the information with this line;

Pictures.insert({url: canvas.toDataURL('image/png'), date_added: new Date});

That is really all there is to it, Meteor handles creating the Mongo database and handling the collection we have asked for.

Heroku

Getting into Heroku was as simple as setting up a build pack, there are several available but I chose to use meteor-buildpack-horse.git. I wish I could say this was an educated choice, but it was what I know Phil McClure has used in the past and I trust his judgement on all Meteor matters! (sidenote: he has written some great stuff about Meteor on his blog).

I also had to set up a free plan on MongoLab to handle the database, once this was setup the URL can be used by your buildpack to set everything up. Way more simple than I imagined.

Conclusion

This was very much a quick sprint through what I did, I will be expanding some of the points and things in other posts in the future

Why not read some more of our JavaScript posts?