a port of the Processing Visualization Language

Learning

Basic Syntax

A brief look at the structure of a Processing sketch reveals how easy it is to program interactive visualizations.

As with any language, you begin by defining your global variables. Then you create a setup() function, where you control the visualization's properties, like the canvas size, frame rate and perhaps variables such as the stoke-weight or background-color.

The next step is to create your draw() function, which controls the behavior of each frame in your animation. The draw function loops continuously unless you tell it otherwise by using the exit() command.

To the right is a basic example of Processing.js in action. If you take a moment to read the source code below, you will see that a few lines of Processing code can go a very long way. You may also notice that Processing syntax is almost identical to Java.

// Global variables
float radius = 50.0;
int X, Y;
int nX, nY;
int delay = 16;

// Setup the Processing Canvas
void setup(){
  size( 200, 200 );
  strokeWeight( 10 );
  frameRate( 15 );
  X = width / 2;
  Y = height / 2;
  nX = X;
  nY = Y;  
}

// Main draw loop
void draw(){
  
  radius = radius + sin( frameCount / 4 );
  
  // Track circle to new destination
  X+=(nX-X)/delay;
  Y+=(nY-Y)/delay;
  
  // Fill canvas grey
  background( 100 );
  
  // Set fill-color to blue
  fill( 0, 121, 184 );
  
  // Set stroke-color white
  stroke(255); 
  
  // Draw circle
  ellipse( X, Y, radius, radius );                  
}


// Set circle's next destination
void mouseMoved(){
  nX = mouseX;
  nY = mouseY;  
}

Adding interactivity to your visualization is incredibly simple. There are a host of built-in functions such as: mousePressed(), which controls the behavior of your script on click events; or mouseMoved() which defines what should happen as your mouse moves across the Canvas.

Processing.js also tracks a range of pre-defined variables like key, which stores the value of the last key pressed; or mouseX and mouseY, which store the last recorded position of the mouse pointer.

Using Processing

There are two ways of implementing processing. The first way is the recommended one. Let me illustrate both of these:

First Method

Needed files:

  1. processing.js
  2. anything.html
  3. anything.pde

The anything.html file will look like:

<script src="processing.js"></script> 
<canvas data-processing-sources="anything.pde"></canvas>

The anything.pde file will look like:

void setup()
{
  size(200,200);
  background(125);
  fill(255);
  noLoop();
  PFont fontA = loadFont("courier");
  textFont(fontA, 14);  
}

void draw(){  
  text("Hello Web!",20,20);
  println("Hello ErrorLog!");
}

Second Method

Needed files:

  1. processing.js
  2. anything.html

In this method the anything.html file will look like:

<script src="processing.js"></script>
<script type="text/processing" data-processing-target="mycanvas">
void setup()
{
  size(200,200);
  background(125);
  fill(255);
  noLoop();
  PFont fontA = loadFont("courier");
  textFont(fontA, 14);  
}

void draw(){  
  text("Hello Web!",20,20);
  println("Hello ErrorLog!");
}
</script>
<canvas id="mycanvas"></canvas>

Notice no data-processing-sources attribute on the canvas?

Writing Processing code with JavaScript

If you love JavaScript and want to write processing examples with it you can. Here are a couple of examples that showcase how to do this.

<html>
<head>
  <script src="processing.js"></script>
</head>
<body><h1>Processing.js</h1>
<h2>Simple processing.js via JavaScript</h2>
<p>Clock</p>

<p><canvas id="canvas1" width="200" height="200"></canvas></p>

<script id="script1" type="text/javascript">

// Simple way to attach js code to the canvas is by using a function
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 p = new Processing(canvas, sketchProc);
// p.exit(); to detach it
</script>
</body>
</html>

Here is another example that uses 3D

<html>
<head>
  <script src="processing.js"></script>
</head>
<body><h1>Processing.js</a></h1>
<h2>Advanced processing.js via JavaScript</h2>
<p>Processing.js Cube</p>
<em>Note: runs via a web server or requres local files access in the web browser settings.</em>
Converted to the JavaScript language from the Processing code<br>
Original souce code:<a href="http://processing.org/learning/3d/texturecube.html">TexturedCube</a> 
by Dave Bollinger.

<canvas id="canvas1" width="200" height="200"></canvas>

<script id="script1" type="text/javascript">

// Attaching js code to the canvas by using a sketch object

var sketch = new Processing.Sketch();
// define 3D context
sketch.use3DContext = true;
// preload the images
sketch.imageCache.add("pjs.png");
// attach function (also, can be specified as the single parameter 
// in the Processing.Sketch object constructor)
sketch.attachFunction = function(processing) {
  var tex;
  var rotx = Math.PI/4;
  var roty = Math.PI/4;

  processing.setup = function() {
    processing.size(640, 360, processing.P3D);
    tex = processing.loadImage("pjs.png");
    processing.textureMode(processing.NORMALIZED);
    processing.fill(255);
    processing.stroke(processing.color(44,48,32));
  };

  processing.draw = function() {
    processing.background(0);
    processing.noStroke();
    processing.translate(processing.width/2.0, 
                         processing.height/2.0, -100);
    processing.rotateX(rotx);
    processing.rotateY(roty);
    processing.scale(90);
    texturedCube(tex);
  }

  function texturedCube(tex) {
    processing.beginShape(processing.QUADS);
    processing.texture(tex);

    // Given one texture and six faces, we can easily set up the uv coordinates
    // such that four of the faces tile "perfectly" along either u or v, but the other
    // two faces cannot be so aligned.  This code tiles "along" u, "around" the X/Z faces
    // and fudges the Y faces - the Y faces are arbitrarily aligned such that a
    // rotation along the X axis will put the "top" of either texture at the "top"
    // of the screen, but is not otherwised aligned with the X/Z faces. (This
    // just affects what type of symmetry is required if you need seamless
    // tiling all the way around the cube)
    
    // +Z "front" face
    processing.vertex(-1, -1,  1, 0, 0);
    processing.vertex( 1, -1,  1, 1, 0);
    processing.vertex( 1,  1,  1, 1, 1);
    processing.vertex(-1,  1,  1, 0, 1);

    // -Z "back" face
    processing.vertex( 1, -1, -1, 0, 0);
    processing.vertex(-1, -1, -1, 1, 0);
    processing.vertex(-1,  1, -1, 1, 1);
    processing.vertex( 1,  1, -1, 0, 1);

    // +Y "bottom" face
    processing.vertex(-1,  1,  1, 0, 0);
    processing.vertex( 1,  1,  1, 1, 0);
    processing.vertex( 1,  1, -1, 1, 1);
    processing.vertex(-1,  1, -1, 0, 1);

    // -Y "top" face
    processing.vertex(-1, -1, -1, 0, 0);
    processing.vertex( 1, -1, -1, 1, 0);
    processing.vertex( 1, -1,  1, 1, 1);
    processing.vertex(-1, -1,  1, 0, 1);

    // +X "right" face
    processing.vertex( 1, -1,  1, 0, 0);
    processing.vertex( 1, -1, -1, 1, 0);
    processing.vertex( 1,  1, -1, 1, 1);
    processing.vertex( 1,  1,  1, 0, 1);

    // -X "left" face
    processing.vertex(-1, -1, -1, 0, 0);
    processing.vertex(-1, -1,  1, 1, 0);
    processing.vertex(-1,  1,  1, 1, 1);
    processing.vertex(-1,  1, -1, 0, 1);

    processing.endShape();
  }

  // mouse event
  processing.mouseDragged = function() {
    var rate = 0.01;
    rotx += (processing.pmouseY-processing.mouseY) * rate;
    roty += (processing.mouseX-processing.pmouseX) * rate;
  };
};

var canvas = document.getElementById("canvas1");
// attaching the sketch to the canvas
var p = new Processing(canvas, sketch);

</script>

Read Quick Start Guides for Processing Developers or JavaScript Developers, to learn about the Processing language.

Fork me on GitHub