简体   繁体   中英

Meteor: How to Perform Calculations Client-Side on Mongo Data

In my Meteor app, I've successfully published data server-side and subscribed to that data client-side. Now, rather than pushing raw data straight to the client's screen, I want to store it as a javascript object, perform some calculations on it (number crunching), and render the result on the client's screen (within an HTML5 canvas element). Every time Mongo is updated, the javascript code should re-run (ie the js object is re-set, calculations are performed again from that object, and the new results are rendered on the canvas).

I can grab hold of Mongo data using the Template.example.helpers block and show that directly in the client as follows:


Meteor.subscribe('collection','query');

Template.example.helpers({
  sampleData: function(){
    return Collection.findOne({query:`query`});
  }
});

<template name="example">
  <div>
    {{sampleData.last}}
  </div>
  <canvas id="test-canvas"></canvas>
</template>

But what I'm trying to do is grab hold of this data before pushing to the client's screen, within the Template.example.rendered block:

Meteor.subscribe('collection','query');

Template.example.rendered = function(){
  // define HTML5 canvas and context variables
  var canvas = $("#test-canvas")[0];
  var context = canvas.getContext("2d");
  // store Mongo data as Javascript variable
  // loop over this variable and perform calculations
    // draw results to the canvas
}

Am I approaching this the right way? If so, how can I achieve it? Thanks!

在一个单独的对象中存储数据并执行计算,然后从该对象而不是从mongo渲染模板可能会更容易,您可以使用“ Deps”轻松地使模板保持响应状态,这将使您编写更多代码可维护的。

Your approach is good. The key here is to observe collection and update canvas when items in collections are:

  • added(document) or addedAt(document, atIndex, before)
  • removed(oldDocument) or removedAt(oldDocument, atIndex)
  • changed(newDocument, oldDocument) or changedAt(newDocument, oldDocument, atIndex)
  • movedTo(document, fromIndex, toIndex, before)

There is also more performant way to observe changes in collection . Code similar to below should help you:

if (Meteor.isClient) {
  Template.example.rendered = function () {
   var canvas = $("#test-canvas")[0];
   var context = canvas.getContext("2d");
   Collection.find().observe({
      added: function (doc) {              // draw sth on canvas          },
      changed: function (doc) {            // draw sth on canvas          },
      movedTo: function (doc) {            // draw sth on canvas          },
      removed: function (doc) {            // remove sth from canvas      }
    });
  };
}

Example: https://github.com/Slava/d3-meteor-basic

I was able to figure out my own answer to the question posed above. My template was loading before the data was retrieved by the client, therefore I kept getting cannot read property <blank> of undefined in the browser's javascript console and code would interrupt. You need to use the iron-router package in order to

1) set the "data context" of the template you are working on (package up an object containing data sources you need for that specific template), and

2) force the template not to render until the data has been retrieved. Once the data is retrieved, iron-router loads the template and you now have full javascript control of the data object you created above.

Steps at a high-level:

1) Install iron-router

2) Define a route for the template

3) Use the waitOn method to tell iron-router which data source you are subscribing to (which data it is waiting on)

4) Define a "loading" template (aka splash screen) to show while data is being retrieved before template load. As per https://github.com/EventedMind/iron-router/issues/554 , you can achieve this by inserting this block of code in your iron-router router.js file:

Router.onBeforeAction(function(pause) {
  if (!this.ready()) {
    this.render('loading'); // wait
    pause();                // ready
  }
});

Just make sure you create a loading template to go along with this.

5) Use the data method to set the data context for your template (create the data object to be used in the template)

Steps at a detailed-level:

http://www.manuel-schoebel.com/blog/iron-router-tutorial

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM