27 juin 2015

PDF your collections, client side

Introduction

There are many ways to produce PDF on a website. You can use server side solutions for creating PDF, create CSS styles for print (and cross your finger waiting that all browser vendors will implement it) or create PDF on the client side. The two last solutions having the advantage not to take too much CPU on your infrastructure.

Leveraging PDFKit and SimpleSchema

PDFKit provides an almost complete isomorphic solution for that. It allows you to choose where you want to implement your PDF creation. Very nice. Unfortunately (or not), it only comes with low drawing primitives and for creating your PDF you will need some serious work on it.

When creating templates and forms for our collections, most of us are relying on Autoform. This solution is so nice that we tend to forget how incredible the amount of work this solution is doing for us. We just create a SimpleSchema of our collection and now we can display them, fill them, check the integrity of data provided by our users, and so forth. An incredibly productive package suite.

What if we could do the same for our PDF? That's what I was needing for a client. A solution that could take collections and create PDF out of them.

PDF Renderer

I've outsourced this solution in a package called pierreeric:pdfrenderer. Let's see a simple example on how to use it.

First, we start creating our classic collection with a SimpleSchema. We tag the fields that we want to see in our PDF using a simple pdf: true attribute:
CustomerSchema = new SimpleSchema
  name:
    type: String
    label: TAPi18n.__ 'name'
  images:
    type: String
    label: TAPi18n.__ 'images'
    optional: true
    autoform: afFieldInput:
      type: 'fileUpload'
      collection: 'Images'
  address:
    type: Object
    label: TAPi18n.__ 'address'
  'address.street':
    type: String
    label: TAPi18n.__ 'street'
    pdf: true
  'address.city':
    type: String
    label: TAPi18n.__ 'city'
    pdf: true

Customers = new Mongo.Collection 'customers'
Customers.attachSchema CustomerSchema

if Meteor.isServer
  if Customers.find().count() is 0
    Customers.insert
      name: 'Mathilde Charpentier'
      address:
        street: '227, rue Camille de Richelieu'
        city: 'Strasbourg'
  Meteor.publish 'customers', -> Customers.find()

if Meteor.isClient
  Template.svgTest.onCreated ->
    sub = @subscribe 'customers'
    @autorun =>
      if sub.ready()
        @customer = Customers.findOne()
  Template.svgTest.helpers
    customer: -> Template.instance().customer
Now for creating the PDF when the user click on a button, we can pass to the PdfRenderer some fields or the complete collection:
if Meteor.isClient
  Template.svgTest.events
    'click button': (e, t) ->
      # Create the initial PDF document
      pdf = new PdfRenderer size: 'a4'
      # Load all required assets
      pdf.addAsset "/cfs/files/images/#{t.customer.images}" if t.customer.images
      # Use reactivity for loading assets if any
      t.autorun ->
        if pdf.ready()
          # Customer image if exists
          if t.customer.images?
            pdf.img "/cfs/files/images/#{t.customer.images}", 'RIGHT',
              width: 100
          # Customer's name
          pdf.h1 t.customer.name
          # Address of customer
          pdf.h2 TAPi18n.__ 'address'
          pdf.schema CustomerSchema, 'address', t.customer
          # End the PDF document, display it and enable back the PDF button
          pdf.finish "file-#{t.customer.name}.pdf", ->
            console.log 'PDF finished'
You can see a rendered PDF in the Github repository.

Conclusion

This example is pretty simple. It could be enhance with theming and templating. Coupled with a CMS like Orion, this could be an interesting block for covering e-commerce solution with automatic catalogue creation, web magazines with press capabilities, bookkeeping with automatic invoices generation, ... Hope you will like it and share your contributions on this little package. Happy coding.

25 mai 2015

The Best Meteor IDE

George McKnight shows us how to install Atom for Meteor development.



Thanks George for talking about our little plugins.

5 mai 2015

Meteor Ottawa and Ottawa Famo.us Meetup

Gadi grants us with a nice intro on using Meteor and Famo.us. Tutorial inside! Thank Gadi and thank to Ottawa's community.

19 avr. 2015

Fullscreen D3 graphs

What are we going to tackle?

When creating D3 graphs, the more graphs you put in your page, the less readable it tends to be. A friend of mine advise me to set my graphs in fullscreen. I immediately loved the idea. That would definitely help users to focus.

What do we need to solve?

  1. Our graphs need to be responsive: when they will be toggled on fullscreen, they need to expand and take as much space as possible.
  2. When setting up fullscreen, the viewport is black despite all your already setup styles.
  3. Tooltips on your graphs needs to be included in the fullscreen's viewport.
  4. As your viewport is changing so are the references on where your tooltips needs to be displayed.

Piece by piece solution

First, let's setup our markup in Jade. figure is our SVG container, the div, .svg-content, is where D3 will place our SVG content and the div, .tip, is our tooltip for this graph:
figure
  .svg-content
    .tip
      span Point
      .arrow
Now, we need to setup our style so that our SVG content takes the available width of its container or the width of the viewport when it will be set on fullscreen. Note that we also need to set the background color of the container so that we don't end up with a black viewport. Here is the relevant extract of the Sylus file:
// Container for responsive SVG
// Mixin for creating SVG container with specific aspect ratio
svgContainer()
  display inline-block
  position relative
  width 100%
  vertical-align middle
  overflow hidden

figure
  display inline-block
  absolute top left
  height 100%
  margin 0
  // This container targets 1:1 SVG
  svgContainer()

  .svg-content
    // Here are the properties for the fullscreen content
    &:fullscreen
      size 100%
      background white
For the tooltip, we use a fixed position that will be modified using our logic. The style is pretty straightforward in Stylus:
.tip
  fixed top left
Now, for creating a responsive D3 graph, we need to use the preserveAspectRatio and the viewBox attributes on the graph instead of the regular width and height on the SVG tag. This is what is done by the following logic in Coffee on a 100x100 graph:
svgWidth = svgHeight = 100
svg = d3.select '.svg-content'
  .append 'svg:svg'
    .attr 'preserveAspectRatio', 'xMinYMin meet'
    .attr 'viewBox', "0 0 #{svgWidth} #{svgHeight}"
Setting the graph in fullscreen is eased thanks to screenfull.js. This library provide a cross browser API of the vanilla JavaScript Fullscreen API:
Template.home.rendered = ->
  @fullscreen = ->
    return screenfull.exit() if screenfull.isFullscreen
    target = (@$ '.svg-content')[0]
    screenfull.request target

Template.home.events
  'click button': (e, t) ->
    $button = t.$ e.target
    role = $button.attr 'data-role'
    t.fullscreen() if role is 'fullscreen'
Now, we need to adjust the tooltips so that they are positioned properly. In our example, we are using a Voronoï diagram. Hovering on the path elements of the Voronoï is triggering the tooltip of its points modeled by circle elements. Getting the position is achieved thank to the DOM API getBoundingClientRect:
  tip = @$ '.tip'
  @positionSetTip = (circle) ->
    rect = circle[0].getBoundingClientRect()
    tip.css 'transform', "translate3d(\
      #{rect.left + .5 * (rect.width - tip.width())}px,\
      #{rect.top - tip.height()}px, 0)"
  @showHideTip = -> tip.toggleClass 'show'
  @showTip = -> Meteor.setTimeout (-> tip.addClass 'show'), 300
  # A debouncing function is used for transitioning over path
  @lazyShowHideTip = _.debounce @showHideTip, 300
  path = svg.append 'g'
    .selectAll 'path'
  svg.append 'g'
    .selectAll 'circle'
    .data vertice
    .enter()
    .append 'circle'
      .attr 'transform', (d) -> "translate(#{d.toString()})"
      .attr 'r', 1
  data = path.data (voronoi vertice)
  data
    .enter()
    .append 'path'
      .attr 'd', polygon
      .order()
      .on 'mouseover', (d, i) =>
        circle = $ "circle:nth-child(#{i + 1})"
        @positionSetTip circle, i
        @showTip()
      .on 'mouseleave', =>
        @lazyShowHideTip()
  data.exit().remove()

Some links

Bonus

On the demo, I've also added some features like:
  • An animated tooltip: when entering or leaving a small animation is done.
  • The Voronoï graph is animated using a simple random function.
  • Key events are handle to let you set the graph in fullscreen or to animate it.
Happy coding!


29 déc. 2014

Access all famo.us examples without downloading the starter kit

One neat trick that we have used on famous-views to set some links to famo.us examples is to use rawgit. A nice service that allow exposing a Github page. Simply choose an index.html file from  Github and make it available using rawgit. Here is the link created for famo.us examples: http://rawgit.com/Famous/famous/master/examples/index.html.

28 déc. 2014

Debugging server side REST calls with mitmproxy in Meteor

Introduction

Isomorphic javascript offers a great flexibility for developper letting them choose where the code will get executed. On the clients or on the servers. While the Chrome DevTools have evolved at an impressive pace allowing to easily debug and see what is going on with your client's REST calls, the state of server side debugging may be a little bit deceptive in this field. Hence, when you need to put data fetching within your server, checking the flows of requests / responses could be a bit cumbersome if you solely rely on transaction logs or node-inspector. You could use technics like packet sniffing using Wireshark but setting a proper environment when using TLS with your REST call is a huge configuration process.

This is where mitmproxy comes to the rescue. Its name says it all: Man In The Middle PROXY. This incredible tool relies on the same technics as the infamous security attack, this time, for a greater purpose. For this article, I'm using mitmproxy as a local proxy server allowing me to trace all outgoing and incoming transactions from my server side Meteor app. Note that it is not the only use case that mitmproxy offers. Actually, this tool is incredibly agile allowing you to debug your mobile apps with great ease. Let us put our white hat on.

Installation on OSX

Using homebrew for installing mitmproxy is a one command line call:
brew install mitmproxy
Note that this steps actually installs 2 tools mitmproxy and mitmdump as well as a set of certificates in ~/.mitmproxy. We only use the first tool in this article but the second one could be handy when you need a lightweight display of your transaction flow and an easy way to save them in a replayable log. Note also that if you also intend to use mitmproxy for debugging other applications like native client ones, you can accept the certificate ~/.mitmproxy/mitmproxy-ca-cert.pemcertificate in OSX that mitmproxy has created just for you. Just a caveat here. When you set your proxy settings in OSX, be sure to remove the local filters that Apple gently put for you if you want to see your native apps talking to your local servers.

Here's a little screenshot of a debugging session using mitmproxy:

Not that isomorphic

For REST calls, Meteor comes with its own isomorphic library: HTTP. On the client, it acts as basic AJAX calls, while on the server, it relies on the request module. Like all isomorphic libraries, this allows you to put your code logic in your clients or in your server with a nice and uniform API. But this comes at a price, it only covers the features that makes sense for both the clients and the server.

A server is not a browser. Indeed, while having cookies on the browser make sense for retaining states in your application for each user, cookies on the server starts to be a weird concept. Are these cookies used for the clients that you will serve or should the server could be seen as a client to another server? The same goes for the proxy settings on a server. Why would you need a proxy on a production server? Therefore, what is available on the client side of your app may not be available on the server side. 

Unfortunately, you could have use cases where the REST API that you are using within your server may need cookies (which is a bit weird when speaking of REpresentational State Transfer which should rely on state-less operations ☺).  Additionally, for debugging our flows, we also need the proxy capabilities that are offered out of the box by our browsers. This is where comes the nice package http-more from dandv. It exposes some already baked in feature of the request module for your server side REST calls.

You install it by replacing Meteor's default package like so:
meteor remove http
meteor add dandv:http-more

Proxyfy your REST calls in your server

Now that our toolbox is setup, it is time to orient our server so that it takes advantages of mitmproxy. This is achieved via the freshly exposed options in the HTTP library.

For orienting your request to the proxy, play nice with your TLS layer and setting a cookie jar:
HTTP.get url,
  proxy: 'http://127.0.0.1:8080'
  strictSSL: false
  jar: true
, (e, r) ->
  console.log 'GET sent through the proxy :-)'
Now, you should see all your flows of your server on mitmproxy.

Some nice mitmproxy shortcuts and moves

mitmproxy's documentation is clear and very helpful. But before let you dive in, I'm sharing some of my most used shortcuts:
  • C to clear the list of flows.
  • and for selecting a flow.
  • for seeing the details of an exchange and q to go back to the list.
  • in detail of a flow to switch between the request and the response.
When you need to save a mitmproxy session for comparing it with other ones, you can use the save feature:
mitmproxy -w FILENAME

Once saved, you can reread it and modify it to only spare the relevant parts of your flows:
mitmproxy -nr FILENAME
Where:
  • n prevents to launch a proxy server.
  • r read the previous saved file.
For the editing your flows, use the following shortcuts:
  • d for deleting flows.
  • e for editing a request or a response.
  • w then a for saving your all your modifications of the flows for the session.
  • q then y for quitting edition mode.
Another nice move is mitmproxy's capabilities to replay a session. For instance, you can replay the client part of your spared session or the server part just by specifying -c or -s respectively. Very handy for debugging without assaulting the REST service that your implementing or using:
mitmproxy -c FILENAME

14 déc. 2014

Put your HTML, CSS and JS in a single file using Meteor

It could be a bit cumbersome to switch from your HTML template file to your JS logic to your CSS stylesheets. I consider that the method exposed hereafter isn't tailored for novice users. Still, it can help you understanding how Meteor works.

Actually, the method is quite simple. It all drills down to how the HTML files are generated using Blaze, the reactive UI. During the build process of your app, Meteor builds JS file out of your HTML template file and exposes / sends them to your clients. This method short-circuits the build process. If you write directly your HTML using Blaze, the reactive UI, you remove the HTML file. The second step is to use JS to write your CSS. Here, I use the CSSC package for Meteor.

Here is the results for an equivalent of the default Meteor  app.
You could think of it as a small component into a larger app.

And now, here is the code to create this small component. As promised, a single file, in CoffeeScript for brevity:
# Render the body when Meteor is ready
Meteor.startup Template.body.renderToDocument

# HTML
# ----
# Instantiate a main template
Template['main'] = new Template 'Template.main', ->
  # Return a table of DOM elements
  [
    # A 'p' tag with a reactive variable
    HTML.P 'Count ', Blaze.View => Spacebars.mustache @lookup 'count'
    # A 'button' tag
    HTML.BUTTON '+1'
  ]

# JS logic
# --------
# Declare a reactive variable
Session.set 'count', 0
# Expose the reactive variable to the template
Template.main.helpers 'count': -> Session.get 'count'
# Handle template events
Template.main.events
  'click button': (e,t) ->
    e.preventDefault()
    Session.set 'count', 1 + Session.get 'count'
# Add the template to the document's body
Template.body.addContent ->
  Spacebars.include @lookupTemplate 'main'

# CSS
# ---
# Instantiate a stylesheet
css = new CSSC
# Style the body and the text
css.add 'body',
  margin: CSSC.px 20
  backgroundColor: CSSC.navy
  color: CSSC.aqua
# Style the button
.add 'button',
  width: CSSC.px 50
  border: "#{CSSC.px 1} #{CSSC.maroon} solid"
  borderRadius: CSSC.px 3
  backgroundColor: CSSC.red
  color: CSSC.yellow

If you want to test it yourself, here is the set of required commands:
# Start by creating a simple app.
meteor create singlefile
cd singlefile
# Remove the Meteor's default app.
rm *
# We are going to focus only on the front.
# Our single file is being placed in the client directory.
mkdir client
# Add the necessary packages.
meteor add coffeescript pierreeric:cssc pierreeric:cssc-colors pierreeric:cssc-normalize
# Create your single file and start editing it.
touch client/main.coffee

At the beginning, it may look a bit weird. But this could be useful from time to time. Note that you can put some nice additions to this sample. For instance, instead of using the events helpers which will scan you DOM for the button, you could directly affect the click event logic when you are creating the button element. If you are looking for performances on some parts of your app, this could be an interesting technic.