Using Classes with Paper.js?

1,644 views
Skip to first unread message

Kevin C

unread,
Nov 11, 2013, 7:55:11 AM11/11/13
to pap...@googlegroups.com
Hey all,

I'm building a little prototype menu system. Each item has a common look and feel, so looking to collect things together a bit more than just loops, which is all i've done previously. I've looked at Symbols but they don't seem to be what I'm after. The closest thing I want is MovieClips in flash. e.g. an object with attached interactivity and variables, but with common graphics.

Are Javascript classes the best approach for this? I've never used classes in JS before.

I looked at the balls example, but i'm not sure fully what's going on:

Why this for example?

    this.item = new Group({

Is this the best approach, and is there perhaps a more stripped down class example I could take a look at?

Thanks,

Kevin

Kevin C

unread,
Nov 11, 2013, 11:07:42 AM11/11/13
to pap...@googlegroups.com
Ok, replying to my own question here. but might be useful if anyone else is looking for a simple classes/oop example.
I stripped down the Ball example to it's core.

If anyone has any comments on this approach, i'd love to hear it.

Thanks.

var NUM_BOXES = 10;
var boxes = [];

// ............................................... Box Object
var Box = function(x, y) {

var radius = 20;
myPos = new Point(x, y);

// draw item 
var square = new Path.Rectangle({
point: [myPos.x, myPos.y],
size: [50, 50]
});
square.strokeColor = '#ff0000';
square.fillColor = 'blue';
// create paper js group
this.me = new Group();
this.me.addChild(square);
}

// animation
Box.prototype.iterate = function() {
this.me.rotate(1);
}

function setup() {
for (var i = 0; i < NUM_BOXES; i++) {
box = new Box(randomBetween(1,view.viewSize.width), randomBetween(1,view.viewSize.height));
boxes.push(box);
}
}


// animation loop
function onFrame() {
for (var i = 0, l = boxes.length; i < l; i++) {
boxes[i].iterate();
console.log(boxes[i]);
}
}

function randomBetween(from,to) {
    return Math.floor(Math.random()*(to-from+1)+from);
}

setup();

Kevin C

unread,
Nov 11, 2013, 1:45:00 PM11/11/13
to pap...@googlegroups.com
Hi there,

Made some good progress, but hitting some scoping issues when mixing JA classes and PaperJS objects.
Below is some code snippets illustrating the problem. I've tried to join everything, but feel I may be taking the wrong approach.

Has anyone got any pointers for me?

Thanks

Kevin


// ............................................... MenuItem Object

var MenuItem = function(_x, _y, _label) {

var radius = 20;
myPos = new Point(_x, _y);

// draw item 
var square = new Path.Rectangle({
point: [myPos.x, myPos.y],
size: [200, 50]
});
square.fillColor = '#333333';
// create paper js group
this.me = new Group();
this.me.name = _label;
this.me.addChild(square);
this.me.addChild(label);

this.me.onClick = this.click; // Is this the right approach to bind PJS's events to my class? 
}

// Click
MenuItem.prototype.click = function() {
console.log("clicked : " + this);  // output: clicked : Group 'Electricity' - I would like the class to be the scope though, possible?
}

// Select
MenuItem.prototype.select = function() {
console.log("select : " + this.me);
this.me.quare.fillColor = "blue"
}

console.log(menu[0].select);  // This outputs the function's code
menu[0].select; // Doesn't triggering anything


Dylan Fries

unread,
Dec 2, 2013, 5:44:52 PM12/2/13
to pap...@googlegroups.com
Hey Kevin,

I spent most of the weekend fighting with this myself. I found the Tadpole example to be the most "OO" version I could find. I ended up with something like


function NavElement (){
// private instance variables
this.isActive = new Boolean(false);
this.navGroup = new Group(); // subgroup of UI elements
this.navShape = new Path(); // child of navGroup
}

NavElement.prototype = {
constructor: NavElement,

// do function stuff
initialize: function(centerPoint, radius){
     // do stuff
     // add all paths to a group I want to be able to click
     return group;
}
}

for which I have no idea if its the best way of doing things. I would then create new NavElement objects ( in another function), and add them as elements in a navGroup. I then set up callbacks on that 

navGroup.onMouseEnter = function(event){
   
}

the problem was that I wanted a reference to the object when it was clicked and the only way I could find of doing that was to search an array of the objects on every mouseEnter and hitCheck each one (hacky as shit i know).

I hope this helps although I feel like it might just make matters worse. I think the article I used was
http://eloquentjavascript.net/chapter8.html

Hope this helps, although I have my doubts. If anyone else has a better solution I'm all ears.

Dylan

ken frederick

unread,
Dec 3, 2013, 8:09:44 AM12/3/13
to pap...@googlegroups.com
I prefer this method of defining classes in JavaScript using the "Revealing Module Pattern" (http://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript), which also plays well when extending Paper.js classes
Here's how I would define your MenuItem class

// ............................................... MenuItem Object
var MenuItem = Path.extend({
    enumerable: true,    // makes additional methods visible
    _class: 'MenuItem',  // just to keep things straight
    _isSelected: false,  // toggle variable

    // internal initialization function, from Base
    initialize: function MenuItem(arg0, arg1, arg2) {
        var that = this;

        // create button
        this.path = new Path.Rectangle({
            position: arg0 || new Point(0,0),
            size:     arg1 || [200, 50]
        });
        this.path.name = 'background';
        this.path.fillColor = '#333333';

        // create group
        this.me = new Group();
        this.me.name = arg2;
        this.me.addChild( this.path );

        // create label
        this.label = new PointText(this.path.position);
        this.label.fillColor = 'white';
        this.label.content = arg2 || '';
        this.label.justification = 'center';
        this.me.addChild( this.label );

        // define event(s)
        this.path.on('click', function(){
            that._isSelected = !that._isSelected;
            if( that._isSelected ) {
                that.deselect();
            }
            else {
                that.select();
            }
        });

        return this;
    },

    // additional methods
    select: function() {
        this.path.fillColor = 'blue';
    },
    deselect: function() {
        this.path.fillColor = '#333333';
    },

    setLabel: function(label) {
        this.label.content = label;
    }

});

then instantiate your class like this:

var menu = new MenuItem(new Point(100,100), [200, 50], 'My Label');

Ken

Dylan Fries

unread,
Dec 3, 2013, 10:44:56 AM12/3/13
to pap...@googlegroups.com
This looks like an improvement, Thanks!

Jürg Lehni

unread,
Dec 3, 2013, 1:00:15 PM12/3/13
to pap...@googlegroups.com
Is there a reason why you extend Path? This is not really supported at the moment. And inside your class you seem to be creating other Path items, so it doesn't really make sense to subclass Path at the same time.

If you'd like to use Paper.js' internal inheritance structure, then I suggest to subclass from Base, which is provided by the straps.js library, that I'll finally document one of these days:

https://github.com/lehni/straps.js

Best

Jürg
> --
> You received this message because you are subscribed to the Google Groups "Paper.js" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to paperjs+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

ken frederick

unread,
Dec 3, 2013, 1:09:16 PM12/3/13
to pap...@googlegroups.com
Hi Jürg,

you're right, there is no particular reason to use Path in this instance.

So in general the best practice would be to always use extend Base and not the additional classes?

Ken

Jürg Lehni

unread,
Dec 3, 2013, 2:37:16 PM12/3/13
to pap...@googlegroups.com
Well most of the paper.js classes are considered final and are not designed for further subclassing.

But you can subclass Item for developing new items that are part of the DOM, and Group for new items that are to contain children (e.g. Layer extends Group, which extends Item).

Dylan Fries

unread,
Dec 15, 2013, 7:03:34 PM12/15/13
to pap...@googlegroups.com
Hi There,

Thanks for all the help, I think I have it sort of working

var PlotItem = Group.extend({
      initialize: function PlotItem( arg0,arg1 ){
          console.log("New PlotItem");
          return this;
      },
     
      growGrass: function(){
              // I want to count the PlotItems children here
      }
});

being created with

var plot1 = new PlotItem(view.center, 100);

This all seems to work, I can inspect the object created in the console and its extended from Group. I'm trying to figure out if there's a way to access the groups (PlotItem's) children array, specifically from within a function I create. Its probably something obvious but I can't seem to figure it out.

Thanks for your help and your patience, I'm new to Javascript and am finding it somewhat confusing.

Best,

Dylan

Jürg Lehni

unread,
Dec 16, 2013, 8:03:22 AM12/16/13
to pap...@googlegroups.com
You're still not calling the super constructor:

The first line in PlotItem should be:

Group.call(this);

(PlotItem.base.call(this) would also work)

To access the child array, then simply use it how you always do:

var item = new PlotItem();
item.addChild(new Path());
console.log(item.children);
Message has been deleted

Billy Malik

unread,
May 27, 2016, 12:30:56 AM5/27/16
to Paper.js
Hai, maybe this is the right topic for my problem, the idea here is i would like to create class in separate file and the problem is showing when i use some paperjs function inside method of classes
 
class SomeClass(){
     draw
() {
         
var a = new Path.Rectangle(new Point(0, 0), new Size(10, 10);
     
}
}

then i call this class in paperscript file. but they said Uncaught Reference Error: Path is not defined. But using classs without paperjs function inside are working well. How i solve this?

Thanks,

Billy
Message has been deleted

ken frederick

unread,
May 30, 2016, 1:19:23 AM5/30/16
to Paper.js
Hi Billy,

as Jürg mentioned above, paper.js uses a clever system for handling inheritance. Without much context here are two examples of how to instantiate classes within paper.js.

Extending paper.js base class
You can use this method to create your own class based on the paper.js base class.

var myClass = Base.extend({
      initialize
: function myClass(arg0, arg1) {
         
Base.call(this);

          console
.log("New MyClass");
         
return this;
     
},
     
      foo
: function(){
         
// custom function here
     
}
});

You can see Jürg's own example of creating a custom class here.

Ken

Reply all
Reply to author
Forward
0 new messages