Processing.js for JavaScript Devs: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(Created page with "= Processing.js Quick Start - JavaScript Developer Edition = ==Introduction== This quick start guide is written from the standpoint of a JavaScript developer. The document ass...")
 
 
(17 intermediate revisions by 2 users not shown)
Line 12: Line 12:
# To use it, download Processing.js here: http://processingjs.org/download
# To use it, download Processing.js here: http://processingjs.org/download
# Make your Processing *.pde files as you normally would, for example hello-web.pde
# Make your Processing *.pde files as you normally would, for example hello-web.pde
# Create a web page that includes Processing.js as well as a <canvas> with info about where to get your sketch file:
# Create a web page that includes Processing.js as well as a <canvas> with info about where to get your sketch file (you can specify multiple *.pde files, separating them with spaces, and can name them anything, foo.pjs or foo.pde, or foo.js):


<pre>
<script src="processing-0.9.7.min.js"></script>
<script src="processing-0.9.7.min.js"></script>
<canvas data-processing-sources="hello-web.pde"></canvas>
<canvas data-processing-sources="hello-web.pde"></canvas>
</pre>


Load your web page, and it will parse, translate, and run your sketch in the browser.
Load your web page, and it will parse, translate, and run your sketch in the browser.
Line 25: Line 23:
===What is Processing?===
===What is Processing?===


The Processing language was originally created at MIT as part of the Media lab and Aesthetics and Computation group.  The people working there needed a way to bridge the gap between software developers, artists, data visualizers, etc., and to do so in a way that allowed new programmers (or non-programmers) to do complex visual work easily.  Processing was built using Java, and can be thought of as a simplified Java, with a customized API for drawing and graphics.
The Processing language was originally created at MIT as part of the Media lab and Aesthetics and Computation group.  They needed a way to bridge the gap between software developers, artists, data visualizers, etc., and to do so in a way that allowed new programmers (or non-programmers) to do complex visual work easily.  Processing was built using Java, and can be thought of as a simplified Java, with a simplified Java API for drawing and graphics.


===What does Processing bring to the web?===
===What does Processing bring to the web?===


Processing has a large and vibrant community, who are good at creating 2D and 3D graphics, visualizing data sets, audio, video, etc.  With HTML5 the web gained <canvas>, <audio>, and <video>--things which had previously only been available via plugins like Flash or Java.  At the same time, advances in JavaScript engines, have made it possible to do things in script that were previously unthinkable.
Processing has a large and vibrant community, who are good at creating 2D and 3D graphics, visualizing data sets, audio, video, etc.  With HTML5 the web gained canvas, audio, and video--things which had previously only been available via plugins like Flash or Java.  At the same time, advances in JavaScript engines have made it possible to do things in script that were previously too slow.


By porting the Processing language to the web, both the Processing and web communities benefit.  For Processing, this means that code which used to only work on the desktop now "just works" in the browser.  For the web, this means that a new but mature and full-featured approach to graphics programming becomes available.  The <canvas> element is too low-level for most developers to use directly--JavaScript libraries are necessary.  Processing.js can be thought of as just such a library.
By porting the Processing language to the web, both the Processing and web communities benefit.  For Processing, this means that code which used to only work on the desktop now "just works" in the browser.  For the web, this means that a new but mature and full-featured approach to graphics programming becomes available.  The <canvas> element is too low-level for most developers to use directly--JavaScript libraries are necessary.  Processing.js can be thought of as just such a library, simplifying the use of the 2D and 3D canvas operations.


===How much work is it to learn Processing?===
===How much work is it to learn Processing?===


The Processing language was designed to be small but complete, and easy to learn.  Having said that, it is
The Processing language was designed to be small but complete, and easy to learn.  This document does not attempt to teach you Processing, and you are encouraged to seek out Processing specific tutorials, books, and examples.  Any Processing code or concepts should map to Processing.js (the exceptions are listed below).  You can also use pure JavaScript to work with the Processing drawing API, skipping the Java syntax of Processing in favour of JavaScript.


is built using Java.  It was created at much the same time that the web was starting.  At this time the choice of the Java language, and Java Runtime, as implementation targets for Processing made a lot of sense.  In the mid-1990s, Java was poised to become the language of the web, with Applets and other Java technologies being used broadly on the client-side.  Even Netscape, who created the language which would eventually become the ''lingua franca'' of the web with JavaScript, named their language so as to align themselves with the growing hype around Java.
==Ways to Use Processing.js==


In the end, Java became an important server side technology, receding from the client-side and browser. Today, most web browsers still support Java Applets, by means of a binary plugin.  However, few web developers deploy Java-based web applications now, due to long load and startup times and difficulties relying on Java (or compatible Java versions) being installedThis trend is not isolated to Java, but is happening to all browser plugins (e.g., Flash), which are becoming less popular as issues of security, installation, deployment, etc. make them inconvenient or risky.
Processing.js was originally created in order to allow existing Processing developers and existing Processing code (often referred to as ''sketches'') to work unmodified on the webAs a result, the recommend way to use Processing.js is to write Processing code, and have Processing.js convert it to JavaScript before running it.


Another reason that plugins like Java and Flash have fallen out of favour is that recent advances in standard web technologies, specifically HTML5 and JavaScript, have made it possible to do things that previously depended on native (i.e., faster, compiled) code. Companies like Google, with GMail and Google Docs, or Scribd (see http://www.scribd.com/doc/30964170/Scribd-in-HTML5) have shown that HTML, CSS, and JavaScript alone are enough to build fast, full featured web applications.
Over time, many web developers have begun using Processing.js, and asked that we design a way for the API to be used separate from the Processing language itself.  Therefore, we have provided a way for JavaScript developers to write pure JavaScript code and still use the Processing.js functions and objects. NOTE: Processing.js is first and foremost a port of Processing to the open web, with design decisions favouring compatibility with Processing. It was not designed as a general purpose HTML drawing library. Having said that, it can be used as a high-level drawing API for canvas.


===Processing.js uses Modern Web Standards===
Below we discuss the various methods for using Processing.js in your web pages.


Processing.js is built using JavaScript and HTML5.  Processing.js is really two things: a Processing-to-JavaScript translator; and an implementation of the Processing API (e.g., functions like line(), stroke(), etc.) written in JavaScript instead of Java.  It might seem odd at first to imagine your Processing sketches running in a browser, usually without modification.  But this is exactly what Processing.js enables.
===Writing Pure Processing Code===


Processing.js automatically converts your Processing code to JavaScript. This means that you don't have to learn JavaScript in order to run your code in a browser.  You can, quite literally, write your code using the Processing IDE like you always have, and follow the steps below to get it running on the webThere's nothing new to learn, beyond getting a simple web page created.
This is the preferred method for using Processing.js, and has been dealt with at length in the [[Processing.js for Processing Devs]] quick start guideTo summarize:


Under the hood, Processing.js uses the new HTML5 canvas element to create your sketch's graphics.  The canvas element is a new feature of the web, and is either implemented or will be implemented by all major web browsers.  All Processing drawing features have been reimplemented in Processing.js to use canvas, so any browser that supports canvas will also support Processing.js.
# Download Processing.js here: http://processingjs.org/download
# Create a separate Processing file or files, naming them whatever you want, but usually *.pde or *.pjs.
# Create a web page that includes Processing.js as well as a <canvas> with info about where to get your sketch file(s), and include Processing filenames as a space-separated list in a data-processing-sources attribute on the canvas:


Here's a sample of a Processing.js sketch running in the browser.  If you can see it working, your browser supports everything you need already, and you can move on to instructions below.
<pre>
<!DOCTYPE html>
<html>
  <head>
    <title>Hello Web - Processing.js Test</title>
    <script src="processing-0.9.7.min.js"></script>
  </head>
  <body>
    <h1>Processing.js Test</h1>
    <p>This is my first Processing.js web-based sketch:</p>
    <canvas data-processing-sources="hello-web.pde"></canvas>
  </body>
</html>
</pre>


'''Create simple sketch here'''
Processing.js will automatically scan the document on page load for <canvas> elements with '''data-processing-sources''' attributes, download the files using XMLHTTPRequest, and feed them to the Processing-to-JavaScript translator.  The resulting JavaScript is run using eval.


==1. Writing a Processing.js Sketch==
===Pre-compiling Processing code to JavaScript===


There's nothing you should do differently to write sketches for Processing.js: you write your Processing.js code exactly like ProcessingFor most people, this will mean using the Processing IDE, which has the nice benefit of letting you write, run, and test your code all in once place.  Remember, any valid Processing sketch should also be a valid Processing.js sketch.
Processing.js automatically downloads and converts any Processing code to JavaScriptIt does this using the Processing.compile() method, and those interested in building tools or utilities for Processing.js can do the same.


If you want to experiment with web-based Processing.js code editors, you can also try these:
In order to obtain "compiled" code (i.e., JavaScript suitable for use by the Processing.js runtime) from Processing code, do the following:


* http://sketch.processing.org/
<pre>
* http://sketchpad.cc/
// hard-coded Processing code, text from an HTML widget, downloaded text, etc.
* http://hascanvas.com/
var processingCode = "...";
var jsCode = Processing.compile(processingCode).sourceCode;
</pre>


Let's make a simple sketch that is 200 by 200 in size, sets the background to gray, draws a small white circle, and prints a message to the debug console:
For example, converting the following Processing code produces the "compiled" JavaScript underneath:


<pre>
<pre>
// Processing code
void setup() {
void setup() {
   size(200, 200);
   size(200, 200);
Line 75: Line 91:
   println("hello web!");
   println("hello web!");
}
}
// "Comiled" JavaScript code
// this code was autogenerated from PJS
(function(processing, $constants) {
    function setup() {
        processing.size(200, 200);
        processing.background(100);
        processing.stroke(255);
        processing.ellipse(50, 50, 25, 25);
        processing.println("hello web!");
    }
    processing.setup = setup;
})
</pre>
</pre>


I'll assume below that you saved this to a file called '''hello-web.pde'''.
===Writing JavaScript-only Processing.js code===


==2. Obtaining Processing.js==
The previous method produced JavaScript code from Processing, but you can also write JavaScript on its own. The Processing.js parser turns Processing code into a JavaScript function, then runs it.  As a result, it's possible to skip the Processing code altogether, and simply write a JavaScript function, passing this to your Processing instance.  Here's an example:


Processing.js is a JavaScript library that is meant to be included in a web page. You don't have to compile it, tell your web server about it, etc. It simply has to be included in a web page, and the browser will do the rest.
<pre>
function sketchProc(processing) {
  // Override draw function, by default it will be called 60 times per second
  processing.draw = function() {
    // determine center and max clock arm length
    var centerX = processing.width / 2, centerY = processing.height / 2;
    var maxArmLength = Math.min(centerX, centerY);


You can download Processing.js at http://processingjs.org/download. The library comes in a number of forms, for example:
    function drawArm(position, lengthScale, weight) {
      processing.strokeWeight(weight);
      processing.line(centerX, centerY,
        centerX + Math.sin(position * 2 * Math.PI) * lengthScale * maxArmLength,
        centerY - Math.cos(position * 2 * Math.PI) * lengthScale * maxArmLength);
    }


* processing-0.9.7.js
    // erase background
* processing-0.9.7.min.js
    processing.background(224);


The version numbers may be different as you read this, but note the file extensions.  Both end in .js, but one also has .min.  The .min version is Processing.js in a minified form, which means it will be smaller to download (minified JavaScript uses tricks like removing whitespace and renaming long variable names to single letters).  File sizes, and download times, matter on the web in a way they don't with normal Processing sketches.
    var now = new Date();


==3. Creating a Processing.js Web Page==
    // Moving hours arm by small increments
    var hoursPosition = (now.getHours() % 12 + now.getMinutes() / 60) / 12;
    drawArm(hoursPosition, 0.5, 5);


It's easy to get overwhelmed with the amount there is to learn about modern web technologies. But there's a secret: you can ignore 95% of it as you start, and add more later as you have time and interest. Unlike compilers or programming languages, web browsers are designed to accept almost any input you throw at them, whether valid or not, whether complete or not.  Here's your first Processing.js web page:
    // Moving minutes arm by small increments
    var minutesPosition = (now.getMinutes() + now.getSeconds() / 60) / 60;
    drawArm(minutesPosition, 0.80, 3);


<pre>
    // Moving hour arm by second increments
<script src="processing-0.9.7.min.js"></script>
    var secondsPosition = now.getSeconds() / 60;
<canvas data-processing-sources="hello-web.pde"></canvas>
    drawArm(secondsPosition, 0.90, 1);
  };
}
 
var canvas = document.getElementById("canvas1");
// attaching the sketchProc function to the canvas
var processingInstance = new Processing(canvas, sketchProc);
</pre>
</pre>


That's it!  No <html> or <body> tags, no title, no CSS, just the processing.js script, and a canvas. While there isn't much here, it's important to understand what is. First, the script tag has a '''src''' attribute, which is the file to loadThis could be a full url or a relative path. In this case the browser is going to look for a file named '''processing-0.9.7.min.js''' in the same directory as your web page.
Here a sketch function is created, similar to what the parser would produce. This function should take 1 argument, a reference to a processing object (i.e., the Processing runtime), which will be created by the Processing constructorAny Processing functions or objects are accessible as properties of this object.
 
Once that function is complete, pass it, along with a reference to a canvas, to the Processing constructor (remember to use ''new'').
 
===Writing Documents that Combine Processing and JavaScript Code===


The second thing in this web page is a <canvas> tag.  Notice that it too has an attribute, '''data-processing-sources'''.  This is a list of filenames (or just one filename if you only have 1 file) separated by spaces (filenames and URLs on the web can't include spaces, so space is a safe choice for separating lists)In this case, the browser is going to look for a file named '''hello-web.pde''' located in the same directory as your page page.
One of the first questions people ask with Processing.js is whether they can read values from the document in which the Processing sketch is running, or vice versaThe answer is yes.


How does the browser know how to load a Processing *.pde file?  Processing.js takes care of this, and will download, parse (i.e., translate to JavaScript), then run it automatically when the page is loaded.
Processing.js converts Processing code into JavaScript contained in a function closure. The variables and functions you create are not attached to the global object (i.e., window).  However, you can still get access to them.


And that's it!  Save this file to the same directory as '''hello-web.pde''' and '''processing-0.9.7.min.js''' and call it '''hello-web.html'''.
====Accessing JavaScript Objects from Processing====


If you're the kind of person who doesn't like taking shortcuts, here's what a more complete web page might look like:
Since Processing code gets converted to JavaScript and run like any other function, all Processing code has access to the global object.  This means that if you create a variable or function in a global script block, they are automatically accessible to Processing.  Consider this example:
 
First the Processing file, mixing.pde:
 
<pre>
String processingString = "Hello from Processing!";
 
void setup() {
  printMessage(jsString + " " + processingString);
}
</pre>
 
Next the web page:


<pre>
<pre>
Line 113: Line 179:
<html>
<html>
   <head>
   <head>
     <title>Hello Web - Processing.js Test</title>
     <title>Hello Web - Accessing JavaScript from Processing</title>
     <script src="processing-0.9.7.min.js"></script>
     <script src="processing-0.9.7.min.js"></script>
   </head>
   </head>
   <body>
   <body>
     <h1>Processing.js Test</h1>
     <div id="msg"></div>
    <p>This is my first Processing.js web-based sketch:</p>
     <canvas data-processing-sources="mixing.pde"></canvas>
     <canvas data-processing-sources="hello-web.pde"></canvas>
    <script type="application/javascript">
      var jsString = "Hello from JavaScript!";
      var printMessage = function(msg) {
        document.getElementById('msg').innerHTML = "Message: " + msg;
      };
    </script>
   </body>
   </body>
</html>
</html>
</pre>
Here Processing.js allows the use of a variable and function declared outside the Processing code.
====Mixing JavaScript and Processing====
The previous example kept a clean separation between the JavaScript and Processing code, while loosening the boundary between the two.  Because Processing.js converts Processing code to JavaScript, it's also possible to mix them directly.  The Processing.js parser will leave JavaScript it finds within the Processing code unaltered, allowing developers to write a hybrid of Processing and JavaScript (NOTE: this is why we don't use a pure Processing parser approach in processing.js).  Here is the previous example rewritten using this method:
<pre>
var jsString = "Hello from JavaScript!";
var printMessage = function(msg) {
  document.getElementById('msg').innerHTML = "Message: " + msg;
};
String processingString = "Hello from Processing!";
void setup() {
  printMessage(jsString + " " + processingString);
}
</pre>
</pre>


Both ways work, and you shouldn't let yourself get burdened by HTML and other web syntax until you feel you want to do other things with your web pages.
There is some JavaScript syntax that can't be easily mixed this way (e.g., regex literals).  In those cases you can simply move your pure JavaScript to a <script> block and access it using the method described above.
 
====Accessing Processing from JavaScript====
 
Reaching out from the Processing code to JavaScript is easier than going the other way, since the JavaScript created by the Processing.js parser is not exposed directly on the global object.  Instead, you gain access using the Processing.instances property.
 
The Processing constructor keeps track of instances it creates, and makes them available using the getInstanceById() method.  By default, when a <canvas> has a data-processing-sources attribute, its id is used as a unique identifier for the Processing instance.  If no id attribute is provided, you can use Processing.instances[0].
 
After you have a reference to the appropriate Processing instance, you can call into it like so:
 
<pre>
<!DOCTYPE html>
<html>
  <head>
    <title>Hello Web - Controlling Processing from JavaScript</title>
    <script src="processing-0.9.7.min.js"></script>
  </head>
  <body>
    <canvas id="sketch" data-processing-sources="controlling.pde"></canvas>
    <button onclick="startSketch();">Start</button>
    <button onclick="stopSketch();">Stop</button>
 
    <script type="application/javascript">
      var processingInstance;
 
      function startSketch() {
        switchSketchState(true);
      }
     
      function stopSketch() {
        switchSketchState(false);
      }


==3. Running your Processing.js Web Page==
      function switchSketchState(on) {
        if (!processingInstance) {
          processingInstance = Processing.getInstanceById('sketch');
        }


In case it isn't obvious, you run your '''hello-web.pde''' sketch by loading your '''hello-web.html''' web page in a compatible browserWeb browsers will provide you a way to load a local file, usually using the File menu and then ''Open File...''.  If you've saved the files above on a web server, you can use the remote URL instead.
        if (on) {
          processingInstance.loop(); // call Processing loop() function
        } else {
        processingInstance.noLoop(); // stop animation, call noLoop()
        }
      }
    </script>
  </body>
</html>
</pre>


==Things to Know as a Processing Developer using Processing.js==
Here two buttons in the DOM are used to allow the user to start or stop a running Processing sketch.  They control the Processing instance (you might have several in a page, or hidden in divs) directly from JavaScript, calling Processing functions: loop() and noLoop().  The Processing functions are well documented elsewhere.


While Processing.js is compatible with Processing, Java is not JavaScript, and canvas has some differences from Java's graphics classes.  Here are some tricks and tips as you start working on more complex sketches in Processing.js.
==Things to Know as a JavaScript Developer using Processing.js==


===Processing.js has no data directory===
While Processing.js tries to be fully compatible with Processing, there are some things which are different or require workarounds.  We have also added some web-specific features to make Processing.js easier to use.  Here are some tricks and tips as you start working on more complex sketches in Processing.js.


Processing uses the concept of a '''data''' directory, where images and other resources are located.  Processing.js does not include this.  As a result, you should always provide file pages (e.g., images) that are relative to your web page, which is the norm on the web.
===Processing.js provides access to various DOM/JavaScript objects via the externals property===


===Processing.js implements Processing, but not all of Java===
Each Processing instance (i.e., Processing.instances) has an '''externals''' property, which is an object containing references to various non-Processing DOM/JavaScript objects that can be useful.  For example:


Processing.js is compatible with Processing, but is not, and will never be, fully compatible with Java.  If your sketch uses functions or classes not defined as part of Processing, they are unlikely to work with Processing.js.  Similarly, libraries that are written for Processing, which are written in Java instead of Processing, will most likely not work.
* canvas - the canvas to which the sketch is bound
* context - the canvas' context
* onblur and onfocus - event handlers


===Division which is expected to produce an integer might need explicit casting===
===Division which is expected to produce an integer might need explicit casting===


There are a class of bugs that arise when converting Processing code to Processing.js that involve integer vs. floating point division.  What was straight-up integer division in Processing code, when converted to Processing.js, can sometimes become problematic, as numbers become doubles, and introduce a fractional part.  The fix is to explicitly cast any division to an integer that exhibits this behaviour:
There are a class of bugs that arise when converting Processing code to Processing.js that involve integer vs. floating point division.  What was straight-up integer division in Processing code, when converted to JavaScript, can sometimes become problematic, as numbers become doubles, and introduce a fractional part.  The fix is to explicitly cast any division to an integer that exhibits this behaviour:


<pre>
<pre>
Line 160: Line 295:
Processing uses a synchronous I/O model, which means that functions like '''loadImage()''' take time to execute, and while they are running, nothing else happens: the program waits until '''loadImage()''' is done before moving on to the next statement.  This means that you can count on the value returned by a function like '''loadImage()''' being usable in the next line of code.
Processing uses a synchronous I/O model, which means that functions like '''loadImage()''' take time to execute, and while they are running, nothing else happens: the program waits until '''loadImage()''' is done before moving on to the next statement.  This means that you can count on the value returned by a function like '''loadImage()''' being usable in the next line of code.


Web browsers don't work like this.  The web uses an asynchronous I/O model, which means that functions which load external resources can't make the program wait until they finish.  In order to replicate Processing's load* functions, you have to use a special Processing.js Directive.
Obviously, JavaScript doesn't work like this.  The web uses an asynchronous I/O model, which means that functions which load external resources can't make the program wait until they finish.  In order to replicate Processing's load* functions, you have to use a special Processing.js Directive.


The Processing.js Directives are hints to the browser that are written in comments rather than in the Processing code itself.  Here's a typical Processing sketch that loads an image synchronously and then draws it:
The Processing.js Directives are hints to the browser that are written in comments rather than in the Processing code itself.  Here's a typical Processing sketch that loads an image synchronously and then draws it:
Line 185: Line 320:
</pre>
</pre>


Notice the extra comment line at the top of the code.  The '''@pjs''' directive is for Processing.js, and not the developer.  Think of it as an extra in of code that will be executed before the program begins.
Notice the extra comment line at the top of the code.  The '''@pjs''' directive is for Processing.js, and not the developer.  Think of it as an extra line of code that will be executed before the program begins.


If you have multiple images to load, use a list like so:
If you have multiple images to load, use a list like so:
Line 199: Line 334:
===It is possible to put Processing code directly in your web page===
===It is possible to put Processing code directly in your web page===


Using the data-processing-sources attribute on the canvas, and having Processing.js load an external file is the preferred and recommend way to include scripts in a web page.  However, it is also possible to write in-line Processing code.
Using the data-processing-sources attribute on the canvas, and having Processing.js load an external file is the preferred and recommended way to include scripts in a web page.  However, it is also possible to write in-line Processing code.


A few changes are necessary to make the example above work with inline Processing code:
A few changes are necessary to make the example above work with inline Processing code:
Line 256: Line 391:
</pre>
</pre>


This code is more complex because it has to figure out which canvas goes with which script (i.e., you can have multiple Processing sketches living in the same page, and therefore, multiple canvses).  Also note that the scripts include a '''type''' attribute, which distinguishes between JavaScript and Processing code (the browser will ignore Processing scripts).  Finally, note the use of the '''id''' and '''target''' attributes to connect the Processing script with the associated canvas.
This code is more complex because it has to figure out which canvas goes with which script (i.e., you can have multiple Processing sketches living in the same page, and therefore, multiple canvases).  Also note that the scripts include a '''type''' attribute, which distinguishes between JavaScript and Processing code (the browser will ignore Processing scripts).  Finally, note the use of the '''id''' and '''target''' attributes to connect the Processing script with the associated canvas.


Portions of the code above are from the Processing.js project's '''init.js''' file, see http://github.com/annasob/processing-js/blob/0.9.8/examples/init.js.  This file will likely be going away in the future, and happen automatically as part of Processing.js initialization.
Portions of the code above are from the Processing.js project's '''init.js''' file, see http://github.com/annasob/processing-js/blob/0.9.8/examples/init.js.  This file will likely be going away in the future, and happen automatically as part of Processing.js initialization.
===Whatever you can do with the web, you can do with Processing.js===
Now that your sketch is working, and you have a basic web page, you'll probably start getting ideas about how to make this look more beautiful, how to better integrate your sketch with the surrounding web page or site, and how to mix data from various web services and APIs.  Is it possible to mix images on Flickr and a Processing.js sketch? Yes.  Is it possible to link Twitter to Processing.js?  Yes.  Anything the web can do, your Processing.js sketch can do.
This is an important idea, and is worth restating: Processing.js turned your once Java-based code into JavaScript, and your graphics into <canvas>.  As a result, anything you read on the web about dynamic web programming, AJAX, other JavaScript libraries or APIs, all of it applies to your sketch now.  You aren't running code in a box, cut-off from the rest of the web.  Your code is a first-class member of the web, even though you didn't write it that way.
If you're feeling adventurous and want to go learn more about how to do other thing with HTML, JavaScript, CSS, etc. remember that everything they say applies to you and your sketches.

Latest revision as of 01:00, 25 October 2010

Processing.js Quick Start - JavaScript Developer Edition

Introduction

This quick start guide is written from the standpoint of a JavaScript developer. The document assumes you know JavaScript and web programming, but only very basic Processing knowledge is assumed.

For the Impatient

If you're in a rush, here's what you need to know:

  1. Processing.js converts Processing code to JavaScript and runs it in the browser, using <canvas> for a drawing surface.
  2. To use it, download Processing.js here: http://processingjs.org/download
  3. Make your Processing *.pde files as you normally would, for example hello-web.pde
  4. Create a web page that includes Processing.js as well as a <canvas> with info about where to get your sketch file (you can specify multiple *.pde files, separating them with spaces, and can name them anything, foo.pjs or foo.pde, or foo.js):
<script src="processing-0.9.7.min.js"></script>
<canvas data-processing-sources="hello-web.pde"></canvas>

Load your web page, and it will parse, translate, and run your sketch in the browser.

Why Processing.js?

What is Processing?

The Processing language was originally created at MIT as part of the Media lab and Aesthetics and Computation group. They needed a way to bridge the gap between software developers, artists, data visualizers, etc., and to do so in a way that allowed new programmers (or non-programmers) to do complex visual work easily. Processing was built using Java, and can be thought of as a simplified Java, with a simplified Java API for drawing and graphics.

What does Processing bring to the web?

Processing has a large and vibrant community, who are good at creating 2D and 3D graphics, visualizing data sets, audio, video, etc. With HTML5 the web gained canvas, audio, and video--things which had previously only been available via plugins like Flash or Java. At the same time, advances in JavaScript engines have made it possible to do things in script that were previously too slow.

By porting the Processing language to the web, both the Processing and web communities benefit. For Processing, this means that code which used to only work on the desktop now "just works" in the browser. For the web, this means that a new but mature and full-featured approach to graphics programming becomes available. The <canvas> element is too low-level for most developers to use directly--JavaScript libraries are necessary. Processing.js can be thought of as just such a library, simplifying the use of the 2D and 3D canvas operations.

How much work is it to learn Processing?

The Processing language was designed to be small but complete, and easy to learn. This document does not attempt to teach you Processing, and you are encouraged to seek out Processing specific tutorials, books, and examples. Any Processing code or concepts should map to Processing.js (the exceptions are listed below). You can also use pure JavaScript to work with the Processing drawing API, skipping the Java syntax of Processing in favour of JavaScript.

Ways to Use Processing.js

Processing.js was originally created in order to allow existing Processing developers and existing Processing code (often referred to as sketches) to work unmodified on the web. As a result, the recommend way to use Processing.js is to write Processing code, and have Processing.js convert it to JavaScript before running it.

Over time, many web developers have begun using Processing.js, and asked that we design a way for the API to be used separate from the Processing language itself. Therefore, we have provided a way for JavaScript developers to write pure JavaScript code and still use the Processing.js functions and objects. NOTE: Processing.js is first and foremost a port of Processing to the open web, with design decisions favouring compatibility with Processing. It was not designed as a general purpose HTML drawing library. Having said that, it can be used as a high-level drawing API for canvas.

Below we discuss the various methods for using Processing.js in your web pages.

Writing Pure Processing Code

This is the preferred method for using Processing.js, and has been dealt with at length in the Processing.js for Processing Devs quick start guide. To summarize:

  1. Download Processing.js here: http://processingjs.org/download
  2. Create a separate Processing file or files, naming them whatever you want, but usually *.pde or *.pjs.
  3. Create a web page that includes Processing.js as well as a <canvas> with info about where to get your sketch file(s), and include Processing filenames as a space-separated list in a data-processing-sources attribute on the canvas:
<!DOCTYPE html>
<html>
  <head>
    <title>Hello Web - Processing.js Test</title>
    <script src="processing-0.9.7.min.js"></script>
  </head>
  <body>
    <h1>Processing.js Test</h1>
    <p>This is my first Processing.js web-based sketch:</p>
    <canvas data-processing-sources="hello-web.pde"></canvas>
  </body>
</html>

Processing.js will automatically scan the document on page load for <canvas> elements with data-processing-sources attributes, download the files using XMLHTTPRequest, and feed them to the Processing-to-JavaScript translator. The resulting JavaScript is run using eval.

Pre-compiling Processing code to JavaScript

Processing.js automatically downloads and converts any Processing code to JavaScript. It does this using the Processing.compile() method, and those interested in building tools or utilities for Processing.js can do the same.

In order to obtain "compiled" code (i.e., JavaScript suitable for use by the Processing.js runtime) from Processing code, do the following:

// hard-coded Processing code, text from an HTML widget, downloaded text, etc.
var processingCode = "..."; 
var jsCode = Processing.compile(processingCode).sourceCode;

For example, converting the following Processing code produces the "compiled" JavaScript underneath:

// Processing code
void setup() {
  size(200, 200);
  background(100);
  stroke(255);
  ellipse(50, 50, 25, 25);
  println("hello web!");
}

// "Comiled" JavaScript code
// this code was autogenerated from PJS
(function(processing, $constants) {
    function setup() {
        processing.size(200, 200);
        processing.background(100);
        processing.stroke(255);
        processing.ellipse(50, 50, 25, 25);
        processing.println("hello web!");
    }
    processing.setup = setup;
})

Writing JavaScript-only Processing.js code

The previous method produced JavaScript code from Processing, but you can also write JavaScript on its own. The Processing.js parser turns Processing code into a JavaScript function, then runs it. As a result, it's possible to skip the Processing code altogether, and simply write a JavaScript function, passing this to your Processing instance. Here's an example:

function sketchProc(processing) {
  // Override draw function, by default it will be called 60 times per second
  processing.draw = function() {
    // determine center and max clock arm length
    var centerX = processing.width / 2, centerY = processing.height / 2;
    var maxArmLength = Math.min(centerX, centerY);

    function drawArm(position, lengthScale, weight) {
      processing.strokeWeight(weight);
      processing.line(centerX, centerY,
        centerX + Math.sin(position * 2 * Math.PI) * lengthScale * maxArmLength,
        centerY - Math.cos(position * 2 * Math.PI) * lengthScale * maxArmLength);
    }

    // erase background
    processing.background(224);

    var now = new Date();

    // Moving hours arm by small increments
    var hoursPosition = (now.getHours() % 12 + now.getMinutes() / 60) / 12;
    drawArm(hoursPosition, 0.5, 5);

    // Moving minutes arm by small increments
    var minutesPosition = (now.getMinutes() + now.getSeconds() / 60) / 60;
    drawArm(minutesPosition, 0.80, 3);

    // Moving hour arm by second increments
    var secondsPosition = now.getSeconds() / 60;
    drawArm(secondsPosition, 0.90, 1);
  };
}

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

Here a sketch function is created, similar to what the parser would produce. This function should take 1 argument, a reference to a processing object (i.e., the Processing runtime), which will be created by the Processing constructor. Any Processing functions or objects are accessible as properties of this object.

Once that function is complete, pass it, along with a reference to a canvas, to the Processing constructor (remember to use new).

Writing Documents that Combine Processing and JavaScript Code

One of the first questions people ask with Processing.js is whether they can read values from the document in which the Processing sketch is running, or vice versa. The answer is yes.

Processing.js converts Processing code into JavaScript contained in a function closure. The variables and functions you create are not attached to the global object (i.e., window). However, you can still get access to them.

Accessing JavaScript Objects from Processing

Since Processing code gets converted to JavaScript and run like any other function, all Processing code has access to the global object. This means that if you create a variable or function in a global script block, they are automatically accessible to Processing. Consider this example:

First the Processing file, mixing.pde:

String processingString = "Hello from Processing!";

void setup() {
  printMessage(jsString + " " + processingString);
}

Next the web page:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello Web - Accessing JavaScript from Processing</title>
    <script src="processing-0.9.7.min.js"></script>
  </head>
  <body>
    <div id="msg"></div>
    <canvas data-processing-sources="mixing.pde"></canvas>
    <script type="application/javascript">
      var jsString = "Hello from JavaScript!";
      var printMessage = function(msg) {
        document.getElementById('msg').innerHTML = "Message: " + msg;
      };
    </script>
  </body>
</html>

Here Processing.js allows the use of a variable and function declared outside the Processing code.

Mixing JavaScript and Processing

The previous example kept a clean separation between the JavaScript and Processing code, while loosening the boundary between the two. Because Processing.js converts Processing code to JavaScript, it's also possible to mix them directly. The Processing.js parser will leave JavaScript it finds within the Processing code unaltered, allowing developers to write a hybrid of Processing and JavaScript (NOTE: this is why we don't use a pure Processing parser approach in processing.js). Here is the previous example rewritten using this method:

var jsString = "Hello from JavaScript!";
var printMessage = function(msg) {
  document.getElementById('msg').innerHTML = "Message: " + msg;
};

String processingString = "Hello from Processing!";

void setup() {
  printMessage(jsString + " " + processingString);
}

There is some JavaScript syntax that can't be easily mixed this way (e.g., regex literals). In those cases you can simply move your pure JavaScript to a <script> block and access it using the method described above.

Accessing Processing from JavaScript

Reaching out from the Processing code to JavaScript is easier than going the other way, since the JavaScript created by the Processing.js parser is not exposed directly on the global object. Instead, you gain access using the Processing.instances property.

The Processing constructor keeps track of instances it creates, and makes them available using the getInstanceById() method. By default, when a <canvas> has a data-processing-sources attribute, its id is used as a unique identifier for the Processing instance. If no id attribute is provided, you can use Processing.instances[0].

After you have a reference to the appropriate Processing instance, you can call into it like so:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello Web - Controlling Processing from JavaScript</title>
    <script src="processing-0.9.7.min.js"></script>
  </head>
  <body>
    <canvas id="sketch" data-processing-sources="controlling.pde"></canvas>
    <button onclick="startSketch();">Start</button>
    <button onclick="stopSketch();">Stop</button>

    <script type="application/javascript">
      var processingInstance;

      function startSketch() {
        switchSketchState(true);
      }
      
      function stopSketch() {
        switchSketchState(false);
      }

      function switchSketchState(on) {
        if (!processingInstance) {
          processingInstance = Processing.getInstanceById('sketch');
        }

        if (on) {
          processingInstance.loop();  // call Processing loop() function
        } else {
         processingInstance.noLoop(); // stop animation, call noLoop()
        }
      }
    </script>
  </body>
</html>

Here two buttons in the DOM are used to allow the user to start or stop a running Processing sketch. They control the Processing instance (you might have several in a page, or hidden in divs) directly from JavaScript, calling Processing functions: loop() and noLoop(). The Processing functions are well documented elsewhere.

Things to Know as a JavaScript Developer using Processing.js

While Processing.js tries to be fully compatible with Processing, there are some things which are different or require workarounds. We have also added some web-specific features to make Processing.js easier to use. Here are some tricks and tips as you start working on more complex sketches in Processing.js.

Processing.js provides access to various DOM/JavaScript objects via the externals property

Each Processing instance (i.e., Processing.instances) has an externals property, which is an object containing references to various non-Processing DOM/JavaScript objects that can be useful. For example:

  • canvas - the canvas to which the sketch is bound
  • context - the canvas' context
  • onblur and onfocus - event handlers

Division which is expected to produce an integer might need explicit casting

There are a class of bugs that arise when converting Processing code to Processing.js that involve integer vs. floating point division. What was straight-up integer division in Processing code, when converted to JavaScript, can sometimes become problematic, as numbers become doubles, and introduce a fractional part. The fix is to explicitly cast any division to an integer that exhibits this behaviour:

// before
int g = mouseX / i;

// after
int g = (int)(mouseX / i);

See bug https://processing-js.lighthouseapp.com/projects/41284/tickets/532-drawing-artifacts-in-processingjs-not-in-processing-with-this-code

Processing.js has to cheat to simulate Processing's synchronous I/O

Processing uses a synchronous I/O model, which means that functions like loadImage() take time to execute, and while they are running, nothing else happens: the program waits until loadImage() is done before moving on to the next statement. This means that you can count on the value returned by a function like loadImage() being usable in the next line of code.

Obviously, JavaScript doesn't work like this. The web uses an asynchronous I/O model, which means that functions which load external resources can't make the program wait until they finish. In order to replicate Processing's load* functions, you have to use a special Processing.js Directive.

The Processing.js Directives are hints to the browser that are written in comments rather than in the Processing code itself. Here's a typical Processing sketch that loads an image synchronously and then draws it:

PImage img;

void setup() {
  img = loadImage("picture.jpg");
  image(img, 0, 0);
}

This code will not work in the browser with Processing.js, because the call to image() will happen before the file picture.jpg has been downloaded. The fix is to ask Processing.js to download the image before the sketch starts, and cache it--a technique known as preloading. Here is the modified code:

/* @pjs preload="picture.jpg"; */
PImage img;

void setup() {
  img = loadImage("picture.jpg");
  image(img, 0, 0);
}

Notice the extra comment line at the top of the code. The @pjs directive is for Processing.js, and not the developer. Think of it as an extra line of code that will be executed before the program begins.

If you have multiple images to load, use a list like so:

/* @pjs preload="picture.jpg,picture2.jpg,picture3.png"; */

Processing.js requires more care with variable naming than Processing

One of the powerful features of JavaScript is its dynamic, typeless nature. Where typed languages like Java, and therefore Processing, can reuse names without fear of ambiguity (e.g., method overloading), Processing.js cannot. Without getting into the inner-workings of JavaScript, the best advice for Processing developers is to not use function/class/etc. names from Processing as variable names. For example, a variable named line might seem reasonable, but it will cause issues with the similarly named line() function built-into Processing and Processing.js.

It is possible to put Processing code directly in your web page

Using the data-processing-sources attribute on the canvas, and having Processing.js load an external file is the preferred and recommended way to include scripts in a web page. However, it is also possible to write in-line Processing code.

A few changes are necessary to make the example above work with inline Processing code:

<script src="processing-0.9.7.min.js"></script>
<script type="application/javascript">
/*
 * This code searches for all the <script type="application/processing" target="canvasid">
 * in your page and loads each script in the target canvas with the proper id.
 * It is useful to smooth the process of adding Processing code in your page and starting
 * the Processing.js engine.
 */

if (window.addEventListener) {
  window.addEventListener("load", function() {
    var scripts = document.getElementsByTagName("script");
    var canvasArray = Array.prototype.slice.call(document.getElementsByTagName("canvas"));
    var canvas;
    for (var i = 0, j = 0; i < scripts.length; i++) {
      if (scripts[i].type == "application/processing") {
        var src = scripts[i].getAttribute("target");
        if (src && src.indexOf("#") > -1) {
          canvas = document.getElementById(src.substr(src.indexOf("#") + 1));
          if (canvas) {
            new Processing(canvas, scripts[i].text);
            for (var k = 0; k< canvasArray.length; k++)
            {
              if (canvasArray[k] === canvas) {
                // remove the canvas from the array so we dont override it in the else
                canvasArray.splice(k,1);
              }
            }
          }
        } else {    
          if (canvasArray.length >= j) {
            new Processing(canvasArray[j], scripts[i].text);          
          }
          j++;
        }       
      }
    }
  }, false);
}
</script>
<script type="application/processing" target="processing-canvas">
void setup() {
  size(200, 200);
  background(100);
  stroke(255);
  ellipse(50, 50, 25, 25);
  println('hello web!');
}
</script>
<canvas id="processing-canvas"></canvas>

This code is more complex because it has to figure out which canvas goes with which script (i.e., you can have multiple Processing sketches living in the same page, and therefore, multiple canvases). Also note that the scripts include a type attribute, which distinguishes between JavaScript and Processing code (the browser will ignore Processing scripts). Finally, note the use of the id and target attributes to connect the Processing script with the associated canvas.

Portions of the code above are from the Processing.js project's init.js file, see http://github.com/annasob/processing-js/blob/0.9.8/examples/init.js. This file will likely be going away in the future, and happen automatically as part of Processing.js initialization.