Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
/***
|''Name:''|ProcessingPlugin|
|''Description:''|TiddlyWiki Bundle of John Ressig's processing.js|
|''Date:''|May 9, 2008|
|''Author:''|PaulDowney (psd (at) osmosoft (dot) com)|
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/PaulDowney/plugins/ProcessingPlugin.js|
|''Version:''|0.2|
|''License:''|[[MIT license]]|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.2|
With contributions from Simon Baird.
***/
//{{{
// Ensure Plugin is only installed once.
if(!version.extensions.Processingjs) {
version.extensions.Processingjs = {installed:true};
config.macros.Processing = {
counter: 0,
handler: function (place,macroName,params,wikifier,paramString,tiddler) {
var id = "processingcanvas"+this.counter;
var canvas = createTiddlyElement(place,"canvas",id);
// inlined code
var code = paramString;
// quick and dirty grab of code from a named tiddler
if (store.tiddlerExists(params[0])) {
code = store.getTiddlerText(params[0]);
}
// or with no params, grab code from this tiddler
if (paramString.trim() == '') {
code = tiddler.text;
}
createTiddlyElement(place,"br");
var restartBtn = createTiddlyButton(place,"restart","restart",function() {
story.refreshTiddler(tiddler.title,null,true);
return false;
},
'processingRestart' // it's a class so you can style the button
);
Processing(canvas,code);
}
};
// requires 2.4
merge(config.macros.view.views,{
processing: function(value,place,params,wikifier,paramString,tiddler) {
wikify("<<Processing\n"+value+"\n>>",place,highlightHack,tiddler);
}
});
/*
* inlined copy of Processing.js
* latest code at: http://ejohn.org/blog/processingjs/
*/
/*
* Processing.js - John Resig (http://ejohn.org/)
* MIT Licensed
* http://ejohn.org/blog/processingjs/
*
* This is a port of the Processing Visualization Language.
* More information: http://processing.org/
*/
(function(){
this.Processing = function Processing( aElement, aCode )
{
var p = buildProcessing( aElement );
p.init( aCode );
return p;
};
function log()
{
try
{
console.log.apply( console, arguments );
}
catch(e)
{
try
{
opera.postError.apply( opera, arguments );
}
catch(e){}
}
}
function parse( aCode, p )
{
// Angels weep at this parsing code :-(
// Remove end-of-line comments
aCode = aCode.replace(/\/\/ .*\n/g, "\n");
// Weird parsing errors with %
aCode = aCode.replace(/([^\s])%([^\s])/g, "$1 % $2");
// Simple convert a function-like thing to function
aCode = aCode.replace(/(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g, function(all, type, name, args)
{
if ( name == "if" || name == "for" || name == "while" )
{
return all;
}
else
{
return "Processing." + name + " = function " + name + args;
}
});
// Force .length() to be .length
aCode = aCode.replace(/\.length\(\)/g, ".length");
// foo( int foo, float bar )
aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4");
aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4");
// float[] foo = new float[5];
aCode = aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g, function(all, name, args)
{
return "new ArrayList(" + args.slice(1,-1).split("][").join(", ") + ")";
});
aCode = aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g, function(all)
{
return all.replace(/{/g, "[").replace(/}/g, "]");
});
// int|float foo;
var intFloat = /(\n\s*(?:int|float)(?:\[\])?(?:\s*|[^\(]*?,\s*))([a-z]\w*)(;|,)/i;
while ( intFloat.test(aCode) )
{
aCode = aCode.replace(new RegExp(intFloat), function(all, type, name, sep)
{
return type + " " + name + " = 0" + sep;
});
}
// float foo = 5;
aCode = aCode.replace(/(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function(all, type, arr, name, sep)
{
if ( type == "return" )
return all;
else
return "var " + name + sep;
});
// Fix Array[] foo = {...} to [...]
aCode = aCode.replace(/=\s*{((.|\s)*?)};/g, function(all,data)
{
return "= [" + data.replace(/{/g, "[").replace(/}/g, "]") + "]";
});
// static { ... } blocks
aCode = aCode.replace(/static\s*{((.|\n)*?)}/g, function(all, init)
{
// Convert the static definitons to variable assignments
//return init.replace(/\((.*?)\)/g, " = $1");
return init;
});
// super() is a reserved word
aCode = aCode.replace(/super\(/g, "superMethod(");
var classes = ["int", "float", "boolean", "string"];
function ClassReplace(all, name, extend, vars, last)
{
classes.push( name );
var static = "";
vars = vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g, function(all,set)
{
static += " " + name + "." + set;
return "";
});
// Move arguments up from constructor and wrap contents with
// a with(this), and unwrap constructor
return "function " + name + "() {with(this){\n " +
(extend ? "var __self=this;function superMethod(){extendClass(__self,arguments," + extend + ");}\n" : "") +
// Replace var foo = 0; with this.foo = 0;
// and force var foo; to become this.foo = null;
vars
.replace(/,\s?/g, ";\n this.")
.replace(/\b(var |final |public )+\s*/g, "this.")
.replace(/this.(\w+);/g, "this.$1 = null;") +
(extend ? "extendClass(this, " + extend + ");\n" : "") +
"<CLASS " + name + " " + static + ">" + (typeof last == "string" ? last : name + "(");
}
var matchClasses = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)\b\1\s*\(/g;
var matchNoCon = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)(Processing)/g;
aCode = aCode.replace(matchClasses, ClassReplace);
aCode = aCode.replace(matchNoCon, ClassReplace);
var matchClass = /<CLASS (\w+) (.*?)>/, m;
while ( (m = aCode.match( matchClass )) )
{
var left = RegExp.leftContext,
allRest = RegExp.rightContext,
rest = nextBrace(allRest),
className = m[1],
staticVars = m[2] || "";
allRest = allRest.slice( rest.length + 1 );
rest = rest.replace(new RegExp("\\b" + className + "\\(([^\\)]*?)\\)\\s*{", "g"), function(all, args)
{
args = args.split(/,\s*?/);
if ( args[0].match(/^\s*$/) )
args.shift();
var fn = "if ( arguments.length == " + args.length + " ) {\n";
for ( var i = 0; i < args.length; i++ )
{
fn += " var " + args[i] + " = arguments[" + i + "];\n";
}
return fn;
});
// Fix class method names
// this.collide = function() { ... }
// and add closing } for with(this) ...
rest = rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g, function(all, name, args)
{
return "ADDMETHOD(this, '" + name + "', function(" + args + ")";
});
var matchMethod = /ADDMETHOD([\s\S]*?{)/, mc;
var methods = "";
while ( (mc = rest.match( matchMethod )) )
{
var prev = RegExp.leftContext,
allNext = RegExp.rightContext,
next = nextBrace(allNext);
methods += "addMethod" + mc[1] + next + "});"
rest = prev + allNext.slice( next.length + 1 );
}
rest = methods + rest;
aCode = left + rest + "\n}}" + staticVars + allRest;
}
// Do some tidying up, where necessary
aCode = aCode.replace(/Processing.\w+ = function addMethod/g, "addMethod");
function nextBrace( right )
{
var rest = right;
var position = 0;
var leftCount = 1, rightCount = 0;
while ( leftCount != rightCount )
{
var nextLeft = rest.indexOf("{");
var nextRight = rest.indexOf("}");
if ( nextLeft < nextRight && nextLeft != -1 )
{
leftCount++;
rest = rest.slice( nextLeft + 1 );
position += nextLeft + 1;
}
else
{
rightCount++;
rest = rest.slice( nextRight + 1 );
position += nextRight + 1;
}
}
return right.slice(0, position - 1);
}
// Handle (int) Casting
aCode = aCode.replace(/\(int\)/g, "0|");
// Remove Casting
aCode = aCode.replace(new RegExp("\\((" + classes.join("|") + ")(\\[\\])?\\)", "g"), "");
// Convert 3.0f to just 3.0
aCode = aCode.replace(/(\d+)f/g, "$1");
// Force numbers to exist
//aCode = aCode.replace(/([^.])(\w+)\s*\+=/g, "$1$2 = ($2||0) +");
// Force characters-as-bytes to work
aCode = aCode.replace(/('[a-zA-Z0-9]')/g, "$1.charCodeAt(0)");
// Convert #aaaaaa into color
aCode = aCode.replace(/#([a-f0-9]{6})/ig, function(m, hex){
var num = toNumbers(hex);
return "color(" + num[0] + "," + num[1] + "," + num[2] + ")";
});
function toNumbers( str ){
var ret = [];
str.replace(/(..)/g, function(str){
ret.push( parseInt( str, 16 ) );
});
return ret;
}
//log(aCode);
return aCode;
}
function buildProcessing( curElement ){
var p = {};
// init
p.PI = Math.PI;
p.TWO_PI = 2 * p.PI;
p.HALF_PI = p.PI / 2;
p.P3D = 3;
p.CORNER = 0;
p.CENTER = 1;
p.CENTER_RADIUS = 2;
p.RADIUS = 2;
p.POLYGON = 1;
p.TRIANGLES = 6;
p.POINTS = 7;
p.LINES = 8;
p.TRIANGLE_STRIP = 9;
p.CORNERS = 10;
p.CLOSE = true;
p.RGB = 1;
p.HSB = 2;
// "Private" variables used to maintain state
var curContext = curElement.getContext("2d");
var doFill = true;
var doStroke = true;
var loopStarted = false;
var hasBackground = false;
var doLoop = true;
var curRectMode = p.CORNER;
var curEllipseMode = p.CENTER;
var inSetup = false;
var inDraw = false;
var curBackground = "rgba(204,204,204,1)";
var curFrameRate = 1000;
var curShape = p.POLYGON;
var curShapeCount = 0;
var opacityRange = 255;
var redRange = 255;
var greenRange = 255;
var blueRange = 255;
var pathOpen = false;
var mousePressed = false;
var keyPressed = false;
var firstX, firstY, prevX, prevY;
var curColorMode = p.RGB;
var curTint = -1;
var curTextSize = 12;
var curTextFont = "Arial";
var getLoaded = false;
var start = (new Date).getTime();
// Global vars for tracking mouse position
p.pmouseX = 0;
p.pmouseY = 0;
p.mouseX = 0;
p.mouseY = 0;
// Will be replaced by the user, most likely
p.mouseDragged = undefined;
p.mouseMoved = undefined;
p.mousePressed = undefined;
p.mouseReleased = undefined;
p.keyPressed = undefined;
p.keyReleased = undefined;
p.draw = undefined;
p.setup = undefined;
// The height/width of the canvas
p.width = curElement.width - 0;
p.height = curElement.height - 0;
// In case I ever need to do HSV conversion:
// http://srufaculty.sru.edu/david.dailey/javascript/js/5rml.js
p.color = function color( aValue1, aValue2, aValue3, aValue4 )
{
var aColor = "";
if ( arguments.length == 3 )
{
aColor = p.color( aValue1, aValue2, aValue3, opacityRange );
}
else if ( arguments.length == 4 )
{
var a = aValue4 / opacityRange;
a = isNaN(a) ? 1 : a;
if ( curColorMode == p.HSB )
{
var rgb = HSBtoRGB(aValue1, aValue2, aValue3);
var r = rgb[0], g = rgb[1], b = rgb[2];
}
else
{
var r = getColor(aValue1, redRange);
var g = getColor(aValue2, greenRange);
var b = getColor(aValue3, blueRange);
}
aColor = "rgba(" + r + "," + g + "," + b + "," + a + ")";
}
else if ( typeof aValue1 == "string" )
{
aColor = aValue1;
if ( arguments.length == 2 )
{
var c = aColor.split(",");
c[3] = (aValue2 / opacityRange) + ")";
aColor = c.join(",");
}
}
else if ( arguments.length == 2 )
{
aColor = p.color( aValue1, aValue1, aValue1, aValue2 );
}
else if ( typeof aValue1 == "number" )
{
aColor = p.color( aValue1, aValue1, aValue1, opacityRange );
}
else
{
aColor = p.color( redRange, greenRange, blueRange, opacityRange );
}
// HSB conversion function from Mootools, MIT Licensed
function HSBtoRGB(h, s, b)
{
h = (h / redRange) * 100;
s = (s / greenRange) * 100;
b = (b / blueRange) * 100;
if (s == 0){
return [b, b, b];
} else {
var hue = h % 360;
var f = hue % 60;
var br = Math.round(b / 100 * 255);
var p = Math.round((b * (100 - s)) / 10000 * 255);
var q = Math.round((b * (6000 - s * f)) / 600000 * 255);
var t = Math.round((b * (6000 - s * (60 - f))) / 600000 * 255);
switch (Math.floor(hue / 60)){
case 0: return [br, t, p];
case 1: return [q, br, p];
case 2: return [p, br, t];
case 3: return [p, q, br];
case 4: return [t, p, br];
case 5: return [br, p, q];
}
}
}
function getColor( aValue, range )
{
return Math.round(255 * (aValue / range));
}
return aColor;
}
p.nf = function( num, pad )
{
var str = "" + num;
while ( pad - str.length )
str = "0" + str;
return str;
};
p.AniSprite = function( prefix, frames )
{
this.images = [];
this.pos = 0;
for ( var i = 0; i < frames; i++ )
{
this.images.push( prefix + p.nf( i, ("" + frames).length ) + ".gif" );
}
this.display = function( x, y )
{
p.image( this.images[ this.pos ], x, y );
if ( ++this.pos >= frames )
this.pos = 0;
};
this.getWidth = function()
{
return getImage(this.images[0]).width;
};
this.getHeight = function()
{
return getImage(this.images[0]).height;
};
};
function buildImageObject( obj )
{
var pixels = obj.data;
var data = p.createImage( obj.width, obj.height );
if ( data.__defineGetter__ && data.__lookupGetter__ && !data.__lookupGetter__("pixels") )
{
var pixelsDone;
data.__defineGetter__("pixels", function()
{
if ( pixelsDone )
return pixelsDone;
pixelsDone = [];
for ( var i = 0; i < pixels.length; i += 4 )
{
pixelsDone.push( p.color(pixels[i], pixels[i+1], pixels[i+2], pixels[i+3]) );
}
return pixelsDone;
});
}
else
{
data.pixels = [];
for ( var i = 0; i < pixels.length; i += 4 )
{
data.pixels.push( p.color(pixels[i], pixels[i+1], pixels[i+2], pixels[i+3]) );
}
}
return data;
}
p.createImage = function createImage( w, h, mode )
{
var data = {
width: w,
height: h,
pixels: new Array( w * h ),
get: function(x,y)
{
return this.pixels[w*y+x];
},
_mask: null,
mask: function(img)
{
this._mask = img;
},
loadPixels: function()
{
},
updatePixels: function()
{
}
};
return data;
}
p.createGraphics = function createGraphics( w, h )
{
var canvas = document.createElement("canvas");
var ret = buildProcessing( canvas );
ret.size( w, h );
ret.canvas = canvas;
return ret;
}
p.beginDraw = function beginDraw()
{
}
p.endDraw = function endDraw()
{
}
p.tint = function tint( rgb, a )
{
curTint = a;
}
function getImage( img ) {
if ( typeof img == "string" )
{
return document.getElementById(img);
}
if ( img.img || img.canvas )
{
return img.img || img.canvas;
}
img.data = [];
for ( var i = 0, l = img.pixels.length; i < l; i++ )
{
var c = (img.pixels[i] || "rgba(0,0,0,1)").slice(5,-1).split(",");
img.data.push( parseInt(c[0]), parseInt(c[1]), parseInt(c[2]), parseFloat(c[3]) * 100 );
}
var canvas = document.createElement("canvas")
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext("2d");
context.putImageData( img, 0, 0 );
img.canvas = canvas;
return canvas;
}
p.image = function image( img, x, y, w, h )
{
x = x || 0;
y = y || 0;
var obj = getImage(img);
if ( curTint >= 0 )
{
var oldAlpha = curContext.globalAlpha;
curContext.globalAlpha = curTint / opacityRange;
}
if ( arguments.length == 3 )
{
curContext.drawImage( obj, x, y );
}
else
{
curContext.drawImage( obj, x, y, w, h );
}
if ( curTint >= 0 )
{
curContext.globalAlpha = oldAlpha;
}
if ( img._mask )
{
var oldComposite = curContext.globalCompositeOperation;
curContext.globalCompositeOperation = "darker";
p.image( img._mask, x, y );
curContext.globalCompositeOperation = oldComposite;
}
}
p.exit = function exit()
{
}
p.save = function save( file )
{
}
p.loadImage = function loadImage( file )
{
var img = document.getElementById(file);
if ( !img )
return;
var h = img.height, w = img.width;
var canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
var context = canvas.getContext("2d");
context.drawImage( img, 0, 0 );
var data = buildImageObject( context.getImageData( 0, 0, w, h ) );
data.img = img;
return data;
}
p.loadFont = function loadFont( name )
{
return {
name: name,
width: function( str )
{
if ( curContext.mozMeasureText )
return curContext.mozMeasureText( typeof str == "number" ?
String.fromCharCode( str ) :
str) / curTextSize;
else
return 0;
}
};
}
p.textFont = function textFont( name, size )
{
curTextFont = name;
p.textSize( size );
}
p.textSize = function textSize( size )
{
if ( size )
{
curTextSize = size;
}
}
p.textAlign = function textAlign()
{
}
p.text = function text( str, x, y )
{
if ( str && curContext.mozDrawText )
{
curContext.save();
curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
curContext.translate(x, y);
curContext.mozDrawText( typeof str == "number" ?
String.fromCharCode( str ) :
str );
curContext.restore();
}
}
p.char = function char( key )
{
//return String.fromCharCode( key );
return key;
}
p.println = function println()
{
}
p.map = function map( value, istart, istop, ostart, ostop )
{
return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
};
String.prototype.replaceAll = function(re, replace)
{
return this.replace(new RegExp(re, "g"), replace);
};
p.Point = function Point( x, y )
{
this.x = x;
this.y = y;
this.copy = function()
{
return new Point( x, y );
}
}
p.Random = function()
{
var haveNextNextGaussian = false;
var nextNextGaussian;
this.nextGaussian = function()
{
if (haveNextNextGaussian) {
haveNextNextGaussian = false;
return nextNextGaussian;
} else {
var v1, v2, s;
do {
v1 = 2 * p.random(1) - 1; // between -1.0 and 1.0
v2 = 2 * p.random(1) - 1; // between -1.0 and 1.0
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
var multiplier = Math.sqrt(-2 * Math.log(s)/s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
};
}
p.ArrayList = function ArrayList( size, size2, size3 )
{
var array = new Array( 0 | size );
if ( size2 )
{
for ( var i = 0; i < size; i++ )
{
array[i] = [];
for ( var j = 0; j < size2; j++ )
{
var a = array[i][j] = size3 ? new Array( size3 ) : 0;
for ( var k = 0; k < size3; k++ )
{
a[k] = 0;
}
}
}
}
else
{
for ( var i = 0; i < size; i++ )
{
array[i] = 0;
}
}
array.size = function()
{
return this.length;
};
array.get = function( i )
{
return this[ i ];
};
array.remove = function( i )
{
return this.splice( i, 1 );
};
array.add = function( item )
{
for ( var i = 0; this[ i ] != undefined; i++ ) {}
this[ i ] = item;
};
array.clone = function()
{
var a = new ArrayList( size );
for ( var i = 0; i < size; i++ )
{
a[ i ] = this[ i ];
}
return a;
};
array.isEmpty = function()
{
return !this.length;
};
array.clear = function()
{
this.length = 0;
};
return array;
}
p.colorMode = function colorMode( mode, range1, range2, range3, range4 )
{
curColorMode = mode;
if ( arguments.length >= 4 )
{
redRange = range1;
greenRange = range2;
blueRange = range3;
}
if ( arguments.length == 5 )
{
opacityRange = range4;
}
if ( arguments.length == 2 )
{
p.colorMode( mode, range1, range1, range1, range1 );
}
}
p.beginShape = function beginShape( type )
{
curShape = type;
curShapeCount = 0;
}
p.endShape = function endShape( close )
{
if ( curShapeCount != 0 )
{
curContext.lineTo( firstX, firstY );
if ( doFill )
curContext.fill();
if ( doStroke )
curContext.stroke();
curContext.closePath();
curShapeCount = 0;
pathOpen = false;
}
if ( pathOpen )
{
curContext.closePath();
}
}
p.vertex = function vertex( x, y, x2, y2, x3, y3 )
{
if ( curShapeCount == 0 && curShape != p.POINTS )
{
pathOpen = true;
curContext.beginPath();
curContext.moveTo( x, y );
}
else
{
if ( curShape == p.POINTS )
{
p.point( x, y );
}
else if ( arguments.length == 2 )
{
if ( curShape == p.TRIANGLE_STRIP && curShapeCount == 2 )
{
curContext.moveTo( prevX, prevY );
curContext.lineTo( firstX, firstY );
}
curContext.lineTo( x, y );
}
else if ( arguments.length == 4 )
{
if ( curShapeCount > 1 )
{
curContext.moveTo( prevX, prevY );
curContext.quadraticCurveTo( firstX, firstY, x, y );
curShapeCount = 1;
}
}
else if ( arguments.length == 6 )
{
curContext.bezierCurveTo( x, y, x2, y2, x3, y3 );
curShapeCount = -1;
}
}
prevX = firstX;
prevY = firstY;
firstX = x;
firstY = y;
curShapeCount++;
if ( curShape == p.LINES && curShapeCount == 2 ||
(curShape == p.TRIANGLES || curShape == p.TRIANGLE_STRIP) && curShapeCount == 3 )
{
p.endShape();
}
if ( curShape == p.TRIANGLE_STRIP && curShapeCount == 3 )
{
curShapeCount = 2;
}
}
p.curveTightness = function()
{
}
// Unimplmented - not really possible with the Canvas API
p.curveVertex = function( x, y, x2, y2 )
{
p.vertex( x, y, x2, y2 );
}
p.bezierVertex = p.vertex
p.rectMode = function rectMode( aRectMode )
{
curRectMode = aRectMode;
}
p.imageMode = function()
{
}
p.ellipseMode = function ellipseMode( aEllipseMode )
{
curEllipseMode = aEllipseMode;
}
p.dist = function dist( x1, y1, x2, y2 )
{
return Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) );
}
p.year = function year()
{
return (new Date).getYear() + 1900;
}
p.month = function month()
{
return (new Date).getMonth();
}
p.day = function day()
{
return (new Date).getDay();
}
p.hour = function hour()
{
return (new Date).getHours();
}
p.minute = function minute()
{
return (new Date).getMinutes();
}
p.second = function second()
{
return (new Date).getSeconds();
}
p.millis = function millis()
{
return (new Date).getTime() - start;
}
p.ortho = function ortho()
{
}
p.translate = function translate( x, y )
{
curContext.translate( x, y );
}
p.scale = function scale( x, y )
{
curContext.scale( x, y || x );
}
p.rotate = function rotate( aAngle )
{
curContext.rotate( aAngle );
}
p.pushMatrix = function pushMatrix()
{
curContext.save();
}
p.popMatrix = function popMatrix()
{
curContext.restore();
}
p.redraw = function redraw()
{
if ( hasBackground )
{
p.background();
}
inDraw = true;
p.pushMatrix();
p.draw();
p.popMatrix();
inDraw = false;
}
p.loop = function loop()
{
if ( loopStarted )
return;
var looping = setInterval(function()
{
try
{
p.redraw();
}
catch(e)
{
clearInterval( looping );
throw e;
}
}, 1000 / curFrameRate );
loopStarted = true;
}
p.frameRate = function frameRate( aRate )
{
curFrameRate = aRate;
}
p.background = function background( img )
{
if ( arguments.length )
{
if ( img && img.img )
{
curBackground = img;
}
else
{
curBackground = p.color.apply( this, arguments );
}
}
if ( curBackground.img )
{
p.image( curBackground, 0, 0 );
}
else
{
var oldFill = curContext.fillStyle;
curContext.fillStyle = curBackground + "";
curContext.fillRect( 0, 0, p.width, p.height );
curContext.fillStyle = oldFill;
}
}
p.sq = function sq( aNumber )
{
return aNumber * aNumber;
}
p.sqrt = function sqrt( aNumber )
{
return Math.sqrt( aNumber );
}
p.int = function int( aNumber )
{
return Math.floor( aNumber );
}
p.min = function min( aNumber, aNumber2 )
{
return Math.min( aNumber, aNumber2 );
}
p.max = function max( aNumber, aNumber2 )
{
return Math.max( aNumber, aNumber2 );
}
p.ceil = function ceil( aNumber )
{
return Math.ceil( aNumber );
}
p.floor = function floor( aNumber )
{
return Math.floor( aNumber );
}
p.float = function float( aNumber )
{
return typeof aNumber == "string" ?
p.float( aNumber.charCodeAt(0) ) :
parseFloat( aNumber );
}
p.byte = function byte( aNumber )
{
return aNumber || 0;
}
p.random = function random( aMin, aMax )
{
return arguments.length == 2 ?
aMin + (Math.random() * (aMax - aMin)) :
Math.random() * aMin;
}
// From: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
p.noise = function( x, y, z )
{
return arguments.length >= 2 ?
PerlinNoise_2D( x, y ) :
PerlinNoise_2D( x, x );
}
function Noise(x, y)
{
var n = x + y * 57;
n = (n<<13) ^ n;
return Math.abs(1.0 - (((n * ((n * n * 15731) + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0));
}
function SmoothedNoise(x, y)
{
var corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
var sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
var center = Noise(x, y) / 4;
return corners + sides + center;
}
function InterpolatedNoise(x, y)
{
var integer_X = Math.floor(x);
var fractional_X = x - integer_X;
var integer_Y = Math.floor(y);
var fractional_Y = y - integer_Y;
var v1 = SmoothedNoise(integer_X, integer_Y);
var v2 = SmoothedNoise(integer_X + 1, integer_Y);
var v3 = SmoothedNoise(integer_X, integer_Y + 1);
var v4 = SmoothedNoise(integer_X + 1, integer_Y + 1);
var i1 = Interpolate(v1 , v2 , fractional_X);
var i2 = Interpolate(v3 , v4 , fractional_X);
return Interpolate(i1 , i2 , fractional_Y);
}
function PerlinNoise_2D(x, y)
{
var total = 0;
var p = 0.25;
var n = 3;
for ( var i = 0; i <= n; i++ )
{
var frequency = Math.pow(2, i);
var amplitude = Math.pow(p, i);
total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
}
return total;
}
function Interpolate(a, b, x)
{
var ft = x * p.PI;
var f = (1 - p.cos(ft)) * .5;
return a*(1-f) + b*f;
}
p.red = function( aColor )
{
return parseInt(aColor.slice(5));
}
p.green = function( aColor )
{
return parseInt(aColor.split(",")[1]);
}
p.blue = function( aColor )
{
return parseInt(aColor.split(",")[2]);
}
p.alpha = function( aColor )
{
return parseInt(aColor.split(",")[3]);
}
p.abs = function abs( aNumber )
{
return Math.abs( aNumber );
}
p.cos = function cos( aNumber )
{
return Math.cos( aNumber );
}
p.sin = function sin( aNumber )
{
return Math.sin( aNumber );
}
p.pow = function pow( aNumber, aExponent )
{
return Math.pow( aNumber, aExponent );
}
p.constrain = function constrain( aNumber, aMin, aMax )
{
return Math.min( Math.max( aNumber, aMin ), aMax );
}
p.sqrt = function sqrt( aNumber )
{
return Math.sqrt( aNumber );
}
p.atan2 = function atan2( aNumber, aNumber2 )
{
return Math.atan2( aNumber, aNumber2 );
}
p.radians = function radians( aAngle )
{
return ( aAngle / 180 ) * p.PI;
}
p.size = function size( aWidth, aHeight )
{
var fillStyle = curContext.fillStyle;
var strokeStyle = curContext.strokeStyle;
curElement.width = p.width = aWidth;
curElement.height = p.height = aHeight;
curContext.fillStyle = fillStyle;
curContext.strokeStyle = strokeStyle;
}
p.noStroke = function noStroke()
{
doStroke = false;
}
p.noFill = function noFill()
{
doFill = false;
}
p.smooth = function smooth()
{
}
p.noLoop = function noLoop()
{
doLoop = false;
}
p.fill = function fill()
{
doFill = true;
curContext.fillStyle = p.color.apply( this, arguments );
}
p.stroke = function stroke()
{
doStroke = true;
curContext.strokeStyle = p.color.apply( this, arguments );
}
p.strokeWeight = function strokeWeight( w )
{
curContext.lineWidth = w;
}
p.point = function point( x, y )
{
var oldFill = curContext.fillStyle;
curContext.fillStyle = curContext.strokeStyle;
curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
curContext.fillStyle = oldFill;
}
p.get = function get( x, y )
{
if ( arguments.length == 0 )
{
var c = p.createGraphics( p.width, p.height );
c.image( curContext, 0, 0 );
return c;
}
if ( !getLoaded )
{
getLoaded = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) );
}
return getLoaded.get( x, y );
}
p.set = function set( x, y, color )
{
var oldFill = curContext.fillStyle;
curContext.fillStyle = color;
curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
curContext.fillStyle = oldFill;
}
p.arc = function arc( x, y, width, height, start, stop )
{
if ( width <= 0 )
return;
if ( curEllipseMode == p.CORNER )
{
x += width / 2;
y += height / 2;
}
curContext.beginPath();
curContext.moveTo( x, y );
curContext.arc( x, y, curEllipseMode == p.CENTER_RADIUS ? width : width/2, start, stop, false );
if ( doFill )
curContext.fill();
if ( doStroke )
curContext.stroke();
curContext.closePath();
}
p.line = function line( x1, y1, x2, y2 )
{
curContext.lineCap = "round";
curContext.beginPath();
curContext.moveTo( x1 || 0, y1 || 0 );
curContext.lineTo( x2 || 0, y2 || 0 );
curContext.stroke();
curContext.closePath();
}
p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 )
{
curContext.lineCap = "butt";
curContext.beginPath();
curContext.moveTo( x1, y1 );
curContext.bezierCurveTo( x2, y2, x3, y3, x4, y4 );
curContext.stroke();
curContext.closePath();
}
p.triangle = function triangle( x1, y1, x2, y2, x3, y3 )
{
p.beginShape();
p.vertex( x1, y1 );
p.vertex( x2, y2 );
p.vertex( x3, y3 );
p.endShape();
}
p.quad = function quad( x1, y1, x2, y2, x3, y3, x4, y4 )
{
p.beginShape();
p.vertex( x1, y1 );
p.vertex( x2, y2 );
p.vertex( x3, y3 );
p.vertex( x4, y4 );
p.endShape();
}
p.rect = function rect( x, y, width, height )
{
if ( width == 0 && height == 0 )
return;
curContext.beginPath();
var offsetStart = 0;
var offsetEnd = 0;
if ( curRectMode == p.CORNERS )
{
width -= x;
height -= y;
}
if ( curRectMode == p.RADIUS )
{
width *= 2;
height *= 2;
}
if ( curRectMode == p.CENTER || curRectMode == p.RADIUS )
{
x -= width / 2;
y -= height / 2;
}
curContext.rect(
Math.round( x ) - offsetStart,
Math.round( y ) - offsetStart,
Math.round( width ) + offsetEnd,
Math.round( height ) + offsetEnd
);
if ( doFill )
curContext.fill();
if ( doStroke )
curContext.stroke();
curContext.closePath();
}
p.ellipse = function ellipse( x, y, width, height )
{
x = x || 0;
y = y || 0;
if ( width <= 0 && height <= 0 )
return;
curContext.beginPath();
if ( curEllipseMode == p.RADIUS )
{
width *= 2;
height *= 2;
}
var offsetStart = 0;
// Shortcut for drawing a circle
if ( width == height )
curContext.arc( x - offsetStart, y - offsetStart, width / 2, 0, Math.PI * 2, false );
if ( doFill )
curContext.fill();
if ( doStroke )
curContext.stroke();
curContext.closePath();
}
p.link = function( href, target )
{
window.location = href;
}
p.loadPixels = function()
{
p.pixels = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) ).pixels;
}
p.updatePixels = function()
{
var colors = /(\d+),(\d+),(\d+),(\d+)/;
var pixels = {};
var data = pixels.data = [];
pixels.width = p.width;
pixels.height = p.height;
var pos = 0;
for ( var i = 0, l = p.pixels.length; i < l; i++ ) {
var c = (p.pixels[i] || "rgba(0,0,0,1)").match(colors);
data[pos] = parseInt(c[1]);
data[pos+1] = parseInt(c[2]);
data[pos+2] = parseInt(c[3]);
data[pos+3] = parseFloat(c[4]) * 100;
pos += 4;
}
curContext.putImageData(pixels, 0, 0);
}
p.extendClass = function extendClass( obj, args, fn )
{
if ( arguments.length == 3 )
{
fn.apply( obj, args );
}
else
{
args.call( obj );
}
}
p.addMethod = function addMethod( object, name, fn )
{
if ( object[ name ] )
{
var args = fn.length;
var oldfn = object[ name ];
object[ name ] = function()
{
if ( arguments.length == args )
return fn.apply( this, arguments );
else
return oldfn.apply( this, arguments );
};
}
else
{
object[ name ] = fn;
}
}
p.init = function init(code){
p.stroke( 0 );
p.fill( 255 );
// Canvas has trouble rendering single pixel stuff on whole-pixel
// counts, so we slightly offset it (this is super lame).
curContext.translate( 0.5, 0.5 );
if ( code )
{
(function(Processing){with (p){
eval(parse(code, p));
}})(p);
}
if ( p.setup )
{
inSetup = true;
p.setup();
}
inSetup = false;
if ( p.draw )
{
if ( !doLoop )
{
p.redraw();
}
else
{
p.loop();
}
}
attach( curElement, "mousemove", function(e)
{
p.pmouseX = p.mouseX;
p.pmouseY = p.mouseY;
p.mouseX = e.clientX - curElement.offsetLeft;
p.mouseY = e.clientY - curElement.offsetTop;
if ( p.mouseMoved )
{
p.mouseMoved();
}
if ( mousePressed && p.mouseDragged )
{
p.mouseDragged();
}
});
attach( curElement, "mousedown", function(e)
{
mousePressed = true;
if ( typeof p.mousePressed == "function" )
{
p.mousePressed();
}
else
{
p.mousePressed = true;
}
});
attach( curElement, "mouseup", function(e)
{
mousePressed = false;
if ( typeof p.mousePressed != "function" )
{
p.mousePressed = false;
}
if ( p.mouseReleased )
{
p.mouseReleased();
}
});
attach( document, "keydown", function(e)
{
keyPressed = true;
p.key = e.keyCode + 32;
if ( e.shiftKey )
{
p.key = String.fromCharCode(p.key).toUpperCase().charCodeAt(0);
}
if ( typeof p.keyPressed == "function" )
{
p.keyPressed();
}
else
{
p.keyPressed = true;
}
});
attach( document, "keyup", function(e)
{
keyPressed = false;
if ( typeof p.keyPressed != "function" )
{
p.keyPressed = false;
}
if ( p.keyReleased )
{
p.keyReleased();
}
});
function attach(elem, type, fn)
{
if ( elem.addEventListener )
elem.addEventListener( type, fn, false );
else
elem.attachEvent( "on" + type, fn );
}
};
return p;
}
})();
} //# end of "install only once"
//}}}
TiddlyProcessing
[[Basic Examples|BasicExample]]
ProcessingjsPlugin
Processing.js in TiddlyWiki
[[TiddlyWiki|http://tiddlywiki.com]], a wiki in a single HTML page. Open a [[Downloaded]] a copy of this page in Firefox, and you'll be able to edit the examples and save your changes locally on your computer. For more help on using TiddlyWiki, including support for other browsers, see [[Download Software|http://www.tiddlywiki.com/#DownloadSoftware]].
If you have questions, the ~TiddlyWiki community is incredibly helpful - there's a [[developer's group|http://groups.google.com/group/TiddlyWikiDev]] and a [[user's group|http://groups.google.com/group/TiddlyWiki]] on Google Groups.
TiddlyProcessing is a TiddlyWiki containing [[John Ressig|http://ejohn.org]]'s [[Processing.js|http://ejohn.org/apps/processing.js/]] [[basic examples|BasicExample]]. Double click an example, e.g. [[Clock]] to view and edit the source. Most of the examples work, with the notable exception of those involving images. [[Download|./download.php]] this file and reopen it in Firefox to save your work.
[[Simon Baird|http://simonbaird.com/]] has made some great tweaks and examples, and put [[his version|http://tiddlyprocessing-simon.tiddlyspot.com]] up on [[TiddlySpot|http://tiddlyspot.com]], a great place to store your ~TiddlyWikis.
by Daniel Shiffman. Create a more complex wave by adding two waves together.
<<Processing
int xspacing = 8; // How far apart should each horizontal location be spaced
int w; // Width of entire wave
int maxwaves = 4; // total # of waves to add together
float theta = 0.0f;
float[] amplitude = new float[maxwaves]; // Height of wave
float[] dx = new float[maxwaves]; // Value for incrementing X, to be calculated as a function of period and xspacing
float[] yvalues; // Using an array to store height values for the wave (not entirely necessary)
void setup() {
size(200,200);
frameRate(30);
colorMode(RGB,255,255,255,100);
smooth();
w = width+16;
for (int i = 0; i < maxwaves; i++) {
amplitude[i] = random(10,30);
float period = random(100,300); // How many pixels before the wave repeats
dx[i] = (TWO_PI / period) * xspacing;
}
yvalues = new float[w/xspacing];
}
void draw() {
background(0);
calcWave();
renderWave();
}
void calcWave() {
// Increment theta (try different values for 'angular velocity' here
theta += 0.02;
// Set all height values to zero
for (int i = 0; i < yvalues.length; i++) {
yvalues[i] = 0.0f;
}
// Accumulate wave height values
for (int j = 0; j < maxwaves; j++) {
float x = theta;
for (int i = 0; i < yvalues.length; i++) {
// Every other wave is cosine instead of sine
if (j % 2 == 0) yvalues[i] += sin(x)*amplitude[j];
else yvalues[i] += cos(x)*amplitude[j];
x+=dx[j];
}
}
}
void renderWave() {
// A simple way to draw the wave with an ellipse at each location
noStroke();
fill(255,50);
ellipseMode(CENTER);
for (int x = 0; x < yvalues.length; x++) {
ellipse(x*xspacing,width/2+yvalues[x],16,16);
}
}
>>
Taken from [[basic/additivewave.html|http://ejohn.org/apps/processing.js/examples/basic/additivewave.html]]
Loads a "mask" for an image to specify the transparency in different parts of the image. The two images are blended together using the mask() method of PImage. Created 29 April 2003.
<<Processing
PImage img;
PImage maskImg;
void setup()
{
size(200,200);
img = loadImage("test.jpg");
maskImg = loadImage("mask.jpg");
img.mask(maskImg);
}
void draw()
{
background((mouseX+mouseY)/1.5);
image(img, 50, 50);
image(img, mouseX-50, mouseY-50);
}
>>
Taken from [[basic/alphamask.html|http://ejohn.org/apps/processing.js/examples/basic/alphamask.html]]
The angle of each segment is controlled with the mouseX and mouseY position. The transformations applied to the first segment are also applied to the second segment because they are inside the same pushMatrix() and popMatrix() group.
<<Processing
float x = 50;
float y = 100;
float angle1 = 0.0;
float angle2 = 0.0;
float segLength = 50;
void setup() {
size(200, 200);
smooth();
strokeWeight(20.0);
stroke(0, 100);
}
void draw() {
background(226);
angle1 = (mouseX/float(width) - 0.5) * -PI;
angle2 = (mouseY/float(height) - 0.5) * PI;
pushMatrix();
segment(x, y, angle1);
segment(segLength, 0, angle2);
popMatrix();
}
void segment(float x, float y, float a) {
translate(x, y);
rotate(a);
line(0, 0, segLength, 0);
}
>>
Taken from [[basic/arm.html|http://ejohn.org/apps/processing.js/examples/basic/arm.html]]
An array is a list of data. Each piece of data in an array is identified by an index number representing its position in the array. Arrays are zero based, which means that the first element in the array is [0], the second element is [1], and so on. In this example, an array named "coswav" is created and filled with the cosine values. This data is displayed three separate ways on the screen.
<<Processing
size(200, 200);
float[] coswave = new float[width];
for(int i=0; i<width; i++) {
float ratio = (float)i/(float)width;
coswave[i] = abs( cos(ratio*PI) );
}
for(int i=0; i<width; i++) {
stroke(coswave[i]*255);
line(i, 0, i, width/3);
}
for(int i=0; i<width; i++) {
stroke(coswave[i]*255/4);
line(i, width/3, i, width/3*2);
}
for(int i=0; i<width; i++) {
stroke(255-coswave[i]*255);
line(i, width/3*2, i, height);
}
>>
Taken from [[basic/array.html|http://ejohn.org/apps/processing.js/examples/basic/array.html]]
Demonstrates the syntax for creating a two-dimensional (2D) array. Values in a 2D array are accessed through two index values. 2D arrays are useful for storing images. In this example, each dot is colored in relation to its distance from the center of the image.
<<Processing
float[][] distances;
float maxDistance;
size(200, 200);
background(0);
maxDistance = dist(width/2, height/2, width, height);
distances = new float[width][height];
for(int i=0; i<height; i++) {
for(int j=0; j<width; j++) {
float d = dist(width/2, height/2, j, i);
distances[j][i] = d/maxDistance * 255;
}
}
for(int i=0; i<height; i+=2) {
for(int j=0; j<width; j+=2) {
stroke(distances[j][i]);
point(j, i);
}
}
>>
Taken from [[basic/array2d.html|http://ejohn.org/apps/processing.js/examples/basic/array2d.html]]
Demonstrates the syntax for creating an array of custom objects.
<<Processing
int unit = 40;
int num;
Module[] mods;
void setup()
{
size(200, 200);
background(176);
noStroke();
num = width/unit * width/unit;
mods = new Module[num];
for (int i=0; i<height/unit; i++) {
for(int j=0; j<height/unit; j++) {
int index = i*height/unit + j;
mods[index] = new Module(j*unit, i*unit, unit/2, unit/2, random(0.05, 0.8));
}
}
}
void draw()
{
for(int i=0; i<num; i++) {
mods[i].update();
mods[i].draw();
}
}
class Module {
float mx, my;
int size = unit;
float x, y = 0;
int xdir = 1;
int ydir = 1;
float speed;
// Contructor (required)
Module(float imx, float imy, float ix, float iy, float ispeed) {
mx = imy;
my = imx;
x = int(ix);
y = int(iy);
speed = ispeed;
}
// Custom method for updating the variables
void update() {
x = x + (speed * xdir);
if (x >= size || x <= 0) {
xdir *= -1;
x = x + (1 * xdir);
y = y + (1 * ydir);
}
if (y >= size || y <= 0) {
ydir *= -1;
y = y + (1 * ydir);
}
}
// Custom method for drawing the object
void draw() {
stroke(second()*4);
point(mx+x-1, my+y-1);
}
}
>>
Taken from [[basic/arrayobjects.html|http://ejohn.org/apps/processing.js/examples/basic/arrayobjects.html]]
This example presents the fastest way to load a background image into Processing. To load an image as the background, it must be the same width and height as the program.
<<Processing
PImage bg;
int a;
void setup()
{
size(200,200);
frameRate(30);
// The background image must be the same size as the parameters
// into the size() method. In this program, the size of "milan_rubbish.jpg"
// is 200 x 200 pixels.
bg = loadImage("milan_rubbish.jpg");
}
void draw()
{
background(bg);
a = (a + 1)%(width+32);
stroke(226, 204, 0);
line(0, a, width, a-26);
line(0, a-6, width, a-32);
}
>>
Taken from [[basic/backgroundimage.html|http://ejohn.org/apps/processing.js/examples/basic/backgroundimage.html]]
The first two parameters for the bezier() function specify the first point in the curve and the last two parameters specify the last point. The middle parameters set the control points that define the shape of the curve.
<<Processing
size(200, 200);
background(0);
stroke(255);
noFill();
smooth();
for(int i = 0; i < 100; i += 20) {
bezier(90-(i/2.0), 20+i, 210, 10, 220, 150, 120-(i/8.0), 150+(i/4.0));
}
>>
Taken from [[basic/bezier.html|http://ejohn.org/apps/processing.js/examples/basic/bezier.html]]
by Rusty Robison. Brightness is the relative lightness or darkness of a color. Move the cursor vertically over each bar to alter its brightness.
<<Processing
int barWidth = 5;
int[] brightness;
void setup()
{
size(200, 200);
colorMode(HSB, 360, height, height);
brightness = new int[width/barWidth];
}
void draw()
{
int j = 0;
for (int i = 0; i <= (width-barWidth); i += barWidth) {
noStroke();
if ((mouseX > i) && (mouseX < i+barWidth)) {
brightness[j] = mouseY;
}
fill(i, height, brightness[j]);
rect(i, 0, barWidth, height);
j++;
}
}
>>
Taken from [[basic/brightness.html|http://ejohn.org/apps/processing.js/examples/basic/brightness.html]]
Click on the image to give it focus and then type letters to shift the location of the image. Characters are typographic symbols such as A, d, and %. The character datatype, abbreviated as char, stores letters and symbols in the Unicode format, a coding system developed to support a variety of world languages. Characters are distinguished from other symbols by putting them between single quotes ('P'). A string is a sequence of characters. A string is noted by surrounding a group of letters with double quotes ("Processing"). Chars and strings are most often used with the keyboard methods, to display text to the screen, and to load images or files.
<<Processing
PImage frog;
PFont fontA;
int lettersize = 90;
int xoffset;
char letter;
void setup()
{
size(200, 200);
fontA = loadFont("Arial");
textFont(fontA);
textSize(lettersize);
// The String datatype must be capitalized because it is a complex datatype.
// A String is actually a class with its own methods, some of which are
// featured below.
String name= "rathausFrog";
String extension = ".jpg";
int nameLength = name.length();
println("The length of " + name + " is " + nameLength + ".");
name = name.concat(extension);
nameLength = name.length();
println("The length of " + name + " is " + nameLength + ".");
// The parameter for the loadImage() method must be a string
// This line could also be written "frog = loadImage("rathausFrog.jpg");
frog = loadImage(name);
}
void draw()
{
background(51); // Set background to dark gray
image(frog, xoffset, 0);
// Draw an X
line(0, 0, width, height);
line(0, height, width, 0);
// Get the width of the letter
int letterWidth = int(fontA.width(letter) * lettersize);
// Draw the letter to the center of the screen
text(letter, width/2-letterWidth/2, height/2);
}
void keyPressed()
{
// The variable "key" always contains the value of the most recent key pressed.
// If the key is an upper or lowercase letter between 'A' and 'z'
// the image is shifted to the corresponding value of that key
if(key >= 'A' && key <= 'z') {
letter = char(key);
// Scale the values to numbers between 0 and 100
float scale = 100.0/57.0;
int temp = int((key - 'A') * scale);
// Set the offset for the image
xoffset = temp;
println(key);
}
}
>>
Taken from [[basic/charactersstrings.html|http://ejohn.org/apps/processing.js/examples/basic/charactersstrings.html]]
The current time can be read with the second(), minute(), and hour() functions. In this example, sin() and cos() values are used to set the position of the hands. *
<<Processing
void setup() {
size(200, 200);
stroke(255);
smooth();
}
void draw() {
background(0);
fill(80);
noStroke();
// Angles for sin() and cos() start at 3 o'clock;
// subtract HALF_PI to make them start at the top
ellipse(100, 100, 160, 160);
float s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI;
float m = map(minute(), 0, 60, 0, TWO_PI) - HALF_PI;
float h = map(hour() % 12, 0, 12, 0, TWO_PI) - HALF_PI;
stroke(255);
strokeWeight(1);
line(100, 100, cos(s) * 72 + 100, sin(s) * 72 + 100);
strokeWeight(2);
line(100, 100, cos(m) * 60 + 100, sin(m) * 60 + 100);
strokeWeight(4);
line(100, 100, cos(h) * 50 + 100, sin(h) * 50 + 100);
}
>>
Taken from [[basic/clock.html|http://ejohn.org/apps/processing.js/examples/basic/clock.html]]
by Ira Greenberg. The primaries are red, yellow, and blue. The secondaries are green, purple, and orange. The tertiaries are yellow-orange, red-orange, red-purple, blue-purple, blue-green, and yellow-green. Create a shade or tint of the subtractive color wheel using SHADE or TINT parameters.
<<Processing
int segs = 12;
int steps = 6;
float rotAdjust = radians(360.0/segs/2.0);
float radius = 95.0;
float segWidth = radius/steps;
float interval = TWO_PI/segs;
int SHADE = 0;
int TINT = 1;
void setup(){
size(200, 200);
background(127);
smooth();
ellipseMode(CENTER_RADIUS);
noStroke();
// you can substitue TINT for SHADE argument
createWheel(width/2, height/2, SHADE);
}
void createWheel(int x, int y, int valueShift){
if (valueShift == SHADE){
for (int j=0; j<steps; j++){
color[]cols = {
color(255-(255/steps)*j, 255-(255/steps)*j, 0),
color(255-(255/steps)*j, (255/1.5)-((255/1.5)/steps)*j, 0),
color(255-(255/steps)*j, (255/2)-((255/2)/steps)*j, 0),
color(255-(255/steps)*j, (255/2.5)-((255/2.5)/steps)*j, 0),
color(255-(255/steps)*j, 0, 0),
color(255-(255/steps)*j, 0, (255/2)-((255/2)/steps)*j),
color(255-(255/steps)*j, 0, 255-(255/steps)*j),
color((255/2)-((255/2)/steps)*j, 0, 255-(255/steps)*j),
color(0, 0, 255-(255/steps)*j),
color(0, 255-(255/steps)*j, (255/2.5)-((255/2.5)/steps)*j),
color(0, 255-(255/steps)*j, 0),
color((255/2)-((255/2)/steps)*j, 255-(255/steps)*j, 0) };
for (int i=0; i< segs; i++){
fill(cols[i]);
arc(x, y, radius, radius, interval*i+rotAdjust, interval*(i+1)+rotAdjust);
}
radius -= segWidth;
}
} else if (valueShift == TINT){
for (int j=0; j<steps; j++){
color[]cols = {
color((255/steps)*j, (255/steps)*j, 0),
color((255/steps)*j, ((255/1.5)/steps)*j, 0),
color((255/steps)*j, ((255/2)/steps)*j, 0),
color((255/steps)*j, ((255/2.5)/steps)*j, 0),
color((255/steps)*j, 0, 0),
color((255/steps)*j, 0, ((255/2)/steps)*j),
color((255/steps)*j, 0, (255/steps)*j),
color(((255/2)/steps)*j, 0, (255/steps)*j),
color(0, 0, (255/steps)*j),
color(0, (255/steps)*j, ((255/2.5)/steps)*j),
color(0, (255/steps)*j, 0),
color(((255/2)/steps)*j, (255/steps)*j, 0) };
for (int i=0; i< segs; i++){
fill(cols[i]);
arc(x, y, radius, radius, interval*i+rotAdjust, interval*(i+1)+rotAdjust);
}
radius -= segWidth;
}
}
}
>>
Taken from [[basic/colorwheel.html|http://ejohn.org/apps/processing.js/examples/basic/colorwheel.html]]
An object can include several other objects. Creating such composite objects is a good way to use the principles of modularity and build higher levels of abstraction within a program.
<<Processing
EggRing er1, er2;
void setup()
{
size(200, 200);
smooth();
er1 = new EggRing(66, 132, 0.1, 66);
er2 = new EggRing(132, 180, 0.05, 132);
}
void draw()
{
background(0);
er1.transmit();
er2.transmit();
}
class EggRing
{
Egg ovoid;
Ring circle = new Ring();
EggRing(int x, int y, float t, float sp) {
ovoid = new Egg(x, y, t, sp);
circle.start(x, y - sp/2);
}
void transmit() {
ovoid.wobble();
ovoid.display();
circle.grow();
circle.display();
if (circle.on == false) {
circle.on = true;
}
}
}
class Egg {
float x, y; // X-coordinate, y-coordinate
float tilt; // Left and right angle offset
float angle; // Used to define the tilt
float scalar; // Height of the egg
// Constructor
Egg(int xpos, int ypos, float t, float s) {
x = xpos;
y = ypos;
tilt = t;
scalar = s / 100.0;
}
void wobble() {
tilt = cos(angle) / 8;
angle += 0.1;
}
void display() {
noStroke();
fill(255);
pushMatrix();
translate(x, y);
rotate(tilt);
scale(scalar);
beginShape();
vertex(0, -100);
bezierVertex(25, -100, 40, -65, 40, -40);
bezierVertex(40, -15, 25, 0, 0, 0);
bezierVertex(-25, 0, -40, -15, -40, -40);
bezierVertex(-40, -65, -25, -100, 0, -100);
endShape();
popMatrix();
}
}
class Ring {
float x, y; // X-coordinate, y-coordinate
float diameter; // Diameter of the ring
boolean on = false; // Turns the display on and off
void start(float xpos, float ypos) {
x = xpos;
y = ypos;
on = true;
diameter = 1;
}
void grow() {
if (on == true) {
diameter += 0.5;
if (diameter > width*2) {
diameter = 0.0;
}
}
}
void display() {
if (on == true) {
noFill();
strokeWeight(4);
stroke(155, 153);
ellipse(x, y, diameter, diameter);
}
}
}
>>
Taken from [[basic/compositeobjects.html|http://ejohn.org/apps/processing.js/examples/basic/compositeobjects.html]]
Conditions are like questions. They allow a program to decide to take one action if the answer to a question is true or to do another action if the answer to the question is false. The questions asked within a program are always logical or relational statements. For example, if the variable 'i' is equal to zero then draw a line.
<<Processing
size(200, 200);
background(0);
for(int i=10; i<width; i+=10) {
// If 'i' divides by 20 with no remainder draw the first line
// else draw the second line
if(i%20 == 0) {
stroke(153);
line(i, 40, i, height/2);
} else {
stroke(102);
line(i, 20, i, 180);
}
}
>>
Taken from [[basic/conditionals1.html|http://ejohn.org/apps/processing.js/examples/basic/conditionals1.html]]
We extend the language of conditionals by adding the keyword "else". This allows conditionals to ask two or more sequential questions, each with a different action.
<<Processing
size(200, 200);
background(0);
for(int i=2; i<width-2; i+=2) {
// If 'i' divides by 20 with no remainder
// draw the first line else draw the second line
if(i%20 == 0) {
stroke(255);
line(i, 40, i, height/2);
} else if (i%10 == 0) {
stroke(153);
line(i, 20, i, 180);
} else {
stroke(102);
line(i, height/2, i, height-40);
}
}
>>
Taken from [[basic/conditionals2.html|http://ejohn.org/apps/processing.js/examples/basic/conditionals2.html]]
Move the mouse across the screen to move the circle. The program constrains the circle to its box.
<<Processing
float mx;
float my;
float easing = 0.05;
float esize = 25.0;
int box = 30;
void setup()
{
size(200, 200);
noStroke();
smooth();
ellipseMode(CENTER_RADIUS);
}
void draw()
{
background(51);
if(abs(mouseX - mx) > 0.1) {
mx = mx + (mouseX - mx) * easing;
}
if(abs(mouseY - my) > 0.1) {
my = my + (mouseY- my) * easing;
}
float distance = esize * 2;
mx = constrain(mx, box+distance, width-box-distance);
my = constrain(my, box+distance, height-box-distance);
fill(76);
rect(box+esize, box+esize, box*3, box*3);
fill(255);
ellipse(mx, my, esize, esize);
}
>>
Taken from [[basic/constrain.html|http://ejohn.org/apps/processing.js/examples/basic/constrain.html]]
All shapes drawn to the screen have a position that is specified as a coordinate. All coordinates are measured as the distance from the origin in units of pixels. The origin [0, 0] is the coordinate is in the upper left of the window and the coordinate in the lower right is [width-1, height-1].
<<Processing
// Sets the screen to be 200, 200, so the width of the window is 200 pixels
// and the height of the window is 200 pixels
size(200, 200);
background(0);
noFill();
stroke(255);
// The two parameters of the point() method each specify coordinates.
// This call to point() draws at the position [100, 100]
point(width/2, height/2);
// Draws to the position [100, 50]
point(width/2, height/4);
// It is also possible to specify a point with any parameter,
// but only coordinates on the screen are visible
point(60, 30);
point(60, 134);
point(160, 50);
point(280, -800);
point(201, 100);
// Coordinates are used for drawing all shapes, not just points.
// Parameters for different methods are used for different purposes.
// For example, the first two parameters to line() specify the coordinates of the
// first point and the second two parameters specify the second point
stroke(204);
line(0, 73, width, 73);
// The first two parameters to rect() are coordinates
// and the second two are the width and height
rect(110, 55, 40, 36);
>>
Taken from [[basic/coordinates.html|http://ejohn.org/apps/processing.js/examples/basic/coordinates.html]]
The createGraphics() function creates an object from the PGraphics class (PGraphics is the main graphics and rendering context for Processing). The beginDraw() method is necessary to prepare for drawing and endDraw() is necessary to finish. Use this class if you need to draw into an off-screen graphics buffer or to maintain two contexts with different properties.
<<Processing
PGraphics pg;
void setup() {
size(200, 200);
pg = createGraphics(80, 80, P3D);
}
void draw() {
fill(0, 12);
rect(0, 0, width, height);
fill(255);
noStroke();
ellipse(mouseX, mouseY, 60, 60);
pg.beginDraw();
pg.background(102);
pg.noFill();
pg.stroke(255);
pg.ellipse(mouseX-60, mouseY-60, 60, 60);
pg.endDraw();
image(pg, 60, 60);
}
>>
Taken from [[basic/creategraphics.html|http://ejohn.org/apps/processing.js/examples/basic/creategraphics.html]]
The createImage() function provides a fresh buffer of pixels to play with. This example creates an image gradient.
<<Processing
PImage img;
void setup()
{
size(200, 200);
img = createImage(120, 120, RGB);
for(int i=0; i < img.pixels.length; i++) {
img.pixels[i] = color(0, 90, 102, i%img.width * 2);
}
}
void draw()
{
background(204);
image(img, 33, 33);
image(img, mouseX-60, mouseY-60);
}
>>
Taken from [[basic/createimage.html|http://ejohn.org/apps/processing.js/examples/basic/createimage.html]]
Creating variables for colors that may be referred to in the program by their name, rather than a number.
<<Processing
size(200, 200);
noStroke();
color inside = color(204, 102, 0);
color middle = color(204, 153, 0);
color outside = color(153, 51, 0);
// These statements are equivalent to the statements above.
// Programmers may use the format they prefer.
//color inside = #CC6600;
//color middle = #CC9900;
//color outside = #993300;
fill(outside);
rect(0, 0, 200, 200);
fill(middle);
rect(40, 60, 120, 120);
fill(inside);
rect(60, 90, 80, 80);
>>
Taken from [[basic/creating.html|http://ejohn.org/apps/processing.js/examples/basic/creating.html]]
It is sometimes beneficial to convert a value from one type of data to another. Each of the conversion functions converts its parameter to an equivalent representation within its datatype. The conversion functions include int(), float(), char(), byte(), and others.
<<Processing
size(200, 200);
background(51);
noStroke();
char c; // Chars are used for storing typographic symbols
float f; // Floats are decimal numbers
int i; // Ints are values between 2,147,483,647 and -2147483648
byte b; // Bytes are values between -128 and 128
c = 'A';
f = float(c); // Sets f = 65.0
i = int(f * 1.4); // Sets i to 91
b = byte(c / 2); // Sets b to 32
rect(f, 0, 40, 66);
fill(204);
rect(i, 67, 40, 66);
fill(255);
rect(b, 134, 40, 66);
>>
Taken from [[basic/datatypeconversion.html|http://ejohn.org/apps/processing.js/examples/basic/datatypeconversion.html]]
Images can be displayed to the screen at their actual size or any other size.
<<Processing
size(200, 200);
PImage a; // Declare variable "a" of type PImage
a = loadImage("arch.jpg"); // Load the images into the program
image(a, 0, 0); // Displays the image from point (0,0)
image(a, width/2, 0, a.width/2, a.height/2);
>>
Taken from [[basic/displaying.html|http://ejohn.org/apps/processing.js/examples/basic/displaying.html]]
Move the mouse across the image to obscure and reveal the matrix. Measures the distance from the mouse to each square and sets the size proportionally.
<<Processing
float max_distance;
void setup() {
size(200, 200);
smooth();
noStroke();
max_distance = dist(0, 0, width, height);
}
void draw()
{
background(51);
for(int i = 0; i <= width; i += 20) {
for(int j = 0; j <= width; j += 20) {
float size = dist(mouseX, mouseY, i, j);
size = size/max_distance * 66;
//opera.postError(i, j, size);
ellipse(i, j, size, size);
}
}
}
>>
Taken from [[basic/distance2d.html|http://ejohn.org/apps/processing.js/examples/basic/distance2d.html]]
by Ira Greenberg. Using 2 random() calls the and point() function to create an irregular sawtooth line.
<<Processing
size(200, 200);
background(0);
int totalPts = 300;
float steps = totalPts+1;
stroke(255);
float rand = 0;
for (int i=1; i< steps; i++){
point( (width/steps) * i, (height/2) + random(-rand, rand) );
rand += random(-5, 5);
}
>>
Taken from [[basic/doublerandom.html|http://ejohn.org/apps/processing.js/examples/basic/doublerandom.html]]
Move the mouse across the screen and the symbol will follow. Between drawing each frame of the animation, the program calculates the difference between the position of the symbol and the cursor. If the distance is larger than 1 pixel, the symbol moves half of the distance from its current position toward the cursor.
<<Processing
float x;
float y;
float targetX, targetY;
float easing = 0.05;
void setup()
{
size(200, 200);
smooth();
noStroke();
}
void draw()
{
background( 51 );
targetX = mouseX;
float dx = mouseX - x;
if(abs(dx) > 1) {
x += dx * easing;
}
targetY = mouseY;
float dy = mouseY - y;
if(abs(dy) > 1) {
y += dy * easing;
}
ellipse(x, y, 33, 33);
}
>>
Taken from [[basic/easing.html|http://ejohn.org/apps/processing.js/examples/basic/easing.html]]
Embedding "for" structures allows repetition in two dimensions.
<<Processing
float box_size = 11;
float box_space = 12;
int margin = 7;
size(200, 200);
background(0);
noStroke();
// Draw gray boxes
for(int i = margin; i < width-margin; i += box_space) {
for(int j = margin; j < height-margin; j += box_space) {
fill(255 - box_size*10);
rect(j, i, box_size, box_size);
}
box_size = box_size - 0.6;
}
>>
Taken from [[basic/embeddediteration.html|http://ejohn.org/apps/processing.js/examples/basic/embeddediteration.html]]
Click on the left button to open a different URL in the same window (Only works online). Click on the right button to open a URL in a new browser window. Created 21 June 2003.
<<Processing
boolean overLeftButton = false;
boolean overRightButton = false;
void setup()
{
size(200, 200);
}
void draw()
{
background(204);
// Left buttom
if(overLeftButton == true) {
fill(255);
} else {
noFill();
}
rect(20, 60, 75, 75);
rect(50, 90, 15, 15);
// Right button
if(overRightButton == true) {
fill(255);
} else {
noFill();
}
rect(105, 60, 75, 75);
line(135, 105, 155, 85);
line(140, 85, 155, 85);
line(155, 85, 155, 100);
}
void mousePressed()
{
if(overLeftButton) {
link("http://www.processing.org");
} else if (overRightButton) {
link("http://www.processing.org", "_new");
}
}
void mouseMoved() {
checkButtons();
}
void mouseDragged() {
checkButtons();
}
void checkButtons() {
if(mouseX > 20 && mouseX < 95 &&
mouseY > 60 && mouseY <135) {
overLeftButton = true;
} else if (mouseX > 105 && mouseX < 180 &&
mouseY > 60 && mouseY <135) {
overRightButton = true;
} else {
overLeftButton = overRightButton = false;
}
}
>>
Taken from [[basic/embeddedlinks.html|http://ejohn.org/apps/processing.js/examples/basic/embeddedlinks.html]]
The draw_target() function makes it easy to draw many distinct targets. Each call to draw_target() specifies the position, size, and number of rings for each target.
<<Processing
void setup()
{
size(200, 200);
background(51);
noStroke();
smooth();
noLoop();
}
void draw()
{
draw_target(68, 34, 200, 10);
draw_target(152, 16, 100, 3);
draw_target(100, 144, 80, 5);
}
void draw_target(int xloc, int yloc, int size, int num)
{
float grayvalues = 255/num;
float steps = size/num;
for(int i=0; i<num; i++) {
fill(i*grayvalues);
ellipse(xloc, yloc, size-i*steps, size-i*steps);
}
}
>>
Taken from [[basic/functions.html|http://ejohn.org/apps/processing.js/examples/basic/functions.html]]
by Daniel Shiffman. Graphics the following equation: sin(n*cos(r) + 5*theta) where n is a function of horizontal mouse location.
<<Processing
void setup() {
size(50,50);
frameRate(30);
}
void draw() {
loadPixels();
float n = (mouseX * 10.0) / width;
float w = 16.0; // 2D space width
float h = 16.0; // 2D space height
float dx = w / width; // Increment x this amount per pixel
float dy = h / height; // Increment y this amount per pixel
float x = -w/2; // Start x at -1 * width / 2
for (int i = 0; i < width; i++) {
float y = -h/2; // Start y at -1 * height / 2
for (int j = 0; j < height; j++) {
float r = sqrt((x*x) + (y*y)); // Convert cartesian to polar
float theta = atan2(y,x); // Convert cartesian to polar
// Compute 2D polar coordinate function
float val = sin(n*cos(r) + 5 * theta); // Results in a value between -1 and 1
//float val = cos(r); // Another simple function
//float val = sin(theta); // Another simple function
// Map resulting vale to grayscale value
pixels[i+j*width] = color((val + 1.0) * 255.0/2.0); // Scale to between 0 and 255
y += dy; // Increment y
}
x += dx; // Increment x
}
updatePixels();
}
>>
Taken from [[basic/graphing2dequation.html|http://ejohn.org/apps/processing.js/examples/basic/graphing2dequation.html]]
Hue is the color reflected from or transmitted through an object and is typically referred to as the name of the color (red, blue, yellow, etc.) Move the cursor vertically over each bar to alter its hue.
<<Processing
int barWidth = 5;
int[] hue;
void setup()
{
size(400, 400);
colorMode(HSB, 360, height, height);
hue = new int[width/barWidth];
noStroke();
}
void draw()
{
int j = 0;
for (int i=0; i<=(width-barWidth); i+=barWidth) {
if ((mouseX > i) && (mouseX < i+barWidth)) {
hue[j] = mouseY;
}
fill(hue[j], height/1.2, height/1.2);
rect(i, 0, barWidth, height);
j++;
}
}
>>
Taken from [[basic/hue.html|http://ejohn.org/apps/processing.js/examples/basic/hue.html]]
Writing "a++" is equivalent to "a = a + 1". Writing "a--" is equivalent to "a = a - 1".
<<Processing
int a;
int b;
boolean direction;
void setup()
{
size(200, 200);
colorMode(RGB, width);
a = 0;
b = width;
direction = true;
frameRate(30);
}
void draw()
{
a++;
if(a > width) {
a = 0;
direction = !direction;
}
if(direction == true){
stroke(a);
} else {
stroke(width-a);
}
line(a, 0, a, height/2);
b--;
if(b < 0) {
b = width;
}
if(direction == true) {
stroke(width-b);
} else {
stroke(b);
}
line(b, height/2+1, b, height);
}
>>
Taken from [[basic/incrementdecrement.html|http://ejohn.org/apps/processing.js/examples/basic/incrementdecrement.html]]
A class can be defined using another class as a foundation. In object-oriented programming terminology, one class can inherit fi elds and methods from another. An object that inherits from another is called a subclass, and the object it inherits from is called a superclass. A subclass extends the superclass.
<<Processing
SpinSpots spots;
SpinArm arm;
void setup()
{
size(200, 200);
smooth();
arm = new SpinArm(width/2, height/2, 0.01);
spots = new SpinSpots(width/2, height/2, -0.02, 33.0);
}
void draw()
{
background(204);
arm.update();
arm.display();
spots.update();
spots.display();
}
class Spin
{
float x, y, speed;
float angle = 0.0;
Spin(float xpos, float ypos, float s) {
x = xpos;
y = ypos;
speed = s;
}
void update() {
angle += speed;
}
}
class SpinArm extends Spin
{
SpinArm(float x, float y, float s) {
super(x, y, s);
}
void display() {
strokeWeight(1);
stroke(0);
pushMatrix();
translate(x, y);
angle += speed;
rotate(angle);
line(0, 0, 66, 0);
popMatrix();
}
}
class SpinSpots extends Spin
{
float dim;
SpinSpots(float x, float y, float s, float d) {
super(x, y, s);
dim = d;
}
void display() {
noStroke();
pushMatrix();
translate(x, y);
angle += speed;
rotate(angle);
ellipse(-dim/2, 0, dim, dim);
ellipse(dim/2, 0, dim, dim);
popMatrix();
}
}
>>
Taken from [[basic/inheritance.html|http://ejohn.org/apps/processing.js/examples/basic/inheritance.html]]
Integers and floats are two different kinds of numerical data. An integer (more commonly called an int) is a number without a decimal point. A float is a floating-point number, which means it is a number that has a decimal place. Floats are used when more precision is needed.
<<Processing
int a = 0; // Create a variable "a" of the datatype "int"
float b = 0.0; // Create a variable "b" of the datatype "float"
void setup()
{
size(200, 200);
stroke(255);
frameRate(30);
}
void draw()
{
background(51);
a = a + 1;
b = b + 0.2;
line(a, 0, a, height/2);
line(b, height/2, b, height);
if(a > width) {
a = 0;
}
if(b > width) {
b = 0;
}
}
>>
Taken from [[basic/integersfloats.html|http://ejohn.org/apps/processing.js/examples/basic/integersfloats.html]]
Iteration with a "for" structure constructs repetitive forms.
<<Processing
int k;
int xpos1 = 100;
int xpos2 = 118;
int count = 0;
int timey = 0;
int num = 12;
size(200, 200);
background(102);
noStroke();
// Draw gray bars
fill(255);
k=60;
for(int i=0; i < num/3; i++) {
rect(25, k, 155, 5);
k+=10;
}
// Black bars
fill(51);
k = 40;
for(int i=0; i < num; i++) {
rect(105, k, 30, 5);
k += 10;
}
k = 15;
for(int i = 0; i < num; i++) {
rect(125, k, 30, 5);
k +=10;
}
// Thin lines
k = 42;
fill(0);
for(int i=0; i < num-1; i++) {
rect(36, k, 20, 1);
k+=10;
}
>>
Taken from [[basic/iteration.html|http://ejohn.org/apps/processing.js/examples/basic/iteration.html]]
Click on the image to give it focus and press the letter keys to create forms in time and space. Each key has a unique identifying number called it's ASCII value. These numbers can be used to position shapes in space.
<<Processing
int numChars = 26;
color[] colors = new color[numChars];
int keyIndex;
float keyScale;
int rectWidth;
void setup()
{
size(200, 200);
noStroke();
background(0);
keyScale = 200/numChars-1.0;
rectWidth = width/4;
}
void draw()
{
if(keyPressed) {
if(key >= 'A' && key <= 'z') {
if(key <= 'Z') {
keyIndex = key-'A';
} else {
keyIndex = key-'a';
}
fill(millis()%255);
float beginRect = rectWidth/2 + keyIndex*keyScale-rectWidth/2;
rect(beginRect, 0.0, rectWidth, height);
}
}
}
>>
Taken from [[basic/keyboard.html|http://ejohn.org/apps/processing.js/examples/basic/keyboard.html]]
Modified from code by Martin. Original 'Color Typewriter' concept by John Maeda. Click on the window to give it focus and press the letter keys to type colors. The keyboard function keyPressed() is called whenever a key is pressed. keyReleased() is another keyboard function that is called when a key is released.
<<Processing
int max_height = 20;
int min_height = 10;
int letter_height = max_height; // Height of the letters
int letter_width = 10; // Width of the letter
int x = -letter_width; // X position of the letters
int y = 0; // Y position of the letters
boolean newletter;
int numChars = 26; // There are 26 characters in the alphabet
color[] colors = new color[numChars];
void setup()
{
size(200, 200);
noStroke();
colorMode(RGB, numChars);
background(numChars/2);
// Set a gray value for each key
for(int i=0; i<numChars; i++) {
colors[i] = color(i, i, i);
}
}
void draw()
{
if(newletter == true) {
// Draw the "letter"
int y_pos;
if (letter_height == max_height) {
y_pos = y;
rect( x, y_pos, letter_width, letter_height );
} else {
y_pos = y + min_height;
rect( x, y_pos, letter_width, letter_height );
fill(numChars/2);
rect( x, y_pos-min_height, letter_width, letter_height );
}
newletter = false;
}
}
void keyPressed()
{
// if the key is between 'A'(65) and 'z'(122)
if( key >= 'A' && key <= 'z') {
int keyIndex;
if(key <= 'Z') {
keyIndex = key-'A';
letter_height = max_height;
fill(colors[key-'A']);
} else {
keyIndex = key-'a';
letter_height = min_height;
fill(colors[key-'a']);
}
} else {
fill(0);
letter_height = 10;
}
newletter = true;
// Update the "letter" position
x = ( x + letter_width );
// Wrap horizontally
if (x > width - letter_width) {
x = 0;
y+= max_height;
}
// Wrap vertically
if( y > height - letter_height) {
y = 0; // reset y to 0
}
}
>>
Taken from [[basic/keyboardfunctions.html|http://ejohn.org/apps/processing.js/examples/basic/keyboardfunctions.html]]
Drawing letters to the screen in Processing uses a technology developed in the mid 1990s at the Visual Language Workshop at the MIT Media Laboratory. It is a closed system, but we have supplied a number of fonts located in the "font" directory in the main "processing" directory. We expect to change the Processing font technology in the future.
<<Processing
size(200, 200);
background(0);
// Load the font. Fonts are located within the
// main Processing directory/folder and they
// must be placed within the data directory
// of your sketch for them to load
PFont fontA = loadFont("Courier New");
textFont(fontA, 36);
textAlign(CENTER);
// Set the gray value of the letters
fill(255);
// Set the left and top margin
int margin = 6;
int gap = 30;
translate(margin*1.5, margin*2);
// Create a matrix of letterforms
int counter = 0;
for(int i=0; i<margin; i++) {
for(int j=0; j<margin; j++) {
char letter;
// Select the letter
int count = 65+(i*margin)+j;
if(count <= 90) {
letter = char(65+counter);
if(letter == 'A' || letter == 'E' || letter == 'I' ||
letter == 'O' || letter == 'U') {
fill(204, 204, 0);
} else {
fill(255);
}
} else {
fill(153);
letter = char(48+counter);
}
// Draw the letter to the screen
text(letter, 15+j*gap, 20+i*gap);
// Increment the counter
counter++;
if(counter >= 26) {
counter = 0;
}
}
}
>>
Taken from [[basic/letters.html|http://ejohn.org/apps/processing.js/examples/basic/letters.html]]
by Ira Greenberg. Using the convenient red(), green() and blue() component functions, generate some linear gradients.
<<Processing
// constants
int Y_AXIS = 1;
int X_AXIS = 2;
void setup(){
size(200, 200);
// create some gradients
// background
color b1 = color(190, 190, 190);
color b2 = color(20, 20, 20);
//setGradient(0, 0, width, height, b1, b2, Y_AXIS);
//center squares
color c1 = color(255, 120, 0);
color c2 = color(10, 45, 255);
color c3 = color(10, 255, 15);
color c4 = color(125, 2, 140);
color c5 = color(255, 255, 0);
color c6 = color(25, 255, 200);
setGradient(25, 25, 75, 75, c1, c2, Y_AXIS);
setGradient(100, 25, 75, 75, c3, c4, X_AXIS);
setGradient(25, 100, 75, 75, c2, c5, X_AXIS);
setGradient(100, 100, 75, 75, c4, c6, Y_AXIS);
}
void setGradient(int x, int y, float w, float h, color c1, color c2, int axis ){
// calculate differences between color components
float deltaR = red(c2)-red(c1);
float deltaG = green(c2)-green(c1);
float deltaB = blue(c2)-blue(c1);
// choose axis
if(axis == Y_AXIS){
/*nested for loops set pixels
in a basic table structure */
// column
for (int i=x; i<=(x+w); i++){
// row
for (int j = y; j<=(y+h); j++){
color c = color(
(red(c1)+(j-y)*(deltaR/h)),
(green(c1)+(j-y)*(deltaG/h)),
(blue(c1)+(j-y)*(deltaB/h))
);
set(i, j, c);
}
}
}
else if(axis == X_AXIS){
// column
for (int i=y; i<=(y+h); i++){
// row
for (int j = x; j<=(x+w); j++){
color c = color(
(red(c1)+(j-x)*(deltaR/h)),
(green(c1)+(j-x)*(deltaG/h)),
(blue(c1)+(j-x)*(deltaB/h))
);
set(j, i, c);
}
}
}
}
>>
Taken from [[basic/lineargradient.html|http://ejohn.org/apps/processing.js/examples/basic/lineargradient.html]]
The logical operators for AND (&&) and OR (||) are used to combine simple relational statements into more complex expressions. The NOT (!) operator is used to negate a boolean statement.
<<Processing
size(200, 200);
background(126);
boolean op = false;
for(int i=5; i<=195; i+=5) {
// Logical AND
stroke(0);
if((i > 35) && (i < 100)) {
line(5, i, 95, i);
op = false;
}
// Logical OR
stroke(76);
if((i <= 35) || (i >= 100)) {
line(105, i, 195, i);
op = true;
}
// Testing if a boolean value is "true"
// The expression "if(op)" is equivalent to "if(op == true)"
if(op) {
stroke(0);
point(width/2, i);
}
// Testing if a boolean value is "false"
// The expression "if(!op)" is equivalent to "if(op == false)"
if(!op) {
stroke(255);
point(width/4, i);
}
}
>>
Taken from [[basic/logicaloperators.html|http://ejohn.org/apps/processing.js/examples/basic/logicaloperators.html]]
The loop() function causes draw() to execute continuously. If noLoop is called in setup() the draw() is only executed once. In this example click the mouse to execute loop(), which will cause the draw() the execute continuously.
<<Processing
// The statements in the setup() function
// execute once when the program begins
void setup()
{
size(200, 200); // Size should be the first statement
stroke(255); // Set stroke color to white
noLoop();
}
float y = 100;
// The statements in draw() are run until the
// program is stopped. Each statement is run in
// sequence and after the last line is read, the first
// line is run again.
void draw()
{
background(0); // Set the background to black
line(0, y, width, y);
y = y - 1;
if (y < 0) {
y = height;
}
}
void mousePressed()
{
loop();
}
>>
Taken from [[basic/loop.html|http://ejohn.org/apps/processing.js/examples/basic/loop.html]]
A millisecond is 1/1000 of a second. Processing keeps track of the number of milliseconds a program has run. By modifying this number with the modulo(%) operator, different patterns in time are created.
<<Processing
float scale;
void setup()
{
size(200, 200);
noStroke();
scale = width/10;
}
void draw()
{
for(int i=0; i<scale; i++) {
colorMode(RGB, (i+1) * scale * 10);
fill(millis()%((i+1) * scale * 10) );
rect(i*scale, 0, scale, height);
}
}
>>
Taken from [[basic/milliseconds.html|http://ejohn.org/apps/processing.js/examples/basic/milliseconds.html]]
The modulo operator (%) returns the remainder of a number divided by another. As in this example, it is often used to keep numerical values within a set range. Created 12 January 2003.
<<Processing
int num = 20;
float c;
void setup()
{
size(200,200);
fill(255);
frameRate(30);
}
void draw()
{
background(0);
c+=0.1;
for(int i=1; i<height/num; i++) {
float x = (c%i)*i*i;
stroke(102);
line(0, i*num, x, i*num);
noStroke();
rect(x, i*num-num/2, 8, num);
}
}
>>
Taken from [[basic/modulo.html|http://ejohn.org/apps/processing.js/examples/basic/modulo.html]]
Move the mouse left and right to shift the balance. The "mouseX" variable is used to control both the size and color of the rectangles.
<<Processing
int gx = 15;
int gy = 35;
float leftColor = 0.0;
float rightColor = 0.0;
void setup()
{
size(200, 200);
colorMode(RGB, 1.0);
noStroke();
}
void draw()
{
background(0.0);
update(mouseX);
fill(0.0, leftColor + 0.4, leftColor + 0.6);
rect(width/4-gx, width/2-gx, gx*2, gx*2);
fill(0.0, rightColor + 0.2, rightColor + 0.4);
rect(width/1.33-gy, width/2-gy, gy*2, gy*2);
}
void update(int x)
{
leftColor = -0.002 * x/2 + 0.06;
rightColor = 0.002 * x/2 + 0.06;
gx = x/2;
gy = 100-x/2;
if (gx < 10) {
gx = 10;
} else if (gx > 90) {
gx = 90;
}
if (gy > 90) {
gy = 90;
} else if (gy < 10) {
gy = 10;
}
}
>>
Taken from [[basic/mouse1d.html|http://ejohn.org/apps/processing.js/examples/basic/mouse1d.html]]
Moving the mouse changes the position and size of each box.
<<Processing
void setup()
{
size(200, 200);
noStroke();
colorMode(RGB, 255, 255, 255, 100);
rectMode(CENTER);
}
void draw()
{
background(51);
fill(255, 80);
rect(mouseX, height/2, mouseY/2+10, mouseY/2+10);
fill(255, 80);
rect(width-mouseX, height/2, ((height-mouseY)/2)+10, ((height-mouseY)/2)+10);
}
>>
Taken from [[basic/mouse2d.html|http://ejohn.org/apps/processing.js/examples/basic/mouse2d.html]]
Click on the box and drag it across the screen.
<<Processing
float bx;
float by;
int bs = 20;
boolean bover = false;
boolean locked = false;
float bdifx = 0.0;
float bdify = 0.0;
void setup()
{
size(200, 200);
bx = width/2.0;
by = height/2.0;
rectMode(CENTER_RADIUS);
}
void draw()
{
background(0);
// Test if the cursor is over the box
if (mouseX > bx-bs && mouseX < bx+bs &&
mouseY > by-bs && mouseY < by+bs) {
bover = true;
if(!locked) {
stroke(255);
fill(153);
}
} else {
stroke(153);
fill(153);
bover = false;
}
// Draw the box
rect(bx, by, bs, bs);
}
void mousePressed() {
if(bover) {
locked = true;
fill(255, 255, 255);
} else {
locked = false;
}
bdifx = mouseX-bx;
bdify = mouseY-by;
}
void mouseDragged() {
if(locked) {
bx = mouseX-bdifx;
by = mouseY-bdify;
}
}
void mouseReleased() {
locked = false;
}
>>
Taken from [[basic/mousefunctions.html|http://ejohn.org/apps/processing.js/examples/basic/mousefunctions.html]]
Move the mouse to position the shape. Press the mouse button to invert the color.
<<Processing
void setup() {
size(200, 200);
fill(126);
background(102);
}
void draw() {
if(mousePressed) {
stroke(255);
} else {
stroke(0);
}
line(mouseX-66, mouseY, mouseX+66, mouseY);
line(mouseX, mouseY-66, mouseX, mouseY+66);
}
>>
Taken from [[basic/mousepress.html|http://ejohn.org/apps/processing.js/examples/basic/mousepress.html]]
Move and click the mouse to generate signals. The top row is the signal from "mouseX", the middle row is the signal from "mouseY", and the bottom row is the signal from "mousePressed".
<<Processing
int[] xvals;
int[] yvals;
int[] bvals;
void setup()
{
size(200, 200);
xvals = new int[width];
yvals = new int[width];
bvals = new int[width];
}
int arrayindex = 0;
void draw()
{
background(102);
for(int i=1; i<width; i++) {
xvals[i-1] = xvals[i];
yvals[i-1] = yvals[i];
bvals[i-1] = bvals[i];
}
// Add the new values to the end of the array
xvals[width-1] = mouseX;
yvals[width-1] = mouseY;
if(mousePressed) {
bvals[width-1] = 0;
} else {
bvals[width-1] = 255;
}
fill(255);
noStroke();
rect(0, height/3, width, height/3+1);
for(int i=1; i<width; i++) {
stroke(255);
point(i, xvals[i]/3);
stroke(0);
point(i, height/3+yvals[i]/3);
stroke(255);
line(i, 2*height/3+bvals[i]/3, i, (2*height/3+bvals[i-1]/3));
}
}
>>
Taken from [[basic/mousesignals.html|http://ejohn.org/apps/processing.js/examples/basic/mousesignals.html]]
A class can have multiple constructors that assign the fields in different ways. Sometimes it's beneficial to specify every aspect of an objectÕs data by assigning parameters to the fields, but other times it might be appropriate to define only one or a few.
<<Processing
Spot sp1, sp2;
void setup()
{
size(200, 200);
background(204);
smooth();
noLoop();
// Run the constructor without parameters
sp1 = new Spot();
// Run the constructor with three parameters
sp2 = new Spot(122, 100, 40);
}
void draw() {
sp1.display();
sp2.display();
}
class Spot {
float x, y, radius;
// First version of the Spot constructor;
// the fields are assigned default values
Spot() {
x = 66;
y = 100;
radius = 16;
}
// Second version of the Spot constructor;
// the fields are assigned with parameters
Spot(float xpos, float ypos, float r) {
x = xpos;
y = ypos;
radius = r;
}
void display() {
ellipse(x, y, radius*2, radius*2);
}
}
>>
Taken from [[basic/multipleconstructors.html|http://ejohn.org/apps/processing.js/examples/basic/multipleconstructors.html]]
By Ira Greenberg Draw a neighborhood of houses using Door, Window, Roof and House classes. Good example of class composition, with component Door, Window, Roof class references encapsulated within House class. This arrangement allows House class to handle placement and sizing of its components, while still allowing user customization of the individual components.
<<Processing
void setup(){
size(200, 200);
background(190);
smooth();
// Ground plane
int groundHeight = 10;
fill(0);
rect(0, height-groundHeight, width, groundHeight);
fill(255);
// Center the houses
translate(12, 0);
// Houses
Door door1 = new Door(20, 40);
Window window1 = new Window(50, 62, false, Window.DOUBLE);
Roof roof1 = new Roof(Roof.DOME);
House house1 = new House(75, 75, door1, window1, roof1, House.MIDDLE_DOOR);
house1.drawHouse(0, height-groundHeight-house1.h, true);
Door door2 = new Door(20, 40);
Window window2 = new Window(50, 62, true, Window.QUAD);
Roof roof2 = new Roof(Roof.GAMBREL);
House house2 = new House(100, 60, door2, window2, roof2, House.LEFT_DOOR);
house2.drawHouse(house1.x + house1.w, height-groundHeight-house2.h, true);
}
class Door{
//door properties
int x;
int y;
int w;
int h;
// for knob
int knobLoc = 1;
//constants
final static int RT = 0;
final static int LFT = 1;
// constructor
Door(int w, int h){
this.w = w;
this.h = h;
}
// draw the door
void drawDoor(int x, int y) {
rect(x, y, w, h);
int knobsize = w/10;
if (knobLoc == 0){
//right side
ellipse(x+w-knobsize, y+h/2, knobsize, knobsize);
}
else {
//left side
ellipse(x+knobsize, y+h/2, knobsize, knobsize);
}
}
// set knob position
void setKnob(int knobLoc){
this. knobLoc = knobLoc;
}
}
class Window{
//window properties
int x;
int y;
int w;
int h;
// customized features
boolean hasSash = false;
// single, double, quad pane
int style = 0;
//constants
final static int SINGLE = 0;
final static int DOUBLE = 1;
final static int QUAD = 2;
// constructor 1
Window(int w, int h){
this.w = w;
this.h = h;
}
// constructor 2
Window(int w, int h, int style){
this.w = w;
this.h = h;
this.style = style;
}
// constructor 3
Window(int w, int h, boolean hasSash, int style){
this.w = w;
this.h = h;
this.hasSash = hasSash;
this.style = style;
}
// draw the window
void drawWindow(int x, int y) {
//local variables
int margin = 0;
int winHt = 0;
int winWdth = 0;
if (hasSash){
margin = w/15;
}
switch(style){
case 0:
//outer window (sash)
rect(x, y, w, h);
//inner window
rect(x+margin, y+margin, w-margin*2, h-margin*2);
break;
case 1:
winHt = (h-margin*3)/2;
//outer window (sash)
rect(x, y, w, h);
//inner window (top)
rect(x+margin, y+margin, w-margin*2, winHt);
//inner windows (bottom)
rect(x+margin, y+winHt+margin*2, w-margin*2, winHt);
break;
case 2:
winWdth = (w-margin*3)/2;
winHt = (h-margin*3)/2;
//outer window (sash)
rect(x, y, w, h);
//inner window (top-left)
rect(x+margin, y+margin, winWdth, winHt);
//inner window (top-right)
rect(x+winWdth+margin*2, y+margin, winWdth, winHt);
//inner windows (bottom-left)
rect(x+margin, y+winHt+margin*2, winWdth, winHt);
//inner windows (bottom-right)
rect(x+winWdth+margin*2, y+winHt+margin*2, winWdth, winHt);
break;
}
}
// set window style (number of panes)
void setStyle(int style){
this.style = style;
}
}
class Roof{
//roof properties
int x;
int y;
int w;
int h;
// roof style
int style = 0;
//constants
final static int CATHEDRAL = 0;
final static int GAMBREL = 1;
final static int DOME = 2;
// default constructor
Roof(){
}
// constructor 2
Roof(int style){
this.style = style;
}
// draw the roof
void drawRoof(int x, int y, int w, int h) {
switch(style){
case 0:
beginShape();
vertex(x, y);
vertex(x+w/2, y-h/3);
vertex(x+w, y);
endShape(CLOSE);
break;
case 1:
beginShape();
vertex(x, y);
vertex(x+w/7, y-h/4);
vertex(x+w/2, y-h/2);
vertex(x+(w-w/7), y-h/4);
vertex(x+w, y);
endShape(CLOSE);
break;
case 2:
ellipseMode(CORNER);
arc(x, y-h/2, w, h, PI, TWO_PI);
line(x, y, x+w, y);
break;
}
}
// set roof style
void setStyle(int style){
this.style = style;
}
}
class House{
//house properties
int x;
int y;
int w;
int h;
//component reference variables
Door door;
Window window;
Roof roof;
//optional autosize variable
boolean AutoSizeComponents = false;
//door placement
int doorLoc = 0;
//constants
final static int MIDDLE_DOOR = 0;
final static int LEFT_DOOR = 1;
final static int RIGHT_DOOR = 2;
//constructor
House(int w, int h, Door door, Window window, Roof roof, int doorLoc) {
this.w = w;
this.h = h;
this.door = door;
this.window = window;
this.roof = roof;
this.doorLoc = doorLoc;
}
void drawHouse(int x, int y, boolean AutoSizeComponents) {
this.x = x;
this.y =y;
this.AutoSizeComponents = AutoSizeComponents;
//automatically sizes doors and windows
if(AutoSizeComponents){
//autosize door
door.h = h/4;
door.w = door.h/2;
//autosize windows
window.h = h/3;
window.w = window.h/2;
}
// draw bldg block
rect(x, y, w, h);
// draw door
switch(doorLoc){
case 0:
door.drawDoor(x+w/2-door.w/2, y+h-door.h);
break;
case 1:
door.drawDoor(x+w/8, y+h-door.h);
break;
case 2:
door.drawDoor(x+w-w/8-door.w, y+h-door.h);
break;
}
// draw windows
int windowMargin = (w-window.w*2)/3;
window.drawWindow(x+windowMargin, y+h/6);
window.drawWindow(x+windowMargin*2+window.w, y+h/6);
// draw roof
roof.drawRoof(x, y, w, h);
}
// catch drawHouse method without boolean argument
void drawHouse(int x, int y){
// recall with required 3rd argument
drawHouse(x, y, false);
}
}
>>
Taken from [[basic/neighborhood.html|http://ejohn.org/apps/processing.js/examples/basic/neighborhood.html]]
The noLoop() function causes draw() to only execute once. Without calling noLoop(), draw() executed continually.
<<Processing
// The statements in the setup() function
// execute once when the program begins
void setup()
{
size(200, 200); // Size should be the first statement
stroke(255); // Set line drawing color to white
frameRate(30);
noLoop();
}
float y = 100;
// The statements in draw() are executed until the
// program is stopped. Each statement is executed in
// sequence and after the last line is read, the first
// line is executed again.
void draw()
{
background(0); // Set the background to black
y = y - 1;
if (y < 0) { y = height; }
line(0, y, width, y);
}
>>
Taken from [[basic/noloop.html|http://ejohn.org/apps/processing.js/examples/basic/noloop.html]]
Using 1D Perlin Noise to assign location.
<<Processing
float xoff = 0.0;
float xincrement = 0.01;
void setup() {
size(200,200);
background(0);
frameRate(30);
smooth();
noStroke();
}
void draw()
{
// Create an alpha blended background
fill(0, 10);
rect(0,0,width,height);
//float n = random(0,width); // Try this line instead of noise
// Get a noise value based on xoff and scale it according to the window's width
float n = noise(xoff)*width;
// With each cycle, increment xoff
xoff += xincrement;
// Draw the ellipse at the value produced by perlin noise
fill(200);
ellipse(n,height/2,16,16);
}
>>
Taken from [[basic/noise1d.html|http://ejohn.org/apps/processing.js/examples/basic/noise1d.html]]
by Daniel Shiffman. Using 2D noise to create simple texture.
<<Processing
float increment = 0.02;
void setup() {
size(100,100);
noLoop();
}
void draw() {
background(0);
// Optional: adjust noise detail here
// noiseDetail(8,0.65f);
loadPixels();
float xoff = 0.0; // Start xoff at 0
// For every x,y coordinate in a 2D space, calculate a noise value and produce a brightness value
for