Dynamically “unload” a Processing JS sketch from c

2019-02-09 14:54发布

问题:

I'm using some javascript to allow users to dynamically load a sketch on click to a canvas element using:

Processing.loadSketchFromSources('canvas_id', ['sketch.pde']);

If I call Processing.loadSketchFromSources(...) a second (or third...) time, it loads a second (or third...) .pde file onto the canvas, which is what I would expect.

I'd like for the user to be able to click another link to load a different sketch, effectively unloading the previous one. Is there a method I can call (or a technique I can use) to check if Processing has another sketch running, and if so, tell it to unload it first?

Is there some sort of Processing.unloadSketch() method I'm overlooking? I could simply drop the canvas DOM object and recreate it, but that (1) seems like using a hammer when I need a needle, and (2) it results in a screen-flicker that I'd like to avoid.

I'm no JS expert, but I've done my best to look through the processing.js source to see what other functions may exist, but I'm hitting a wall. I thought perhaps I could look at Processing.Sketches.length to see if something is loaded already, but simply pop'ing it off the array doesn't seem to work (didn't think it would).

I'm using ProcessingJS 1.3.6.

回答1:

As of processing.js 1.4.8, Andrew's accepted answer (and the other answers I've found in here) do not seem to work anymore.

This is what worked for me:

    var pjs = Processing.getInstanceById('pjs');
    if (typeof pjs !== "undefined") {
      pjs.exit();
    }

    var canvas = document.getElementById('pjs')
    new Processing(canvas, scriptText);

where pjs is the id of the canvas element where the scrips is being run.



回答2:

In case someone else comes looking for the solution, here's what I did that worked. Note that this was placed inside a closure (not included here for brevity) -- hence the this.launch = function(), blah blah blah... YMMV.

/**
 * Launches a specific sketch. Assumes files are stored in
 * the ./sketches subdirectory, and your canvas is named g_sketch_canvas
 * @param {String} item The name of the file (no extension)
 * @param {Array} sketchlist Array of sketches to choose from
 * @returns true
 * @type Boolean
 */
this.launch = function (item, sketchlist) {
    var cvs = document.getElementById('g_sketch_canvas'),
        ctx = cvs.getContext('2d');
    if ($.inArray(item, sketchlist) !== -1) {
        // Unload the Processing script
        if (Processing.instances.length > 0) {
            // There should only be one, so no need to loop
            Processing.instances[0].exit();
            // If you may have more than one, then use this loop:
             for (i=0; i < Processing.instances.length; (i++)) {
            //  Processing.instances[i].exit();
            //}
        }
        // Clear the context
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.clearRect(0, 0, cvs.width, cvs.height);
        // Now, load the new Processing script
        Processing.loadSketchFromSources(cvs, ['sketches/' + item + '.pde']);
    }
    return true;
};


回答3:

I'm not familiar with Processing.js, but the example code from the site has this:

var canvas = document.getElementById("canvas1");
// attaching the sketchProc function to the canvas
var p = new Processing(canvas, sketchProc);
// p.exit(); to detach it

So in your case, you'll want to keep a handle to the first instance when you create it:

var p1 = Processing.loadSketchFromSources('canvas_id', ['sketch.pde']);

When you're ready to "unload" and load a new sketch, I'm guessing (but don't know) that you'll need to clear the canvas yourself:

p1.exit();
var canvas = document.getElementById('canvas_id'); 
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
// Or context.fillRect(...) with white, or whatever clearing it means to you

Then, from the sound of things, you're free to attach another sketch:

var p2 = Processing.loadSketchFromSources('canvas_id', ['sketch2.pde']);

Again, I'm not actually familiar with that library, but this appears straightforward from the documentation.