How i extends class in p5.js?

Hi, i try to extends class in p5.js sketch, but not works…

How do you make this?

Any simple example please?

can you give us an example of what you’re trying to do to work off of?

JavaScript got a prototype inheritance system, in which we make available all properties to be extended by annexing them all to a constructor function’s property object {} called prototype: :card_file_box:

For example If we wanna extend the class p5 (classes are constructor functions btW) w/ a new method called square(), we can simply annex it to p5.prototype{} object, like this: :+1:

p5.prototype.square = function (x, y, size) {
  return this.rect(x, y, size, size);
};

And a more complex example, but now extending the class p5.Image instead, w/ a new method called resizeNN(): :ok_hand:

1 Like

Thanks for this info, i looking for use “class” and “extends” on p5.js

It´s possible?

i ´m a noob in javaScript.

Yes, it is possible. But in order to use an extended p5 subclass, you’re gonna need to write your code using the dreadful “instance mode” approach: :roll_eyes:

“index.html”:

<script defer src=https://CDN.JsDelivr.net/npm/p5></script>
<script defer src=sketch.js></script>

“sketch.js”:

/**
 * Class p5 Extended (v1.0.1)
 * GoToLoop (2018-Jun-13)
 * https://Discourse.Processing.org/t/how-i-extends-class-in-p5-js/894/5
 */

"use strict";

class p5Plus extends p5 {
  square(x, y, size) {
    return this.rect(x, y, size, size);
  }
}

function mySketch(p) {
  const RATIO = .75, BOLD = 3.5;

  p.setup = function () {
    p.createCanvas(p.displayWidth * RATIO, p.displayHeight * RATIO);
    p.rectMode(p.CENTER).colorMode(p.RGB).noLoop();
    p.fill('yellow').stroke('red').strokeWeight(BOLD);
  };

  p.draw = function () {
    p.background(0).square(p.width >> 1, p.height >> 1, p.width >> 1);
  };
}

new p5Plus(mySketch);
1 Like

Thanks for the info!!

Thxs for the demo @GoToLoop. I have some questions on my own.

  1. This concept of global vs. instance more is common in js? With instance mode, you create your own scope, right? That is what allows to work with several instances. If you get to write js from scratch, it is enough to define a class to be able to have this instance mode feature?

  2. I have to ask… class is not a closure, or is it?

  3. Lastly, how does prototype gets inherit?

I will have to write my own little demo to see these concepts in action.

Kf

1 Like

For my part I use a straight ECMA6 syntax for this…

class Foo{
  constructor(){
    //...
  }
  someMethod(){//...}
}

class Bar extends Foo{
  //...
}

And so on. To me this approach is easier, since JS isn’t really my native language. I was wondering if those of you who know a lot more Javascript than I do could tell me if there are any significant disadvantages to doing it this way. I only see it rarely in other people’s code.

2 Likes

I tried this in the processing IDE in p5.js mode and it does not work.
and some other things that work like the reserved word “const”.

I do not understand why this happens to me.

AFAIK, PDE’s p5js Mode doesn’t allow the instance mode approach I guess. :grimacing:

The easiest way to run my demo sketches is by having any Firefox-based browser installed in your OS. :star_struck:

I recommend Firefox Developer Edition, Waterfox & Palemoon: :sunglasses:
https://www.mozilla.org/en-US/firefox/developer/all/

  • Create some folder and then place both files “index.html” & “sketch.js” there.
  • Finally open any Firefox-based browser and drag & drop the “index.html” file there.
  • It should be run alright now! :cowboy_hat_face:

P.S.: For Chromium-based browsers, read on this site below: :smile_cat:

1 Like

On the contrary; by using the keyword class, the JS language automatically annexes all the methods in the constructor()'s prototype{} object the most correct way. :muscle:

There are many ES5 folks out there who create the methods over & over inside the construtor function itself, rather than its prototype{}; which isn’t RAM savvy btW! :face_with_hand_over_mouth:

This is a Processing concept thingy! Our “Global Mode” approach is strange to JS world! :scream:

Basically, it auto instantiates, then dumps & binds the whole p5 class to the global scope, which allows us to access them all w/o using the dot . operator. :clown_face:

Yup! And that’s the standard way most apps do in the JS world! :smirk:

Correct. However, we still can have multiple p5 “global mode” instances by placing them all inside separate <iframe> tags, like I did below: :money_mouth_face:

Do you mean my “Class p5 Extended” hack example? :thinking:

B/c we have to pass our function sketch as its argument: new p5Plus(mySketch);
That sketch needs to be using the “instance mode” approach. :no_mouth:

1 Like
  • Closures are outer variables & parameters which are accessed & remembered by inner functions, methods and classes (b/c a class is a constructor function).
  • In my “Class p5 Extended” sketch, the parameter p is a closure for methods setup() & draw().
  • And consts RATIO & BOLD are closures to method setup().
  • Since draw() doesn’t access either consts RATIO & BOLD inside it, they don’t become its closures, saving precious RAM!
  • Notice though that everything in the global scope is a potential closure to everything!
  • Therefore, if p5, p5Plus and mySketch() would be accessed within by any of our functions, they’d become closures to them too!
1 Like

Along w/ closures and how the keyword this works under JS, the innards of the prototype{} inheritance chain are the hardest parts of the JS language! :scream:

As I had already posted in this thread at my 1st reply, we can read a fully tech explanation about it here: :face_with_monocle:

But I’m gonna attempt a shorter explanation below… :flushed:

  • All JS objects got a “hidden” accessor property called __proto__:
  • When we use the operator new to create an object, it automatically assigns its __proto__ property the reference of its constructor’s prototype{} object:
  • Then, when we try to access some property of that object via the operator . dot or brackets [], if that property doesn’t exist in that object, the JS engine follows its __proto__ instead.
  • As long as that __proto__ correctly points out to its original constructor’s prototype{} object, it should find the “missing” property there instead.
  • Most properties in the prototype{} object are methods. Although it might have non-method types too.
2 Likes

A post was split to a new topic: Make class get all functions of p5.js

Hey GoToLoop, I realize this is an old post, but would you mind explaining why you say the instance mode is dreadful?
What is your preferred method for writing P5.js code so that it is not in the global namespace (and potentially conflicting with other js libraries)?
Thanks very much

1 Like
  • I was a lil’ over dramatic there. :flushed:
  • You know, Processing got many flavors.
  • And 1 of the things they got in common is that we don’t need to use the accessor operator dot . in order to use their API.
  • Here’s some sketch example, written in the Java Mode, where members from class PApplet (and its parent interface PConstants) are accessed directly:
  1. PApplet
  2. PConstants
static final float BOLD = 1.5;
static final color STROKE = #FF00FF, FILL = -1;
static final color ALL_COLORS = #000000;

void setup() {
  size(800, 600);
  noLoop();

  colorMode(RGB);
  blendMode(REPLACE);

  strokeCap(ROUND);
  strokeJoin(MITER);
  strokeWeight(BOLD);

  stroke(STROKE);
  fill(FILL);
}

void draw() {
  background((color) random(ALL_COLORS));
  print(frameCount, TAB);
}

void mousePressed() {
  redraw();
}

void keyPressed() {
  mousePressed();
}
  • Notice that the dot . operator is never used anywhere in the sketch above.
  • That’s why p5js flavor had to emulate that same “global mode” feature as well.
  • Now that same sketch rewritten, unnecessarily using the dot . operator:
static final int W = 800, H = 600;
static final float BOLD = 1.5;
static final color STROKE = #FF00FF, FILL = -1;
static final color ALL_COLORS = PImage.ALPHA_MASK;

void settings() {
  this.size(W, H, PConstants.JAVA2D);
  this.noLoop();
}

void setup() {
  this.colorMode(PApplet.RGB);
  this.blendMode(this.REPLACE);

  this.strokeCap(PConstants.ROUND);
  this.strokeJoin(PApplet.MITER);
  this.strokeWeight(BOLD);

  this.stroke(STROKE);
  this.fill(FILL);
}

void draw() {
  this.background((color) this.random(ALL_COLORS));
  PApplet.print(this.frameCount, PConstants.TAB);
}

void mousePressed() {
  this.redraw = true;
}

void keyPressed() {
  this.mousePressed();
}
  • No 1 writes Processing sketches like the above, obviously!

  • However, the use of the keyword this reveals that a Java Mode sketch is actually a class.

  • More precisely, a subclass of Processing’s main class PApplet.

  • And if a member happens to be static, Java allows us to optionally access them via its class or interface name instead.

  • For example, static field REPLACE from interface PConstants can be accessed as this.REPLACE, PApplet.REPLACE or PConstants.REPLACE.

  • In p5js, our sketches aren’t a subclass of its main class p5 though.

  • Instead, they’re a callback argument passed to p5’s constructor().

  • Well, at least that’s the case when we use the “instance mode” approach.

  • In “global mode”, the class p5 is automatically instantiated.

  • Then that instance is dumped into JS’ global context, as properties of the window{} object:

  • And finally, callbacks like setup() & draw() are invoked by that p5 instance, as long as they’re stored in the window{} object.
  • Notice that global variables declared via either keywords var or function are automatically added to the window{} object too.
  • In short, the p5js flavor emulates the flagship Java Mode’s no dot . operator behavior very well via its “global mode” style.
1 Like

As a Java/Python Mode user too, I very much prefer p5js’ global mode. :stuck_out_tongue:

  • The key here is “potentially”… :sweat:
  • However, JS libraries which happen to “pollute” the global context so extensively are so rare that I dunno any but p5js! :wastebasket:
  • As long as the only library we’re using which “dumps” itself into the window{} object is p5js, we should not be that concerned about global name conflict w/ other libs, which could add at most 3 global properties. :relieved:
  • Of course, if we have more than 1 p5js sketch running in the same page, only 1 of them can use the “global mode”. :warning:
  • Either the other additional p5js sketches use the “instance mode” style or they gotta be placed in their own <iframe> if we’d rather prefer to keep them on “global mode”. :grimacing:

Here’s an online example which got both global & instance mode versions of a sketch running together at the same time: :running_man:

Each 1 is inside its own <iframe>. But we can easily go w/ 1 global mode sketch along many other instance mode sketches sharing the same window{} global context: :sunglasses:
Bl.ocks.org/GoSubRoutine/raw/60b154e52336f7fee7c5f1fe817ceb22/all.html

  • In the “all.html”, 4 p5js sketches are created.
  • The 2 top 1s are running the “global.js” file.
  • And the 2 bottom 1s are running the “instance.js” file.
  • B/c we can have at most 1 p5js global mode sketch sharing the same window{} object, the 2nd 1 had to go to its own <iframe> in order to have its own separate window{}.
  • In short, we’ve got 3 sketches sharing the same window{} and 1 not sharing it.
1 Like