This page tries to explain how to quickly and (as) correctly (as possible) use
Processing sketches on webpages. The information is based on the work done by
the processing.js group.
This information on this page reflects the best of my knowledge anno November
2010, and processing.js becomes more and more complete, so it is possible that the
information on this page changes over time. Should you spot any incompletenesses
or blatant mistakes, please contact me at
pomax at
nihongoresources.com,
with the obvious substitutions in place to make it a legal email address.
What is Processing?
The "Processing" language (also referred to as "P5") is a programming language
with a focus on data visualisation. Of course, "data" is a loose concept, and
Processing can be used for anything from drawing a few lines and circles on a
screen, to full blown interactive animations. In fact, a basic Processing program
is two lines of code, and will already play an animation:
Of course this program doesn't show you anything, because all it does is set up
the visual context to have a certain width and height (indicated in the setup
method as the size(...,...) instruction) and then calls draw() every few milliseconds.
Of course, draw() is empty, so it won't actually show you anything. A more useful
minimal program would be a "hello world" program, but I hate those because they only
show a programming language can write text, and that's pretty much the least interesting
feature of any programming language. Instead let's look at a minimal program that makes
sense for a data visualisation language:
1 float framerate = 24; // our "sketch" will have a framerate of 24 frames per second.
2
3 int ball_x; // ball administration: x coordinate
4 int ball_y; // ball administration: y coordinate
5 int ball_radius = 20; // ball administration: ball radius
6
7 void setup() {
8 size(200,200); // set draw area size
9 frameRate(framerate); // set animation framerate
10 ball_x = width/2; // set the initial ball coordinates
11 ball_y = ball_radius; // set the initial ball coordinates
12 stroke(#003300); // set the default shape outline colour
13 fill(#0000FF); // set the default shape fill colour
14 }
15
16 void draw() {
17 // compute the ball height for this frame
18 float bounce_height = height/2 * abs(sin(PI*frameCount/framerate));
19 // because the top of the screen is 0, and the bottom is "height",
20 float ball_height = height - (bounce_height+ball_radius);
21 // clear the drawing area
22 background(#FFFFEE);
23 // set the new ball y position
24 ball_y = (int) (ball_height);
25 // draw the ball
26 ellipse(ball_x,ball_y,ball_radius,ball_radius);
27 }
play controls:
This looks a bit long for a minimal program, but then again, this actually does
something: it shows us a ball that bounces up and down, taking one second for each
bounce. It shows a few aspects of Processing too: every variable is strongly typed.
So you have to indicate what you'll be using a variable for, and you can choose from:
boolean, a binary value that can be either true or false
byte, an 8-bit value
char, a byte representing an ascii character
color, a type specific to Processing, representing an on-screen color
int, a 32 bit signed integer number
long, a 64 bit signed integer number
float, a 32 bit signed decimal number
double, a 64 bit signed decimal number
And of course there are also the typical complex data types:
Object, a catch-all data type for things that are complex data types.
String, a text string (stored as UTF-16).
ArrayList, a list structure for arbitrary values with add/remove functionality.
HashMap, a structure that can store {, } pairs.
XMLElement, a convenient XML-mirroring object.
You'll see why this last one turns out to be really useful later on.
Coming back to the minimally functional example of a Processing program, or "sketch",
there are also some examples of Processing' own API at work. The following methods are
native Processing calls:
size(int, int), sets the drawing area dimensions, and the global "width" and "height" values.
frameRate(int), sets the refresh rate for the drawing area, and the frameRate value.
stroke(color), sets the shape outline color.
fill(color), sets the shape fill color.
abs(number), computes the absolute value of any number.
sin(number), computes the sinoid value based on any number (treated as radians).
background(color), sets every pixel of the drawing area to the specified color.
ellipse(int, int, int, int), draws an ellipse on the drawing area.
The Processing API is in fact quite expansive (See
http:///reference for the full
list), but it can't cover everything. Luckily it supports object oriented programming, so
that our previous example can also be written as an object oriented sketch:
Instead of doing everything in the draw() function, the object oriented approach
tucks all the code that relates to computing the ball's position in the definition
for what we consider a "Ball". To be good object oriented programmers, we've also said
that things that are a Ball are also a Bouncer, and this lets us extend our sketch very
easily to instead of a bouncing ball, have a bouncing box by keeping almost everything
the same, and adding a new class Box that's a Bouncer:
All of a sudden we have a bouncing box, that starts from a falling position instead
of from the ground, and we didn't have to modify the master draw() function for it!
In fact, let's just use a group of bouncing things:
Fantastic, two bouncing balls and a bouncing box, bouncing counter-point to each
other. But it's not very interactive yet. Let's change it so that we can "hang on"
to bouncing things until we let go of them again. Processing allows interaction with
the keyboard and mouse, using what are known as "event handlers", methods that Processing
automatically calls for you when you use the keyboard or mouse. In this case we care
about mouse interaction, so we'll look at mousePressed and mouseReleased events:
Because the Ball and Box classes will do the same thing on mouse interaction,
the interface Bouncer has been changed to an actual class too, to take care of some of
the shared functionality. Now if you click on anything that's a Bouncer it'll stop
moving until you let it go. Let's go one step further an just allow us to move the
bouncing things around, too.
And with that, on to the original topic of this article: using Processing on web pages
Putting a sketch on the page
The great thing about Processing is that it can be used on webpages. Traditionally,
you would convert your sketch to a java applet, and embed that on a page, but the
processing.js project has changed this: you can now use your sketches directly without
turning it into an applet at all. In the same way that you include a javascript file,
or a CSS stylesheet, you can simply link to your sketch and magic happens.
Let's say we save the previous sketch, with the bouncing and the mouse interaction,
as "mysketch.pde", and we want to show this on a webpage. Using processing.js, this is
a trivially simple trick:
And we're done. In fact, I went ahead and made sure this page already uses processing.js,
and that there is a mysketch.pde to load. If you click on the play control for the sketch
above, it will start running, and do exactly what you would expect it to do based on what
it does when you run it from the Processing environment.
Putting a sketch inline on the page
While not recommended, you can also put your sketch directly on a page, much like how
you can put javascript or CSS styles directly on a page. However, in order for processing.js
to properly load your code, you'll need some extra help in the form of the "init.js" file
that is included with the processing.js examples archive from the processing.js downloads page
There are several reasons for why this is not a very good practice, but the most important
one is that this way you can't be sure whether or not you've written a bug-free sketch. By
writing it directly on the page, you might in fact have written some buggy code, which you
will then find is terribly hard to debug because the browser is not equiped with a debugger
for Processing code. In fact, processing.js rewrites your sketch into pure javascript (using
some terribly clever tricks that we won't go into), so even if when it tells you where the
error is in a javascript debugger, it will tell you where it went wrong in the converted
javascript object, not the actual place in your source code. So keep it as a separate file,
and make sure to test your code in the Processing IDE!
Making your sketch and your page see each other
Just running a sketch on a page is fine, but the benefit of a webpage is that it offers
the kind of user interaction that you can't get from within the sketch itself. Pretty buttons,
text areas that fold away, pop up, etc. make it very attractive to have your sketch do all
the animation graphicsy work, but have all the information about the sketch, as well as
controls for it, on the webpage. This is entirely possible - in fact, the "stop" and "play"
buttons for the sketch above are examples of javascript telling the sketch what to do. Because
a webpage offers more than a plain sketch can, processing.js has a few special tricks up its
sleeve, so that you can get the most out of your creative work. Arguably the most important of
these is the "get the sketch" function:
1 var mysketch = Processing.getInstanceById('mysketchid');
This is the pivotal function on the javascript side of things. It gives you a direct reference
to your sketch, and everything in it, so that you can call any function and examine and modify
any variable that is in the sketch.
Making javascript see your sketch
Let's say we have the following sketch:
1 void setup() {
2 size(200,200);
3 noLoop(); // turn off animation, since we won't need it
4 stroke(#FFEE88);
5 fill(#FFEE88);
6 background(#000033);
7 text("",0,0); // force Processing to load a font
8 textSize(24); // set the font size to something big
9 }
10
11 void draw() { }
12
13 void drawText(String t)
14 {
15 background(#000033);
16 // get the width for the text
17 float twidth = textWidth(t);
18 // place the text centered on the drawing area
19 text(t, (width - twidth)/2, height/2);
20 }
We can make this sketch draw a different text based on some text we have on our webpage,
using javascript. This is in fact really easy: first, let's save this processing code as
mysketch2.pde, and load it onto a page in the same way as earlier in the article. Then, we
use javascript to ask for our sketch instance, after which we call the "drawText" function
with some text that we get from the web page that the sketch is running on:
This has the same effect as the sketch that's running below. Simply fill in a bit
of text, and hit the ? button to see the sketch render it on the drawing area.
set text:
So far so good, but what if we also want to make Processing code call javascript?
In order for us to so, while making sure the sketch keeps running both on your page an
in the Processing environment, we have to do a bit more work
Making your sketch "see" javascript
You can't just stick plain javascript in your sketch and hope everything goes well
because it's "on a web page". A better approach is to neatly separate your sketch and
your on-page javascript, and ensure that whatever you want to do on your page runs
through a javascript function. How do we do that? Let's say we have the following page:
As an exercise, let's try to get the mouse coordinates from that mouseMoved event
onto the page. This means we'll need to define a javascript function that will do this for us:
What we've done is we've told Processing: "There are things that follow the
JavaScript interface. This means that whatever else they can do, they'll have a
function called "showXYCoordinates" and that function takes two arguments, both of type int."
- of course, the sketch will not magically know our on-page javascript, so we also
define a function that lets us tell the sketch what actually counts as javascript,
which is what the bindJavascript(...) function is for.
This leaves us with needing to make sure that we really do tell the sketch what
Javascript is, which we'll do as follows on the page:
This defines a function that checks whether processing.js has loaded our sketch yet.
If not, it tries again 250ms later. If the sketch is loaded, the reference to the sketch
is used to tell it what "javascript" should be. This is achieved by virtue of processing.js
trusting that you wrote valid code. As such, as long as you're on the javascript side of
things, you can pass the sketch whatever you like, and the sketch will trust that it conforms
to what the method says the type should be. In this case we pass the javascript "this" value
(which refers to the global javascript environment for the current window), and tell processing
"this thing conforms to your JavaScript interface, so it has loads of things but the only
thing you need to be concerned about is whether or not it has a showXYCoordinates(int, int)
function, which it does."
So, our final sketch behaves like the sketch below, and our final page source looks like the following:
Passing complex objects from javascript to your sketch
This leaves us with one last topic that we need to cover, simply because it's so common:
using an AJAX approach to get some data, and then passing that data, properly formatted, to your sketch.
Actually using Processing objects
One interesting thing that processing.js allows us to do is to create objects as we defined them in
our sketch, in javascript, and then hand them over to the sketch to deal with. To give an example, let's
use the following sketch, which lets you draw points by clicking with the mouse, and links up all the
points with lines:
Because processing.js turns the sketch into actual javascript, every class we defined in it
can be created using new pjs.ClassName(arguments,...).
JSON
Another way to get data from javascript into a sketch is by way of a JSON description. JSON
is particulary interesting because javascript can read a JSON text string and immediately turn
it into a full-fledged javascript object. Let's look at our point-drawing sketch again, this
time with a dedicated "addPoint" method:
1 ArrayList points;
2
3 void setup() {
4 size(200,200);
5 points = new ArrayList();
6 }
7
8 void draw() {
9 background(200,200,255);
10 for(int p=0, end=points.size(); p<end; p++) {
11 Point pt = (Point) points.get(p);
12 if(p<end-1) {
13 Point next = (Point) points.get(p+1);
14 line(pt.x,pt.y,next.x,next.y); }
15 pt.draw(); }
16 }
17
18 void mouseClicked() {
19 addPoint(mouseX,mouseY);
20 }
21
22 Point addPoint(int x, int y) {
23 Point pt = new Point(x,y);
24 points.add(pt);
25 return pt;
26 }
27
28 class Point {
29 int x,y;
30 Point(int x, int y) { this.x=x; this.y=y; }
31 void draw() {
32 stroke(255,0,0);
33 fill(255);
34 ellipse(x,y,10,10);
35 }
36 }
Now what if -- instead of using mouse clicks, or predetermined javascript -- we want to
load points based on some data on a remote server? We change our web page so that it can deal
with JSON data from a remote server, and then make our javascript tell the sketch what to do:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>My Processing Page</title>
6 <script type="text/javascript" src="jquery.js"></script>
7 <script type="text/javascript" src="processing.js"></script>
8 <script type="text/javascript">
9 function drawPoints(id) {
10 var pjs = Processing.getInstanceById(id);
11 var json = $.get("http:///serving/json.asp");
12 var data = eval("("+json+")");
13 if(data) {
14 // we know the JSON is an array of points, called "points"
15 for(p=0, end=data.points.length; p<end; p++) {
16 var point = data.points[p];
17 pjs.addPoint(point.x, point.y);
18 }
19 }
20 }
21 </script>
22 </head>
23 <body>
24 <canvas id="mysketch5" data-processing-sources="mysketch5.pde"></canvas>
25 <div id="controller"><button type="button" id="loadPoints" onclick="loadPoints('mysketch5')"></div>
26 </body>
27 </html>
load points:
The JSON that gets loaded in the example sketch in this section is the following:
Another favourite is the XML document. This is where the Processing data type "XMLElement"
comes into play. Rather than trying to use javascript to parse the XML, we pass the xml data
straight on to our sketch, which will know exactly what to do with it:
load points:
1 function loadPoints(id, button) {
2 button.disabled = "disabled";
3 var pjs = Processing.getInstanceById(id);
4 var xml = $.get("http:///serving/getxml.php");
5 pjs.buildFromXML(xml);
6 }
And the handling in our sketch will look like this:
1 void buildFromXML(String xml) {
2 XMLElement data = new XMLElement(xml);
3 XMLElement[] xmlpoints = data.getChildren();
4 for(int p=0, end=xmlpoints.length; p<end; p++) {
5 XMLElement xmlpoint = xmlpoints[p];
6 int x = xmlpoint.getIntAttribute("x");
7 int y = xmlpoint.getIntAttribute("y");
8 points.add(new Point(x, y));
9 }
10 redraw();
11 }
If the xml thus loaded looks like the following snippet, the sketch will behave in
the way the sketch below does:
A special kind of XML document is the SVG Scalable Vector Graphics document. What's
special about it is that it already represents visual data, and Processing can load SVG
XML natively.
This sketch will load the following SVG code, and allows you to click on the shape to
change its color, or click-drag it to move it around:
1 <svg width='200' height='200'>
2 <path d='M 10 10 L 190 10 L 140 100 L 190 190 L 10 190 L 50 100 L 10 10 M 100 80 L 140 30 L 50 30 L 100 80 M 100 120 L 50 170 L 140 170 Z'/>
3 </svg>
Javascript Objects
One last thing you may want to pass to a sketch is a real javascript object. Say we have
a physics library that we want to take advantage of in our sketch, and for Processing it's a
.jar file, but there's a javascript version too. This thing lets us create a javascript "Physics"
object that we can call functions on for computing momentum and force transfer when we make
two things hit each other. Since processing.js does not support .jar libraries (because it's
precompiled binary java class code, and pjs cannot unpack a jar file, reverse engineer the
.java source, transform it to Processing API calls, then confirm all calls are supported) we'll
use this convenient javascript library. But how to do this cleanly?
We have to do three things:
Write an interface for the object we're using, so our sketch will know what it even is,
use a javascript binding so that we can ask javascript to make these objects for us, and
write a javascript function to make these objects for us.
So let's get cracking! First we determine which functions in the javascript Physics object
we actually make use of. We could write an interface that has correct method signatures for
every function in the library, but this would be overkill. After reviewing our code we see
that we actually only make use of three of the objects functions: collide_objects(forcevector1,
forcevector2, collisionangle), get_force_vector(startpoint, distancevector, accelleration) and
get_trajectory(startpoint, objectmass, initialvector, gravityvector, gravitystrength).
Let's build our interface:
1 interface Physics
2 {
3 // collision modifies the two force vectors in place. Nothing is returned.
4 void collide_objects(float[] forcevector1, float[] forcevector2, float collisionangle);
5
6 // get force vector returns a force vector
7 float[] get_force_vector(float[] startpoint, float[] distancevector, float accelleration);
8
9 // trajectory calculation returns a curve, represented as a lest of 2D coordinates
10 float[][] get_trajectory(float[] startpoint, float objectmass, float[] initialvector, float[] gravityvector, float gravitystrength);
11 }
First job done. Now to bind javascript. We've already looked at how to do this, so just follow
the standard procedure and job's a good'n. In addition to whatever javascript functions you want
to expose, however, we must add one more:
1 interface JavaScript {
2 ...
3 Physics buildPhysicsObject([properly typed variables to match the javascript constructor]);
4 ...
5 }
Finally, we now make use of our purely javascript library in our js file(s):
1 function buildPhysicsObject(x, y, someothervar)
2 {
3 return new Physics(x,y,someothervar);
4 }
This last step seems silly, but we have to delegate the task of building a javascript object
to javascript. If we tried to do this inside our sketch, processing.js will not complain, but
Processing will. To make matters worse, it also obscures the point of failure: if something
goes wrong in the sketch, did it go wrong because processing.js has a bug, or because you were
sloppy with javascript inside a Processing sketch? Golden rule: keep the different languages
separated as much as possible.
We're almost set to use our javascript library for Processing purposes now. The only thing
left is to create these objects and then use them in our sketch:
1 class MassBody
2 {
3 // a class for bodies with mass that travel with some speed and are located at some x/y position
4 float[] forceVector = new float[2]; // 2 dimensional vector;
5 int XDIM = 0; // index constant
6 int YDIM = 1; // index constant
7 float x = 0; // position
8 float y = 0; // position
9 MassBody(float x, float y) { forceVector[XDIM] = 0; forceVector[YDIM] = 0; this.x=x; this.y=y; }
10 void draw() { /* draws the body */ }
11 float[] getForce() { return forceVector; }
12 void impartForce(float[] stimulus) { forceVector[XDIM] += stimulus[XDIM]; forceVector[YDIM] += stimulus[YDIM]; }
13 void updatePosition() { x+=...; y+=...; }
14 }
15
16 MassBody body1 = new MassBody(...);
17 MassBody body2 = new MassBody(...);
18
19 Phsyics physicsObject
20
21 void bindJavascript(JavaScript js) {
22 javascript = js;
23 int x = 0;
24 float y = 9;
25 String[] somevalues = {"scalar", "vector", "tensor"};
26 physicsObject = javascript.buildPhysicsObject(x,y,somevalues);
27 }
28
29 void setup()
30 {
31 ...
32 }
33
34 void draw()
35 {
36 // if the two bodies collide, compute the resultant forces
37 if(body1.collides(body2))
38 {
39 // forces are recomputed in place
40 float angle_12 = body1.getAngleTo(body2);
41 physicsObject.collide_objects(body1.getForce(), body2.getForce(), angle_12);
42 body1.updatePosition();
43 body2.updatePosition();
44 }
45 body1.draw();
46 body2.draw();
47 }
And we're done!
Processing.js as javascript graphics library
As last point of business, you can of course also use Processing.js as a pure graphics
library, by invoking it for some canvas and then calling Processing API calls directly. Let's
jump right in! The following code is what you would write on-page, although of course as ever
it's far better practice to link to your source files, so you should really place what's in
the script tags in a file myPjsSketch.js and link to it using src="..." instead.
The following code is split up into multiple (numbered) sections.
First, bind a new Processing instance to the indicated canvas.
1 <canvas id="glibcanvas"></canvas>
2 <script type="text/javascript">
3 (function() {
4 var canvas = document.getElementById('glibcanvas');
5 var pjs = new Processing(canvas);
The setup() function defines the entry point for our sketch. It sizes the canvas, and
tells it not to animate by default.
1 // let's write a sketch
2 var value = 0;
3 // Definition for the initial entry point
4 pjs.setup = function() {
5 pjs.size(200,200);
6 // we want to turn off animation, because this is a demo page and it
7 // would use cpu while not being looked at. Only draw on mousemoves
8 pjs.noLoop();
9 }
The draw() function defines the main draw function, which is called whenever a frame
update is requested (either because the sketch is looping, or because redraw() is called manually)
1 // Draw a "sine wave" using two bezier curves, with an undulating amplitude.
2 pjs.draw = function() {
3 // partially clear, by overlaying a semi-transparent rect
4 // with background color
5 pjs.noStroke();
6 pjs.fill(255,75);
7 pjs.rect(0,0,200,200);
8 // draw the "sine wave"
9 pjs.stroke(100,100,200);
10 pjs.noFill();
11 pjs.bezier(0,100, 33,100+value, 66,100+value, 100,100);
12 pjs.bezier(100,100, 133,100+-value, 166,100+-value, 200,100);
13 }
The mouseMoved() function is a Processing event handler that is triggered by the
mouse moving around over the canvas. It is far more convenient to
use the built-in event handler than to write our own.
This is all we need in our sketch, so there's only one call left to make:
1 // Finally, calling setup() will kickstart the sketch
2 pjs.setup();
3 }());
4 </script>
So let's see that in action - the code that we just ran through is supposed to draw
a sinewave, with an amplitude that depends on where the mouse is on the canvas. If all
went well, it will look like this: