Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meteor - automatically updating canvas with subscribed data?

Tags:

meteor

I might be missing something, but it seems that Meteor's "magic" revolves around binding data to DOM elements, and updating text and HTML fragments via handlebars: http://docs.meteor.com/#reactivity

This is great, however, when trying to write a meteor app that displays live data in a <canvas> element, I cannot figure out the "meteor way" to update my canvas when the live data changes, since the canvas is populated via JS code like:

var g = canvas.getContext('2d')
g.fillRect(x, y, w, h)

and not data-backed text in the HTML template.

I am trying to draw on the canvas using data from a Meteor.Collection.

My only thought was to embed canvas-drawing JS code in the HTML template in a script tag populated by handlebar vars, but this seems wrong since meteor's events and data-binding code is already client-side JS.

Is there some way listen for live data changes, which triggers drawing on the canvas via JS instead of HTML elements/text?

Please let me know if I can clarify the question in some way

Update: Tom's answer below made me notice Meteor.deps, which look to allow executing arbitrary code in a reactive context: http://docs.meteor.com/#on_invalidate

I will try this out and update here if it works.

like image 555
7zark7 Avatar asked May 29 '12 06:05

7zark7


3 Answers

Perhaps the answer to your question is to use Collection.observe (http://docs.meteor.com/#observe) and trigger the relevant redrawing code in the various callbacks.

For instance, something like:

Rectangles.observe({
  added: function(rect) {
    var g = canvas.getContext('2d');
    g.fillRect(rect.x, rect.y, rect.w, rect.h);
  },
  // etc
})
like image 168
Tom Coleman Avatar answered Sep 22 '22 23:09

Tom Coleman


This works:

var Shapes = new Meteor.Collection('shapes')

if (Meteor.is_client) {
  // Function that redraws the entire canvas from shapes in Meteor.Collection
  function drawShapes() {
    var shapes = Shapes.find({})
    shapes.forEach(function(shape) {
      // draw each on canvas
    })
  }

  var startUpdateListener = function() {
    // Function called each time 'Shapes' is updated.
    var redrawCanvas = function() {
      var context = new Meteor.deps.Context()
      context.on_invalidate(redrawCanvas) // Ensures this is recalled for each update
      context.run(function() {
        drawShapes()
      })
    }
    redrawCanvas()
  }

  Meteor.startup(function() {
    startUpdateListener()
  })
}
like image 21
7zark7 Avatar answered Sep 24 '22 23:09

7zark7


I had some trouble with updating the canvas so I created this simple game demo: https://github.com/randompast/Meteor-SimpleGame

like image 44
randompast Avatar answered Sep 24 '22 23:09

randompast