How do I make paper.js work in Meteor?

After doing: meteor add marcinn:paperjs.

It generates an error because Path is not defined (the paperjs Path() function in framePreview.js)

What is missing (paper.js is present in packages and package list file)

here is my test:

    ---tsite01.html (stands for test site 01)

<head>
<title>tsite01</title>
<!-- Load the Paper.js library--> 
<script type="text/paperscript" src="papers/framePreview.js" canvas="framePreview"> </script>
</head>

<body>
  <h1>Hello World!</h1>
  {{> hello}}   
  <canvas id="framePreview" resize></canvas>
</body>


<template name="hello">
  <button>Click here</button>
  <p>You've pressed the bouton {{counter}} times.</p>
</template>

--- framePreview.js  in papers subdirectory

var path=new Path();
path.strokeColor='black';
var start= new Point(100,100);
path.moveTo(start);
path.lineTo(start+[10,-50]);

-- tsite.js

if (Meteor.isClient) {
  // counter starts at 0
  Session.setDefault('counter', 0);

  Template.hello.helpers({
    counter: function () {
      return Session.get('counter');
    }
  });

  Template.hello.events({
    'click button': function () {
      // increment the counter when button is clicked
      Session.set('counter', Session.get('counter') + 1);
    }
  });
}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}

i think you should move this block

var path=new Path();
path.strokeColor='black';
var start= new Point(100,100);
path.moveTo(start);
path.lineTo(start+[10,-50]);

in Meteor.isClient

Move your code into a client block or client file as @mrphu3074 says first.

Then you’ll need to swap out to using js directly to instantiate and setup the canvas as described here: http://paperjs.org/tutorials/getting-started/using-javascript-directly/

It does not work. (see code billow).
I do not declare a paper.js file because I have the package installed. If I should flush the packageand declare the paper.js I downloaded, there are many files. Beside example and css folders, should I keep only the one named paper.js in the paperjs-v0.9.23/doc/assets/js ?

<head>
<title>tsite01</title>
<!-- Load the Paper.js library:  NO because package in Meteor JS--> 
<script type="text/javascript"> 
    window.onload = function() {
        // Get a reference to the canvas object
        var canvas = document.getElementById('framePreview');
        // Create an empty project and a view for the canvas:
        paper.setup(canvas);
        // Create a Paper.js Path to draw a line into it:
        var path = new paper.Path();
        // Give the stroke a color
        path.strokeColor = 'black';
        var start = new paper.Point(100, 100);
        // Move to start and draw a line from there
        path.moveTo(start);
        // Note that the plus operator on Point objects does not work
        // in JavaScript. Instead, we need to call the add() function:
        path.lineTo(start.add([ 200, -50 ]));
        // Draw the view now:
        paper.view.draw();
    }

</script>
</head>

<body>
  <h1>Hello World!</h1>
  {{> hello}}    
  <canvas id="framePreview" resize></canvas>
</body>


<template name="hello">
  <button>Click here</button>
  <p>You've pressed the button {{counter}} times.</p>
</template>

Stick with the package for now.

Load your apps index and pop open the browser console (CTRL + SHIFT + J) on chrome.

See if paper is in available by typing paper. This will double check the library is loaded correctly. You shouldn’t get undefined.

Then your problem actually occurs with where the script is. The javascript you have is running before the canvas is loaded.

I’d place the canvas into a template:

<template name="canvas">
<canvas id="framePreview" resize></canvas>
</template>

Then include that in the body:

{{> canvas}}

Then you can use template events to be trigger the js at a more apropriate time:

Template.canvas.onRendered(function() {
 // Get a reference to the canvas object
        var canvas = document.getElementById('framePreview');
        // Create an empty project and a view for the canvas:
        paper.setup(canvas);
        // Create a Paper.js Path to draw a line into it:
        var path = new paper.Path();
        // Give the stroke a color
        path.strokeColor = 'black';
        var start = new paper.Point(100, 100);
        // Move to start and draw a line from there
        path.moveTo(start);
        // Note that the plus operator on Point objects does not work
        // in JavaScript. Instead, we need to call the add() function:
        path.lineTo(start.add([ 200, -50 ]));
        // Draw the view now:
        paper.view.draw();
});

Then you’ll be sure the canvas is only initialized when it actually exists. You can double check DOM load order is the problem by putting:

console.log(document.getElementById('framePreview'));

inside your onload block as it stands, you should see undefined because its still loading the page.

1 Like

Your tip about consol brought me to the list of packages. When I click the source for that package, it says: //Write your package code here! Does it mean my package is empty? I like the rest of your solution because in other words it says: do it the Meteor way and it should be simpler and fine! It solves the 2 ideas of the right call time and in a file for not crowding a markup listing.

But for now, maybe, I need a paper.js package that work. There is more than on in Atmosphere. Any idea of one that works? Thanks for your fast replies, all those involved in this thread.

Which paperjs package are you using?

maddymaxey:paperjs should work, i reviewed its package.js contents and it seems like its doing the correct things.

https://atmospherejs.com/marcinn/paperjs has no source so i can’t determine its contents I would use maddymaxey instead.

Ya, I wish to use this one. But I posted an issue in its GitHub because I do not understand very well how to use it.

Maybe you could answer some. Have you tried it?

Its a regular package you shouldnt need to clone anything.

Let me try some stuff.

EDIT:

The paper variable isn’t being exported to the global scope and is getting tied up in the meteor packaging. :frowning:

Meteor packages up files from packages and wraps them in an IIFE, nothing ever gets exported back to the global.

I would say follow my advise above about templates and using onRendered but include within the paperjs library as the “core” version: http://cdnjs.cloudflare.com/ajax/libs/paper.js/0.9.23/paper-core.min.js.

Here’s a full example where I’ve got the line from your above code rendering: https://github.com/rfox90/paperjs-example

@emhmark7

Thanks for bearing with me!

but include within the paperjs library as the “core” version
Q1) How Do I do it?

But in my beginners understanding, the advantage of making a package is to scope variables to a limited package code.
I wish to maintain these variables and objects during the app execution and wish also to use several canvas.
Q2) How are variable maintained persistant between calls?
Q3) I supose, onRendered is called everytime there is a change in the DOM. But if I need to call functions from buttons or mouse, I will need to write/rewrite code in helpers and events. How can they act on the same objects? Will they be interpreted correctly for paper.js functions? Not sure a understand what scoping will be visible and affected.
(for my POV, on scoping, paper.js documentation is not easy to understand)

In your example, you declare the library as a script in the HTML. (OK for question 1)

  1. Client packages usually just expose stuff to the global window object anyway. For example the jquery package exposes $ so you can use it anywhere.
  2. paper is a global variable and should be accessible anywhere on the client now. In that template code we’ve also bound the paper object to that canvas. So you should be able to draw lines from any other piece of code and have it appear on that same canvas.
  3. Again sure, paper is global just call it when you need to.

I spose it’ll b easier for further guidance if i knew what you were trying to achive with your paper js drawings but feel free to just have a go!

First, thanks, it works now.
Beside an error in the console:
“The connection to ws://localhost:3000/sockjs/255/i5wb1s_q/websocket was interrupted while the page was loading”

(No idea where it comes from)

I will just have a design interface where there will be about 3 canvas zones and button icons. Of the 3 canvas, 2 will be used interactively (drawing, selecting points and curves)

I suppose the bounding of paper object and the canvas is done at:

if (Meteor.isClient) {
Template.previewFrame.onRendered(function(){
var canvas = document.getElementById('previewFrame');
paper.setup(canvas);

I will experiment and see if I can use the global paper for drawing in another canvas than the one I was in for triggering the action.

Thanks again, you have put me on my way, on the road again!

Q1) Paper.js doc is not clear on how we can change of drawing context and from what I tried, I am not sure it keeps record of drawing objects. So, maybe it means we need to rebuild the whole drawing and its paths at every call. Am I right on that?

Q2) Maybe it gives some advantages to keep each canvas in its template, maybe it keeps its specific data context linked to it, especially specific code. But how in Meteor can we call from a template’s code the code of another template (so here that it could draw in its canvas)?

My actual code is:

TSITE01.HTML:

<head>
<title>tsite01</title>
<!-- Load the Paper.js library:  NO because package in Meteor JS--> 
<script src="//cdnjs.cloudflare.com/ajax/libs/paper.js/0.9.23/paper-core.min.js"></script>

</head>

<body>
  <h1>Hello World!</h1>
  {{> hello}}  
  {{> previewTPL}}
  {{> pieTPL}}
</body>

<template name="hello">
  <button>Click here</button>
  <p>You've pressed the button {{counter}} times.</p>
</template>

<template name="previewTPL">
    <canvas id="previewCAN" width="200" height="200" style="border:1px solid #000000;"></canvas>
</template>

<template name="pieTPL">
    <canvas id="pieCAN" width="200" height="200" style="border:1px solid #000000;"></canvas>
</template>

DESIGN.JS

if (Meteor.isClient) {
Template.previewTPL.onRendered(function(){
    var canvas = document.getElementById('previewCAN');
    paper.setup(canvas);

    var path2 = new paper.Path(); path2.strokeColor = 'red';
    var start2 = new paper.Point(10, 0);
    path2.moveTo(start2); path2.lineTo(start2.add([ 100, 100 ]));
    paper.view.draw();

}) // onRendered

Template.pieTPL.onRendered(function(){
    var canvas = document.getElementById('pieCAN');
    paper.setup(canvas);

    var path = new paper.Path(); path.strokeColor = 'green';
    var start = new paper.Point(0, 0);
    path.moveTo(start); path.lineTo(start.add([ 50, 50 ]));
    paper.view.draw();

}) // onRendered

Template.pieTPL.events({
    'click' : function(e) {
        Session.set('counter', Session.get('counter') + 1);
        paper.view.draw();
       // paper.path.moveTo(start); path.lineTo(start.add([ 50, 50 ]));
        //paper.get('previewFrame').path.rotate(3);
    }  // click
}); // events
}  // is client

TSITE01.JS:

if (Meteor.isClient) {
  // counter starts at 0
  Session.setDefault('counter', 0);

  Template.hello.helpers({
    counter: function () {
      return Session.get('counter');
    }
  });

  Template.hello.events({
    'click button': function () {
      // increment the counter when button is clicked
      Session.set('counter', Session.get('counter') + 1);
    }
  });
}

You’ll need multiple PaperScopes as discussed here: http://paperjs.org/reference/paperscope/

Each one bound to its own canvas.

I read and re-read the doc and I cannot figure out how to do it and syntax. The object hierarchy is really crowded.

In other words, How do we make the paper global object point to another path list and canvas?
(to another active object list and view)

You need multiple papers.

Let me try some stuff for you.

Here you go: https://github.com/rfox90/paperjs-example updated with two lines, one is red!

@emhmark7

1 Like

Ya, I have been able to reach that by reading code from other answers in the paper.js mailing list. Thanks for your effort, it looks like what I am doing. Among the most puzzling BUT necessary elements now are:

  1. If I refresh or re-render the page, paper.js objects could (I suppose) be lost. If not, it could generate duplicate initialized paths but assigned to the same variable, loosing pointer to the previous data.
    So how people using paper.js manage that? Where would be the best place to initialize paths? And most straight forward way of saving it (if code available)?

  2. When we call varName=new path(…) or new point(…), does it create an object that remains in memory even if varName is cleared from memory because was a local variable?

  3. (not a question) I have sticked to meteor events, not those of paper.js. (it was not working - maybe in conflict) but maybe I will retry them once the rest works) This is my first Meteor JS coding ever. I can say that not much lines of code is needed! : )
    For getting mouse coordinates, I do use JQuery-UI:
    var pt = new paper.Point(e.pageX-220,e.pageY-164);
    where 220 and 164 are canvas position, e the event.