问题
I want use p5.js
function inside a class with ECMAScript notation.
How to fix this code?
class Sketch {
constructor(p, params) {
// generate vars use in class with object
if (typeof params !== 'undefined') {
for (let key in params) this[key] = params[key];
}
// p5.js object
this.p = p;
}
// p5.js setup method
setup() {
this.p.createCanvas();
}
// p5.js draw method
draw() {
}
}
sketch = new Sketch(p5,{});
Error:
this.p.createCanvas is not a function
回答1:
The docs say that you must instantiate p5
and pass your initialiser function that creates the method on p
:
const myp5 = new p5(p => {
p.setup = () => {
p.createCanvas();
};
…
});
See also the Global and instance mode tutorial.
This is a really weird construction however. Although it's not documented, in ES6 it should be possible to subclass p5
:
class Sketch extends p5 {
constructor(params) {
super(p => {
// do any setup in here that needs to happen before the sketch starts
// (e.g. create event handlers)
// `p` refers to the instance that becomes `this` after the super() call
// so for example
if (typeof params == 'object' && params != null)
for (let key in params)
p[key] = params[key];
});
// `this` itself is the p5.js object
}
// p5.js setup method
setup() {
this.createCanvas();
}
// p5.js draw method
draw() {
}
}
const myp5 = new Sketch({});
Notice that the p5
constructor will invoke your methods; you don't have to do myp5.setup()
yourself.
回答2:
Tinkering with this issue. I was able to implement inheritance of p5 kinda like so:
import p5 from 'p5';
const MIN_RAD = 150;
const MAX_RAD = 250;
const ITEM_COLOR = 'red';
const BG = 'rgba(50,50,50,.05)';
const VELOCITY = 1;
export default class Sketch extends p5 {
constructor(sketch = ()=>{}, node = false, sync = false) {
super(sketch, node, sync);
console.log('Sketch [this:%o]', this);
this.setup = this.setup.bind(this);
this.draw = this.draw.bind(this);
this.render = this.render.bind(this);
this.increment = this.increment.bind(this);
this.windowResized = this.windowResized.bind(this);
}
setup() {
console.log('setup', this.windowWidth, this.windowHeight);
this.createCanvas(this.windowWidth, this.windowHeight, p5.WEBGL);
this.bg = this.color(BG);
this.itemColor = this.color(ITEM_COLOR);
this.rad = MIN_RAD;
this.grow = true;
this.frame = 0;
}
draw() {
this.increment();
this.render();
}
render() {
let x = this.windowWidth / 2;
let y = this.windowHeight / 2;
this.background(this.bg);
this.fill(this.itemColor);
this.stroke(this.itemColor);
this.ellipse(x, y, this.rad, this.rad);
}
increment() {
this.rad = this.grow ? this.rad + VELOCITY : this.rad - VELOCITY;
if (this.rad > MAX_RAD) {
this.grow = false;
};
if (this.rad < MIN_RAD) {
this.grow = true;
}
this.frame++;
}
// EVENTS
windowResized() {
console.log('windowResized', this.windowWidth, this.windowHeight);
this.resizeCanvas(this.windowWidth, this.windowHeight);
}
}
This class can be imported normally, and instantiated by invoking the constructor.
import Sketch from './sketch';
...
const sketch = new Sketch();
Digging through the source code a little, there are two critical states that auto-magically activate the so-called 'global' mode, where p5 dumps its guts onto window
(to be avoided).
- 1) at init.js#L21, if
draw
andsetup
both exist on thewindow
- 2) on core.js#L496, if the
sketch
argument is falsey
p5/Core
uses these conditions to set its internal _isGlobal
prop which is used to define context as either window
or this
, and conditionally acts on this throughout. EG:core.js#L271
Just expanding on the selected answer (which is correct, except I get errors passing in an empty object).
Frankly, both of the documented construction methods are unsatisfactory. This is an improvement, but we still have to do extra work to manage scope.
来源:https://stackoverflow.com/questions/43079407/p5-js-ecmascript6-notation