recommended way to extend classes in Paper.js
Asked Answered
U

2

8

Is there a recommended way to extend classes in Paper.js? In particular, I am interested in extending Path

Pardon if my terminology is incorrect, but I am essentailly asking the same question about paper that is being asked about three here

Undistinguished answered 25/7, 2013 at 17:37 Comment(3)
How is this dirty work @avall?Finale
I didn't realize I was asking anyone to do the dirty work. please explainUndistinguished
I don't know paperjs well enough to give specific help, but look at their code try to see how they handle the inheritanceFinale
C
5

Based on your comment to the initial version of my answer, you are looking for the 'extend' function (oops, that was exactly what you meant) to do subclassing. In an email to the paper.js mailing list, Jürg Lehni (one of the creators) said:

As for subclassing, that's not something that is supported at the moment. It might work, it might not, it might work in most cases, but not in very rare cases that are hard to pinpoint, it might need only a couple of changes to make it work well, but those might be in many different places.

For example, each Item subclass has a _type property which is a string representing its type. Sometimes we check that instead of using instanceof, because it's faster, and so far, for example for Path we just assumed there would be no subclassing.

A complication is that there are no paper.Path.Rectangle objects. There are paths, and there are rectangles, but when you call new paper.Path.Rectangle() it creates a new Path using initialization code (createRectangle) that creates a rectangular shape.

So we would need to extend paper.Path. Unfortunately, when you call new paper.Path.Rectangle it calls createPath, which always returns a Path (not your extension). It may be possible to do something like:

var SuperRectangle = paper.Path.extend({
    otherFunc: function() {
        console.log('dat');
    }
});

...and with correctly substituting/overriding for createRectangle or createPath get a subclass to work. Unfortunately, I have not been able to manage it.

My first working recommendation is to make a factory and add your functions to the objects in that factory (jsbin here):

  var createSuperRectangle = function(arguments){
    var superRect = new paper.Path.Rectangle(arguments);
    superRect.otherFunc = function(){
      console.log('dat');
    }
    return superRect;
  }
  var aRect = new Rectangle(20, 30, 10, 15);
  var aPath = createSuperRectangle({
    rectangle: aRect,
    strokeColor: 'black'
  });
  aPath.otherFunc();

Similarly, you can use the factory to just change the prototype for your SuperRectangles, having added your functions to that prototype object (and making its prototype the one from paper.Path.__proto__) (jsbin here):

  var superRectProto = function(){};
  var tempRect = new paper.Path.Rectangle();
  tempRect.remove();
  superRectProto.__proto__ = tempRect.__proto__;
  superRectProto.otherFunc = function(){
    console.log('dat');
  }
  delete tempRect;
  var createSuperRectangle = function(arguments){
    var superRect = new paper.Path.Rectangle(arguments);
    superRect.__proto__ = superRectProto;
    return superRect;
  }
  var aRect = new Rectangle(20, 30, 10, 15);
  var aPath = createSuperRectangle({
    rectangle: aRect,
    strokeColor: 'black'
  });
  aPath.otherFunc();

Alternatively, you can make an object that encapsulates the Path (jsbin here):

  var SuperRectangle = function(arguments){
    this.theRect = new paper.Path.Rectangle(arguments);
    this.otherFunc = function(){
      console.log('dat');
    }
  }
  var aRect = new Rectangle(20, 30, 10, 15);
  var aPath = new SuperRectangle({
    rectangle: aRect,
    strokeColor: 'black'
  });
  aPath.otherFunc();
  aPath.theRect.strokeWidth = 5;

Unfortunately, then to access the path you have to use the theRect variable.


Initial incorrect answer follows:

I don't think you mean "extending classes". In Javascript you can extend objects so that they have more functions, so extending the Path "class" would mean all Path objects have the same new functions. Javascript object extension is further described here.

If I'm wrong, and you do want to extend Path, then you can use:

paper.Path.inject({
    yourFunctionName: function(anyArgumentsHere) {
        // your function here
    }
});

However, I think you are actually talking about creating new objects that mostly behave like Path objects but have different functionality from each other. If that is the case, then you may want to look at this answer about Javascript using prototypical inheritance. For example, here I create two Rectangle objects that behave differently when I ask them to doSomething (jsbin here):

var rect1 = new Path.Rectangle({
    point: [0, 10],
    size: [100, 100],
    strokeColor: 'black'
    });
rect1.doSomething = function() {
    this.fillColor = new Color('red');
};
var rect2 = new Path.Rectangle({
    point: [150, 10],
    size: [100, 100],
    strokeColor: 'black'
    });
rect2.doSomething = function() {
    this.strokeWidth *= 10;
};
rect1.doSomething();
rect2.doSomething();
Code answered 2/8, 2013 at 19:16 Comment(1)
Thanks so much for the response, but I'm actually not talking about either of these things. What I want to do is create, say, Path.SuperRectangle, which gets all of the functionality of Path.Rectangle, but I can also add additional functions and properties. So I can do var foo = new Path.SuperRectangle()Undistinguished
N
0

A couple of things.

1) You can wrap the original paperjs object but this is very much a hack paperjs playground

function SuperSquare() {
    this.square = new Path.Rectangle({
        size:50,
        fillColor:'red',
        onFrame:function(base) {
            var w2 = paper.view.element.width / 2;
            this.position.x = Math.sin(base.time) * w2 + w2;
        }
    });
}
SuperSquare.prototype.setFillColor = function(str) {
    this.square.fillColor = str;
}

var ss = new SuperSquare();
ss.setFillColor('blue');

2) I may clone & create a paper 2017 which operates off of es6 so that you can use the extend keyword.

3) I wrote an application called Flavas but it never gained a following so I just kind of left it. That being said, I have been playing with it lately; upgrading it to es6. With it you can do what you're talking about.

class Square extends com.flanvas.display.DisplayObject {
    constructor(size) {
        this.graphics.moveTo(this.x, this.y);
        this.graphics.lineTo(this.x + size, this.y);
        this.graphics.lineTo(this.x + size, this.y + size);
        this.graphics.lineTo(this.x, this.y + size);
    }

    someMethod(param) {
        trace("do something else", param);
    }
);

I wrote all this kind of quick so feel free to hit me up with Q's.

Nosebleed answered 31/5, 2017 at 22:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.