a port of the Processing Visualization Language

Pomax's guide to Processing.js

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:

1   void setup() { size(..., ...); }
2   void draw() {}

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://processing.org/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:

 1   Bouncer bouncer;
 2 
 3   void setup() {
 4     size(200,200);
 5     frameRate(24);
 6     stroke(#003300);
 7     fill(#0000FF);
 8     bouncer = new Ball(width/2,20,20);
 9   }
10 
11   void draw() {
12     bouncer.computeNextStep(width, height, frameRate);
13     background(#FFFFEE);
14     bouncer.draw();
15   }
16 
17   interface Bouncer {
18     void computeNextStep(int width, int height, float framerate);
19     void draw();
20   }
21 
22   class Ball implements Bouncer
23   {
24     int x,y,radius;
25     int step = 0;
26 
27     Ball(int x, int y, int r) {
28       this.x = x;
29       this.y = y;
30       this.radius = r;
31     }
32 
33     void computeNextStep(int sketch_width, int sketch_height, float frame_rate) {
34       step++;
35       float sin_value = abs(sin(PI*step/(float)frame_rate));
36       float bounce_height = sketch_height/2 * sin_value;
37       float ball_height = sketch_height - (bounce_height + radius);
38       y = (int) (ball_height);
39     }
40 
41     void draw() {
42       ellipse(x,y,radius,radius);
43     }
44   }
play controls:

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:

 1   void setup() {
 2     ...
 3     bouncer = new Box(width/2,20,20,20);
 4   }
 5 
 6   class Box implements Bouncer
 7   {
 8     int x,y,w,h;
 9     int step=0;
10 
11     Box(int x, int y, int w, int h) {
12     this.x = x;
13     this.y = y;
14     this.w = w;
15     this.h = h;
16   }
17 
18   void computeNextStep(int sketch_width, int sketch_height, float frame_rate) {
19     step++;
20     float sin_value = abs(sin(PI/2.0 + (PI*step/(float)frame_rate)));
21     float bounce_height = sketch_height/2 * sin_value;
22     float ball_height = sketch_height - (bounce_height + h);
23     y = (int) (ball_height);
24   }
25 
26   void draw() {
27     rect(x,y,w,h);
28   }
play controls:

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:

 1   Bouncer[] bouncer = new Bouncer[3];
 2 
 3   void setup() {
 4     ...
 5     bouncer[0] = new Ball(width/3-20,20,20);
 6     bouncer[1] = new Box(width/2-10,20,20,20);
 7     bouncer[2] = new Ball((2*width/3)+20,20,20);
 8   }
 9 
10   void draw() {
11     for(int b=0, end=bouncer.length; b<end;b++) {
12       bouncer[b].computeNextStep(width, height, frameRate);
13     }
14     background(#FFFFEE);
15     for(int b=0, end=bouncer.length; b<end;b++) {
16       bouncer[b].draw();
17     }
18   }
19   ...
play controls:

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:

 1   void mousePressed() {
 2     for(int b=0, end=bouncer.length; b<end;b++) {
 3       if(bouncer[b].mouseOver(mouseX, mouseY)) {
 4         bouncer[b].mousePressed();
 5       }
 6     }
 7   }
 8 
 9   void mouseReleased() {
10     for(int b=0, end=bouncer.length; b<end;b++) {
11       bouncer[b].mouseReleased();
12     }
13   }
14 
15   abstract class Bouncer
16   {
17     int x, y;
18     boolean canmove = true;
19     int step = 0;
20     abstract void computeNextStep(int width, int height, float framerate);
21     abstract void draw();
22     abstract boolean mouseOver(int mx, int my);
23     void mousePressed() { canmove = false; }
24     void mouseReleased() { canmove = true; }
25   }
26 
27   class Ball extends Bouncer
28   {
29     int radius;
30 
31     Ball(int x, int y, int r) {
32       this.x = x;
33       this.y = y;
34       this.radius = r;
35     }
36     void computeNextStep(int sketch_width, int sketch_height, float frame_rate) {
37     if(canmove) {
38       step = (int)((step+1) % frame_rate);
39       float sin_value = abs(sin(PI*step/(float)frame_rate));
40       float bounce_height = sketch_height/2 * sin_value;
41       float ball_height = sketch_height - (bounce_height + radius);
42       y = (int) (ball_height);
43     }
44   }
45 
46   void draw() { ellipse(x,y,radius,radius); }
47 
48   boolean mouseOver(int mx, int my) {
49     return sqrt((x-mx)*(x-mx) + (y-my)*(y-my)) <= radius;
50   }
51 
52   class Box extends Bouncer
53   {
54     int w,h;
55     int step=0;
56 
57     Box(int x, int y, int w, int h) {
58       this.x = x;
59       this.y = y;
60       this.w = w;
61       this.h = h;
62     }
63 
64     void computeNextStep(int sketch_width, int sketch_height, float frame_rate) {
65       if(canmove) {
66         step = (int)((step+1) % frame_rate);
67         float sin_value = abs(sin(PI/2.0 + (PI*step/(float)frame_rate)));
68         float bounce_height = sketch_height/2 * sin_value;
69         float ball_height = sketch_height - (bounce_height + h);
70         y = (int) (ball_height);
71       }
72     }
73 
74     void draw() { rect(x,y-h/2,w,h); }
75 
76     boolean mouseOver(int mx, int my) {
77       return x<=mx && mx<=x+w && (y-h/2)<=my && my<=(y+h/2);
78     }
79   }
play controls:

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.

  1   Bouncer[] bouncer = new Bouncer[3];
  2 
  3   void setup() {
  4     size(200,200);
  5     frameRate(24);
  6     stroke(#003300);
  7     fill(#0000FF);
  8     bouncer[0] = new Ball(width/3-20,20,20);
  9     bouncer[1] = new Box(width/2-10,20,20,20);
 10     bouncer[2] = new Ball((2*width/3)+20,20,20);
 11   }
 12 
 13   void draw() {
 14     for(int b=0, end=bouncer.length; b<end;b++) {
 15       bouncer[b].computeNextStep(width, height, frameRate);
 16     }
 17     background(#FFFFEE);
 18     for(int b=0, end=bouncer.length; b<end;b++) {
 19       bouncer[b].draw();
 20     }
 21   }
 22 
 23   void mousePressed() {
 24     for(int b=0, end=bouncer.length; b<end;b++) {
 25       if(bouncer[b].mouseOver(mouseX, mouseY)) {
 26         bouncer[b].mousePressed();
 27       }
 28     }
 29   }
 30 
 31   void mouseReleased() {
 32     for(int b=0, end=bouncer.length; b<end;b++) {
 33       bouncer[b].mouseReleased();
 34     }
 35   }
 36 
 37   void mouseDragged() {
 38     for(int b=0, end=bouncer.length; b<end;b++) {
 39       bouncer[b].mouseDragged(mouseX, mouseY);
 40     }
 41   }
 42 
 43   abstract class Bouncer
 44   {
 45     int x, y;
 46     boolean canmove = true;
 47     int step = 0;
 48     int xoffset = 0;
 49     int yoffset = 0;
 50 
 51     void computeNextStep(int width, int height, float framerate) {
 52       if(canmove) {
 53         reallyComputeNextStep(width, height, framerate);
 54       }
 55     }
 56 
 57     abstract void reallyComputeNextStep(int width, int height, float framerate);
 58 
 59     abstract void draw();
 60 
 61     abstract boolean mouseOver(int mx, int my);
 62 
 63     void mousePressed() {
 64       canmove = false;
 65     }
 66 
 67     void mouseReleased() {
 68       canmove = true;
 69       x += xoffset;
 70       y += yoffset;
 71       xoffset = 0;
 72       yoffset = 0;
 73     }
 74 
 75     void mouseDragged(int mx, int my) {
 76       if(!canmove) {
 77         xoffset = mx-x;
 78         yoffset = my-y;
 79       }
 80     }
 81   }
 82 
 83   class Ball extends Bouncer
 84   {
 85     int radius;
 86 
 87     Ball(int x, int y, int r) {
 88       this.x = x;
 89       this.y = y;
 90       this.radius = r;
 91     }
 92 
 93     void reallyComputeNextStep(int sketch_width, int sketch_height, float frame_rate) {
 94       step = (int)((step+1) % frame_rate);
 95       float sin_value = abs(sin(PI*step/(float)frame_rate));
 96       float bounce_height = sketch_height/2 * sin_value;
 97       float ball_height = sketch_height - (bounce_height + radius);
 98       y = (int) (ball_height);
 99     }
100 
101     void draw() { ellipse(x+xoffset,y+yoffset,radius,radius); }
102 
103     boolean mouseOver(int mx, int my) {
104       return sqrt((x-mx)*(x-mx) + (y-my)*(y-my)) <= radius;
105     }
106   }
107 
108   class Box extends Bouncer
109   {
110     int w,h;
111     int step=0;
112 
113     Box(int x, int y, int w, int h) {
114       this.x = x;
115       this.y = y;
116       this.w = w;
117       this.h = h;
118     }
119 
120     void reallyComputeNextStep(int sketch_width, int sketch_height, float frame_rate) {
121       step = (int)((step+1) % frame_rate);
122       float sin_value = abs(sin(PI/2.0 + (PI*step/(float)frame_rate)));
123       float bounce_height = sketch_height/2 * sin_value;
124       float ball_height = sketch_height - (bounce_height + h);
125       y = (int) (ball_height);
126     }
127 
128     void draw() { rect(x+xoffset,(y-h/2)+yoffset,w,h); }
129 
130     boolean mouseOver(int mx, int my) {
131       return x<=mx && mx<=x+w && (y-h/2)<=my && my<=(y+h/2);
132     }
133   }
play controls:

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:

 1   <!DOCTYPE html>
 2   <html>
 3     <head>
 4       <meta charset="utf-8">
 5       <title>My Processing Page</title>
 6       <script type="text/javascript" src="processing.js"></script>
 7     </head>
 8     <body>
 9       <canvas id="mysketch" data-processing-sources="mysketch.pde"></canvas>
10     </body>
11   </html>
play controls:

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

 1   <!DOCTYPE html>
 2   <html>
 3     <head>
 4       <meta charset="utf-8">
 5       <title>My Processing Page</title>
 6       <script type="text/javascript" src="processing.js"></script>
 7     </head>
 8     <body>
 9       <script type="application/processing" target="mysketch">
10       void setup() { ... }
11       void draw() { ... }
12       class SomeClass {
13         ...
14       }
15       </script>
16       <canvas id="mysketch"></canvas>
17     </body>
18   </html>

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:

 1   <!DOCTYPE html>
 2   <html>
 3     <head>
 4       <meta charset="utf-8">
 5       <title>My Processing Page</title>
 6       <script type="text/javascript" src="processing.js"></script>
 7       <script type="text/javascript">
 8       function drawSomeText(id) {
 9         var pjs = Processing.getInstanceById(id);
10         var text = document.getElementById('inputtext').value;
11         pjs.drawText(text); }
12       </script>
13     </head>
14     <body>
15       <canvas id="mysketch2" data-processing-sources="mysketch2.pde"></canvas>
16       <input type="textfield" value="my text" id="inputtext">
17       <button type="button" onclick="drawSomeText('mysketch2')">place</button>
18     </body>
19   </html>

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:

 1   <!DOCTYPE html>
 2   <html>
 3     <head>
 4       <meta charset="utf-8">
 5       <title>My Processing Page</title>
 6       <script type="text/javascript" src="processing.js"></script>
 7     </head>
 8     <body>
 9       <canvas id="mysketch3" data-processing-sources="mysketch3.pde"></canvas>
10       <div id="coordinates">
11         x/y: <input type="textfield" id="xcoord">/<input type="textfield" id="ycoord">
12       </div>
13     </body>
14   </html>

And say we have the following sketch, which we'll save as mysketch3.pde:

 1   void setup() {
 2     size(200,200);
 3     stroke(255);
 4     background(0);
 5     noLoop();
 6   }
 7 
 8   void draw() {
 9     fill(0,0,0,40);
10     rect(-1,-1,width+2,height+2);
11   }
12   void mouseMoved() {
13     line(mouseX,0,mouseX,height);
14     line(0,mouseY,width,mouseY);
15     redraw();
16   }

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:

1   function showXYCoordinates(x, y) {
2     document.getElementById('xcoord').value = x;
3     document.getElementById('ycoord').value = x;
4   }

And we'll need to make the sketch know that there is such a thing as javascript, and that it has this function:

 1   interface JavaScript {
 2     void showXYCoordinates(int x, int y);
 3   }
 4 
 5   void bindJavascript(JavaScript js) {
 6     javascript = js;
 7   }
 8 
 9   JavaScript javascript;
10 
11   void setup() { ...}
12   void draw() { ... }
13   void mouseMoved() {
14     ...
15     if(javascript!=null){
16       javascript.showXYCoordinates(mouseX, mouseY);
17     }
18   }

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:

 1   var bound = false;
 2 
 3   function bindJavascript() {
 4     var pjs = Processing.getInstanceById('mysketch3');
 5     if(pjs!=null) {
 6       pjs.bindJavascript(this);
 7       bound = true;
 8     }
 9     if(!bound) setTimeout(bindJavascript, 250);
10   }
11 
12   bindJavascript();

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:

 1   <!DOCTYPE html>
 2   <html>
 3     <head>
 4       <meta charset="utf-8">
 5       <title>My Processing Page</title>
 6       <script type="text/javascript" src="processing.js"></script>
 7       <script type="text/javascript">
 8       var bound = false;
 9 
10       function bindJavascript() {
11         var pjs = Processing.getInstanceById('mysketch3');
12         if(pjs!=null) {
13           pjs.bindJavascript(this);
14           bound = true; }
15         if(!bound) setTimeout(bindJavascript, 250);
16       }
17       bindJavascript();
18 
19       function showXYCoordinates(x, y) {
20         document.getElementById('xcoord').value = x;
21         document.getElementById('ycoord').value = y;
22       }
23       </script>
24     </head>
25     <body>
26       <canvas id="mysketch3" data-processing-sources="mysketch3.pde"></canvas>
27       <div id="coordinates">
28         x/y: <input type="textfield" id="xcoord">/<input type="textfield" id="ycoord">
29       </div>
30     </body>
31   </html>
x/y coordinates: /

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:

 1   ArrayList points;
 2 
 3   ArrayList getPoints() { return points; }
 4 
 5   void setup() {
 6     size(200,200);
 7     points = new ArrayList();
 8     noLoop();
 9     stroke(255,0,0);
10     fill(255);
11   }
12 
13   void draw() {
14     background(200,200,255);
15     for(int p=0, end=points.size(); p < end; p++) {
16       Point pt = (Point) points.get(p);
17       if(p < end-1) {
18       Point next = (Point) points.get(p+1);
19       line(pt.x,pt.y,next.x,next.y); }
20       pt.draw(); }
21   }
22 
23   void mouseClicked() {
24     points.add(new Point(mouseX,mouseY));
25     redraw();
26   }
27 
28   class Point {
29     int x,y;
30     Point(int x, int y) { this.x=x; this.y=y; }
31     void draw() { ellipse(x,y,10,10); }
32   }
click to place points

We can also make javascript place some points for us, automatically, by using the following javascript:

1   function loadPoints(id, button) {
2     var pjs = Processing.getInstanceById(id);
3     var points = pjs.getPoints();
4     points.add(new pjs.Point(10,10));
5     points.add(new pjs.Point(10,190));
6     points.add(new pjs.Point(190,190));
7     points.add(new pjs.Point(190,10));
8     pjs.draw();
9   }
load points:

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://thatfunkysite.com/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:

{ 'points' : [ {'x': 10 , 'y': 10},
               {'x': 190 , 'y': 10},
               {'x': 190 , 'y': 190},
               {'x': 10, 'y': 190} ] }

XML

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://thatfunkysite.com/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:

1   <xml>
2     <point x='10' y='10'/>
3     <point x='190' y='50'/>
4     <point x='10' y='90'/>
5     <point x='190' y='140'/>
6     <point x='10' y='190'/>
7   </xml>

SVG

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.

drawing with SVG
 1   XMLElement svgxml;
 2   PShape ps;
 3   int x=0;
 4   int y=0;
 5   int xoffset=0;
 6   int yoffset=0;
 7   int xmark=0;
 8   int ymark=0;
 9 
10   void setup() {
11     size(200,200);
12     noLoop();
13   }
14 
15   void draw() {
16     background(255);
17     stroke(0);
18     for(int px=0; px<width; px+=10) { line(px,0,0,px); }
19     for(int py=0; py<height; py+=10) { line(width,py,0,py+height); }
20     stroke(#000066);
21     for(int py=0; py<height;py+=10) { line(0,py,width,py); }
22     if(ps!=null) { shape(ps,x-xoffset,y-yoffset,200,200); }
23   }
24 
25   void mousePressed() {
26     xmark = mouseX;
27     ymark = mouseY;
28   }
29 
30   void mouseDragged() {
31     xoffset = xmark-mouseX;
32     yoffset = ymark-mouseY;
33     redraw();
34   }
35 
36   void mouseReleased() {
37     if(xoffset!=0 || yoffset!=0) {
38       x -= xoffset;
39       y -= yoffset;
40       xoffset=0;
41       yoffset=0;
42     } else {
43       XMLElement path = svgxml.getChild(0);
44       path.setAttribute("fill",getNextColor());
45       bindSVG(svgxml);
46     }
47   }
48 
49   String[] colors = {"#f0f8ff","#faebd7","#00ffff","...", ..., ... };
50   int color_len = colors.length;
51   int current_color = 0;
52 
53   String getNextColor() {
54     current_color = (current_color+1)%color_len;
55     return colors[current_color];
56   }
57 
58   void buildFromSVG(String svg) {
59     svgxml = new XMLElement(svg);
60     bindSVG(svgxml);
61   }
62 
63   void bindSVG(XMLElement svg) {
64     ps = new PShapeSVG(svgxml);
65     redraw();
66   }

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:

  1. Write an interface for the object we're using, so our sketch will know what it even is,
  2. use a javascript binding so that we can ask javascript to make these objects for us, and
  3. 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.

  1. 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);
    
  2. 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         }
    
  3. 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         }
    
  4. 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.

    1         pjs.mouseMoved = function() {
    2           value = ( pjs.mouseY-100);
    3           pjs.redraw();
    4         }
    
  5. 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:

More information

This guide was brought to you by Mike "Pomax" Kamermans.

For more information, you can visit the following websites, or visit us in the #processing.js IRC channel on irc.mozilla.org.

Fork me on GitHub