Using p5.js in the global JS namespace

If I have this right, it's possible (customary) to use e.g. jQuery in the global JS interpreter namespace as $. How would one use p5 similarly? I've tried p5, but that doesn't seem to work.

Answers

  • edited April 2015 Answer ✓
    • AFAIK, p5 is like a function that we pass another function as its running "sketch".
    • That "sketch" argument would contain callbacks like setup(), draw(), mousePressed(), etc.
    • I doubt if p5 can be used by some external ".js" script as some regular library like jQuery.
    • Definition of p5 is framework. And it follows similar approach as Processing's Java Mode.
    • However, jQuery can be used inside p5's passed "sketches". ;;)
  • Answer ✓

    We might give a better answer if you clarify why you want to have a global reference to p5; but I've certainly found it a useful strategy.

    If you look at the Instantiation/namespace example you'll find one way of setting a 'global' reference: in this case you should be able to get at p5 properties and methods from the myp5 variable.

    I've been using a slightly different pattern:

        // global variable used to avoid polluting global namespace
        var foo = foo || {}; // ...but choose something unique! i.e. not foo!
        // Instead of hooking on to a single global variable
        // you could also simply do the following here:
        // var $ = new p5(...
        // But given the abuse $ gets as a global variable that would be bad ;)
        foo.p5 = new p5(function (p) { 
            p.setup = function() {
                //...
            }
    
            p.draw = function() {
                //...
            }
        }), "sketch01");
        // 'sketch01' is the id of the target container in index.html
    
        // I can then reference foo.p5 from Objects defined *outside*
        // the p5 instantiation function:
    
        foo.Mover = function(x, y, vx, vy) {
          //...
        }
        // snip...
        foo.Mover.prototype.draw = function () {
            var p = foo.p5;
            p.ellipseMode(p.RADIUS);
            p.fill(0, 0, 0);
            p.ellipse(this.x, this.y, this.rad, this.rad)
        };
    

    This avoids having to pass a reference to p5 around as a parameter in function calls...

    If you wan to get overly technical, pretty much everything in JavaScript is an Object; even functions. So essentially both jQuery and p5 are Objects with their own set of properties and methods. jQuery is helpful enough to attach itself to a single global variable automatically; because it's meant to be used globally and you only ever want a single instance (seriously!).

    I'd assume that since P5 is meant for a specific application the authors leave it to you to apply it where appropriate; and you can create multiple instances: e.g. in order to have multiple sketches running on the same page.

  • Ah, I don't know how I missed the namespace example. I knew about "everything's an Object" in JS; that's partly why I figured this should be possible.

    What I'm ultimately trying to do is a horrible Frankenstein's Monster involving PyPy.js and p5, e.g. write Python Processing sketches which run in the browser as "first-class citizens".

  • This gist works.

    O_O

    There's a definite need for a load screen, as it takes a while to download everything/spin up.

    This

    "import js\n" + "import time\n" + "p = js.globals['p5js']\n" + "p.textSize(32)\n" + "p.text('word', 10, 30)\n" + "p.fill(0, 102, 153)"

    (which I think is down to my lack of experience with JS) is truly unfortunate.

  • edited May 2015
    • Actually, p5*js inserts itself into global naming space if at least setup() or draw() exist as global properties too!
    • Thus, even an empty function setup() {} would be enough to pull the global trick out! *-:)
    • Problem is that it's not instantaneous! And trying to access p5*js's API before it's fully global crashes the JS script! b-(
    • A possible solution to mix p5*js w/ others in the global space would be invoking target function from within setup():

    function setup() {
      myPyPyApp();
    }
    
    function myPyPyApp() {
      // Your Python script mixed up w/ p5*js below:
    }
    
  • I think I understand what you're saying, but I'm not sure how it will work with PyPy.js, which requires something like

    var vm = new PyPyJS();
    vm.ready.then(...);
    

    for more-or-less the same reason; we have to wait for the PyPy.js vm to fully load and instantiate before we can use it.

  • edited May 2015
    • I dunno how to code w/ that PyPyJS.
    • It'd be better if you had a concrete running app w/ both ".html" + ".js" files.
    • So we could have some idea how to mix it up w/ p5*js framework.
  • There are various strategies you can use to ensure resources are ready. The modern approach is to use a library like requireJS. In this case that's probably overkill. A standard direct approach is to use setInterval, check that all resources are ready (you might have to set a global Boolean from p5 setup()), and then launch a callback function once they are.

    I might get a chance to post some example code - and properly test this with p5 - later...

  • This appears to be working; though I haven't actually tried doing anything with pypy and haven't tried it on a remote server...

    You'll notice pypy blocks fairly heavily: in the console you'll see the 'checking' msg output from setInterval pauses for a moment - one reason for not relying on it for accurate time-keeping!.

    Snippet of content in index.html:

    <script src="lib/Promise.min.js" ></script>
    <script src="lib/pypy.js" ></script>
    
    <script>
    
        var foo = foo || {};
    
        // These need to be set to true once each library is 
        // up and running
        foo.pypyReady = undefined;
        foo.p5Ready = undefined;
    
        // this is where your application finally launches
        foo.callback = function () {
            console.info("all resources loaded and ready");
            // do stuff with p5 and pypy
        }
    
        // modified from pypy example
        foo.vm = new PyPyJS();
        foo.vm.ready.then(function() {
            // this callback is fired when the interpreter is ready for use.
            console.info("pypy ready");
            foo.pypyReady = true;
        })
    
        foo.waiting = setInterval(
            // using an anonymous function here for convenience
            function () {
            console.info("checking");
    
            if(foo.pypyReady && foo.p5Ready) {
                clearInterval(foo.waiting);
                foo.callback();
            }
    
            // TODO: it's good practice to add a limit to 
            // the number of iterations; in case resources 
            // fail to load
    
        } , 100);
    
    </script>
    
    <script src="lib/p5.min.js" ></script>
    <script src="js/sketch.js" ></script>
    

    sketch.js:

    foo.p5 = new p5(function (p) {
    
      p.setup = function () {
        foo.p5Ready = true;
        console.info("p5 ready");
      };
    
      p.draw = function () {
    
      };
    
    });
    
Sign In or Register to comment.