This is the API documentation for <graphics-element> source code, which at its code is simply plain JavaScript with a bunch of extra global constants and functions to allow you to quickly but cleanly get (interactive, and animated) graphics onto a page using the native web stack instead of needing some kind of build system.
Note that the index just below is ordered by category, but the full list itself is ordered alphabetically to allow you to search by scrolling as well as searching the index.
Also, if this made a difference in your dev life, consider (temporarily, even?) becoming a patron of my work over on my Patreon page, or send a one-time donation to help keep this project, and others like it, funded. Any amount is appreciated!
abs(v: number): number
v
- Any number
returns the input value with its sign set to positive
(number
)
Get the absolute value for some input
function draw() {
clear(`white`);
translate(0, height / 2);
noFill();
setStroke(`black`);
line(-huge, 0, huge, 0);
const w2 = width / 2;
const data = array(width, (x) => [x, x - w2, abs(x - w2)]);
setStroke(`red`);
plotData(data, 0, 1);
setStroke(`blue`);
plotData(data, 0, 2);
}
acos(v: number): number
v
- Any numberreturns the inverse cosine of that number (number
)
The inverse cosine function
acosh(input: number): number
input
- Any numberreturns the hyperbolic inverse cosine (number
)
The hyperbolic inverse cosine function
See https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Definitions_in_terms_of_logarithms
addButton(label: string, onClick: Function):
HTMLButtonElement
label
- The text label for your buttononClick
- The click handling function, see
description.
returns the button element this added to the page
(HTMLButtonElement
)
Add a button below your figure that can trigger event-based code, which is especially important if you want your graphics to be useable by users who don't have, or cannot use, a mouse.
onClick is similar to the standard JS event handler, except that the call argument is a reference to your button, not the click event.
const colors = [`white`, `black`];
let bgColor = 0;
function setup() {
setSize(200, 200);
addButton(`flip background`, (button) => {
bgColor = -(bgColor - 1);
redraw();
});
}
function draw() {
clear(colors[bgColor]);
}
addSlider(varName: string, options: object): HTMLInputElement
varName
- The name for the variable this slider gets
tied to.
options
- See description
returns the HTML input element for this slider
(HTMLInputElement
)
Add a slider to your figure, allowing users to control a variable in your graphics code directly by interacting with that on-page slider, which is especially important if you want your graphics to be useable by users who don't have, or cannot use, a mouse.
The propLabel
value should be the name of the variable that
your graphics code uses, and should not be
"preallocated" in your code with a const, let, or var: it will
automatically get added as part of the source loading process.
The options object accepts the following properties and values:
"slider"
The transform
pre-processor runs after the user updates the
slider, but before its value gets assigned to your variable, so that you
can map it to something else (for instance, numbers in one range to
numbers in a completely different range, or even numbers to strings or
entire objects)
function setup() {
setSize(400, 200);
addSlider(`bgColor`, {
min: 0,
max: 255,
step: 1,
value: 200,
transform: (v) => {
// convert v into a hex color code
v = v.toString(16).padStart(2, `0`);
return `#${v}${v}${v}`;
},
});
}
function draw() {
clear(bgColor);
}
arc(x: number, y: number, radius: number, startAngle: number,
endAngle: number, drawWedge: boolean)
x
- The circular center x pixel valuey
- The circular center y pixel valueradius
- The radius of this arc in pixelsstartAngle
- The start angle for this arc in radians
endAngle
- The end angle for this arc in radians
drawWedge
- A boolean indicating whether to draw a
wedge or capped circle (default=circle)
arc(point: PointLike, radius: number, startAngle: number, endAngle:
number, drawWedge: boolean)
point
- The circular center {x,y} coordinateradius
- The radius of this arc in pixelsstartAngle
- The start angle for this arc in radians
endAngle
- The end angle for this arc in radians
drawWedge
- A boolean indicating whether to draw a
wedge or capped circle (default=circle)
Draw a circular arc with radius r
at (x,y), starting at
angle s
and ending at angle e
. If
wedge
is true, this will draw a closed shape that is
anchored at (x,y). If omitted or explicitly set to false, this will draw
an open shape with a fill that connects the first and last point on the
arc, but no closing stroke.
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`#F002`);
arc(width / 2 + 30, height / 2 - 40, 40, 0, 0.66 * TAU);
arc(width / 2 - 30, height / 2 + 20, 40, 0, 0.66 * TAU, true);
}
array(length: number, fillFunction?: Function)
length
- The size of the array you wantfillFunction?
- The optional function that gets used
to fill the array
Create an array of specified length, optionally filled using a function that takes the element index as single input argument.
function draw() {
clear(`white`);
noFill();
translate(0, height / 2);
let data = array(width, (i) => [i, (height / 2) * sin(i / 25)]);
plotData(data, 0, 1);
}
asin(input: number): number
input
- Any numberreturns the inverse sine (number
)
The inverse sine function
asinh(input: number): number
input
- Any numberreturns the hyperbolic inverse sine (number
)
The hyperbolic inverse sine function
See https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Definitions_in_terms_of_logarithms
atan(input: number): number
input
- Any numberreturns the inverse tangent (number
)
The inverse tangent function
atan2(input: x): number
input
- Any number
returns the atan2 angle for this number pair (number
)
The "atan2" function
atanh(input: number): number
input
- Any numberreturns the hyperbolic inverse tangent (number
)
The hyperbolic inverse tangent function
See https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Definitions_in_terms_of_logarithms
axes(hLabel: string, hs: number, he: number, vLabel: string, vs:
number, ve: number, hsLabel?: string, heLabel?: string, vsLabel?:
string, veLabel?: string)
hLabel
- the horizontal axis labelhs
- the start (left) pixel value for the horizontal
axis
he
- the end (right) pixel value for the horizontal
axis
vLabel
- the vertical axis labelvs
- the start (top) pixel value for the vertical
axis
ve
- the end (bottom) pixel value for the vertical
axis
hsLabel?
- an optional label for the start (left) of
the horizontal axis
heLabel?
- an optional label for the end (right) of
the horizontal axis
vsLabel?
- an optional label for the start (top) of
the vertical axis
veLabel?
- an optional label for the end (bottom) of
the vertical axis
Draw a pair of horizontal and vertical axes.
function setup() {
setSize(200, 200);
setBorder(1, `black`);
setGrid(50, `lightgrey`);
}
function draw() {
setCursor(`none`);
clear(`#fffef7`);
setColor(`#333`);
translate(25, 25);
axes(
`time (s)`,
0,
width - 50,
`distance (km)`,
0,
height - 50,
"0",
"60",
"0",
"500",
);
}
bezier(...coordinates: number[8], ...additionalCoordinates?:
number[6n])
...coordinates
- Eight x, y values....additionalCoordinates?
- Multiples of six x, y
values.
bezier(...coordinates: PointLike[4], ...additionalCoordinates?:
PointLike[3n])
...coordinates
- Four {x,y} coordinates....additionalCoordinates?
- Multiples of three {x,y}
coordinates.
Draw one or more Bezier curves from an array of Point or Point-likes that implement:
{
x: number
y: number
}
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`#F002`);
bezier(
new Point(20, height - 55),
new Point(20, 25),
{ x: width - 20, y: 25 },
{ x: width - 20, y: height - 55 },
);
noFill();
bezier(
new Point(0, height - 20),
new Point(width - 20, height - 20),
{ x: 20, y: 20 },
{ x: width, y: 20 },
);
}
binomial(n: number, k: number): number
n
- A positive integerk
- A positive integer less than or equal to `n`
returns the value (n choose k) (number
)
Get the binomial coefficient (n choose k).
bspline(...coordinates: number[8], ...additionalCoordinates?:
number[2n])
...coordinates
- Eight x, y values....additionalCoordinates?
- Multiples of x, y values.
bspline(...coordinates: PointLike[4], ...additionalCoordinates?:
PointLike[n])
...coordinates
- Four {x,y} coordinates....additionalCoordinates?
- Zero or more {x,y}
coordinates.
Draw a B-spline using four or more Point or Point-likes that implement:
{
x: number
y: number
}
const points = [];
function setup() {
setSize(200, 200);
range(0, TAU, PI / 5, (a) =>
points.push(new Point(random(30) + 50 * cos(a), random(30) + 50 * sin(a))),
);
setMovable(...points);
}
function draw() {
clear(`white`);
translate(width / 2, height / 2);
noStroke();
setFill(`#0002`);
bspline(...points);
setColor(`red`);
points.forEach((p) => point(p));
}
constant
The constant for indicating a projector should be a "cabinet" projector, i.e. a projector without perspective, where coordinates further away are draw progressively more up and right, similar to the kind of pictures one might find in an instruction leaflet for building a cabinet.
cbrt(input: number): number
input
- Any number
returns the (real) cube root of that number (number
)
The cube root function
ceil(input: number): number
input
- Any number
returns the integer result after rounding up. (number
)
The "round up to the nearest integer" function.
center()
Centers the coordinate system on your graphic. This is equivalent to calling:
translate(width/2, height/2);
function draw() {
clear(`white`);
setColor(`red`);
center();
setColor(`black`);
line(0, -huge, 0, huge);
line(-huge, 0, huge, 0);
setColor(randomColor());
point(10, 10);
setColor(randomColor());
point(10, -10);
setColor(randomColor());
point(-10, -10);
setColor(randomColor());
point(-10, 10);
}
circle(x: number, y: number, r: number)
x
- The circle's center x pixel valuey
- The circle's center y pixel valuer
- The circle's radius in pixelscircle(p: PointLike, r: number)
p
- The circle's center {x,y} coordinater
- The circle's radius in pixelsDraw a circle with radius r
at x,y
.
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`#F002`);
circle(width / 2, height / 2, 80);
}
clear(color?: color)
color?
- The (CSS) background color to use (default =
`white`)
Clear the canvas, and set it to a specific (CSS) colour. If no
noGrid()
call was made, this will then also draw the
background grid.
function draw() {
clear(`pink`);
}
clearButtons()
Remove all buttons for your figure from the page.
function setup() {
setSize(200, 200);
addButton(`this does nothing`, () => {});
}
function draw() {
clear(`white`);
setColor(`black`);
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
text(`click to clear`, width / 2, height / 2);
}
function pointerDown() {
clearButtons();
}
clearMovable()
Empty the list of movable points in your graphic.
const points = [];
function setup() {
setSize(200, 200);
addButton(`lock`, () => {
clearMovable();
redraw();
});
}
function draw() {
clear(`white`);
for (let p of points) {
setColor(isMovable(p) ? `red` : `grey`);
point(p);
}
}
function pointerDown(x, y) {
if (currentMovable) return;
const p = new Point(x, y);
points.push(p);
setMovable(p);
redraw();
}
clearSliders()
Remove all sliders for your figure from the page.
function setup() {
setSize(200, 200);
addSlider(`x`);
}
function draw() {
clear(`white`);
setColor(`black`);
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
text(`click to clear`, width / 2, height / 2);
}
function pointerDown() {
clearSliders();
}
clz32(input: number): number
input
- Any number
returns the number of leading zero bits in the 32-bit binary
representation of that number. (number
)
Get the number of leading zero bits in the 32-bit binary representation of a number
color(hue: number, saturation: number, lightness: number, opacity:
number): string
hue
- in the range [0, 360]saturation
- in the range [0, 100]lightness
- in the range [0, 100]opacity
- in the range [0, 1]returns a CSS hsla color string (string
)
Generates a color based on the HSL color space.
function draw() {
clear(color(45, 80, 90));
}
constrain(value: number, lowerBound: number, upperBound: number):
number
value
- The value to constrainlowerBound
- The lower bound on our valueupperBound
- The upper bound on our value
returns the value, if it falls withing [lowerBound,upperBound],
otherwise one of those bounds. (number
)
Constrain a number to within a given range. This is really nothing more than a convenient function wrapper around the statement:
v < s ? s : v > e ? e : v
copy(): HTMLCanvasElement
returns a copy of the current canvas
(HTMLCanvasElement
)
Create a copy of the current canvas element for use somewhere else in your own code.
function draw() {
clear(`pink`);
}
function pointerDown(x, y) {
document.dispatchEvent(
new CustomEvent(`graphics:update`, {
detail: {
canvas: copy(),
},
}),
);
}
cos(input: number): number
input
- Any numberreturns the cosine (number
)
The cosine function
cosh(input: number): number
input
- Any numberreturns the hyperbolic cosine (number
)
The hyperbolic cosine function
See https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Definitions_in_terms_of_logarithms
cot(input: number): number
input
- Any numberreturns the cotangent (number
)
The cotangent function
createProjector(projectorType: Symbol): Projector
projectorType
- This sets up a new projector, of type
CABINET or
HOMOGENOUS.
returns a new projector instance. (Projector
)
Create a 3D to 2D projector. This can be either a
CABINET
or HOMOGENEOUS
projector, supporting
the following API:
projector.setRotation(x, y, z)
projector.setTranslation(tx, ty, tz)
projector.setScale(tx, ty, tz)
furthermore, the CABINET
projector supports setting the
default cabinet angle using:
projector.setPhi(phi)
and the HOMOGENEOUS
projection supports setting the
distance of the point-at-infinity by using:
projector.setInfinity(distance)
(note,
distance
can be Infinity
)
const cabinet = createProjector(CABINET);
const homogeneous = createProjector(HOMOGENEOUS);
const bottom = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
const top = bottom.map((v) => [v[0], v[1], 1]);
function setup() {
setSize(400, 200);
cabinet.setScale(50);
homogeneous.setScale(50);
}
function draw() {
clear(`white`);
translate(-width / 4, height / 2);
[cabinet, homogeneous].forEach((projector) => {
setProjector(projector);
translate(width / 2, 0);
drawAxisPoints();
drawCube();
});
}
function drawAxisPoints() {
setColor(`black`);
point(...bottom[0]);
setColor(`red`);
point(...bottom[1]);
setColor(`green`);
point(...bottom[3]);
setColor(`blue`);
point(...top[0]);
}
function drawCube() {
noFill();
setStroke(`red`);
[bottom, top].forEach((r) => {
line(...r[0], ...r[1]);
line(...r[2], ...r[3]);
});
setStroke(`green`);
[bottom, top].forEach((r) => {
line(...r[1], ...r[2]);
line(...r[3], ...r[0]);
});
setStroke(`blue`);
[0, 1, 2, 3].forEach((i) => line(...bottom[i], ...top[i]));
}
csc(value: number): number
value
- The input value, in radians.returns the cosecant of our value. (number
)
The cosecant function, which is:
1 / sin(v)
ctn(value: number): number
value
- The input value, in radians.returns the cotangent of our value. (number
)
The cotangent function, which is:
cos(v) / sin(v)
constant
If any points were registered as movable, and the pointer is near enough
to a movable point, this value will point to that movable point, or
false
if the pointer is not near any movable point (or, of
course, there are no movable points)
degrees(value: number, constrain?: boolean): number
value
- The value to constrainconstrain?
- A boolean that determines whether or not
to constrain the resultant value to [0, 360] (default = false)
returns the degree value corresponding to the input value in
radians, optionally constrained to [0, 360] (number
)
Convert a number in radians to a number in degrees. This is really nothing more than a convenient function wrapper around the statement:
v/PI * 180
With one trick, in that it allows you to constrain the resultant value to the standard [0, 360] interval.
dist(x1: number, y1: number, x2: number, y2: number): number
x1
- The first point's x pixel valuey1
- The first point's y pixel valuex2
- The second point's x pixel valuey2
- The second point's y pixel value
returns the euclidean distance between the two coordinates
(number
)
dist(p1: PointLike, p2: PointLike): number
p1
- The first point's {x,y} coordinatep2
- The second point's {x,y} coordinate
returns the euclidean distance between the two coordinates
(number
)
Calculate the 2D Euclidean distance between two points.
constant
The base for the natural logarithm.
end(close?: boolean)
close?
- A boolean that indicates whether or not to
close the path (default = false)
Counterpart to start(), finalizes the current shape and colours it. If
close
is true, it will close the path before colouring.
If noFill()
is in effect, the shape will not be filled. if
noStroke()
is in effect, the shape outline will not be
coloured.
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`gold`);
start();
vertex(0, height / 2);
vertex(width / 2, 0);
vertex(width, height / 2);
vertex(width / 2, height);
end(true);
}
endShape(close?: boolean): Shape
close?
- When used, closes the shape's current
segment.
returns the shape that got closed (Shape
)
Clear the current shape, optionally closing it.
constant
A very small value for performing imprecise math operations such as checking whether a value is approximately the same as some other value.
exp(input: number): number
input
- Any number
returns the value of E raised to that number's power
(number
)
The exponent function, that is: e^x
find(querySelector: string): HTMLElement|null
querySelector
- A query selector
returns the matched element, or null if there was no match.
(HTMLElement|null
)
Find an HTML element inside your graphics-element by query selector. This is equivalent to:
yourElement.querySelector(qs)
findAll(querySelector: string): HTMLElement[]
querySelector
- A query selector
returns an array with all matching elements, [] if there were no
matches. (HTMLElement[]
)
Find all HTML elements inside your graphics-element that match a given query selector. This is equivalent to:
Array.from(yourElement.querySelectorAll(qs))
floor(input: number): number
input
- Any number
returns the integer result after rounding down.
(number
)
The "round down to the nearest integer" function.
constant
The current frame number
constant
The number of milliseconds since the last frame.
fround(input: number): number
input
- Any number
returns the number after rounding to the nearest 32 bit floating
point representation. (number
)
Round a number to the nearest 32 bit, rather than the standard JS 64 bit, floating point representation.
constant
The height of the canvas in pixels
highlight(color: color|boolean)
color
- Set the color that should get replaced with
the highlight color, or disable highlight when color is `false`
Mark a specific color as the highlight color, which causes the graphic to redraw with that color replaced by whichever color you picked as highlight color.
Note that you can only use named (CSS) colors with this function.
function setup() {
setSize(200, 200);
setHighlightColor(`lime`);
}
function draw() {
clear();
setColor(`red`);
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
text("let's go", width / 2, height / 2);
}
function pointerActive(state) {
if (state) highlight(`red`);
else highlight(false);
}
constant
The constant for indicating a projector should be a "normal" homogeneous projector, i.e. projection with a "point at infinity" and normal perspective applied.
constant
A very large value that can still be used to draw things on the canvas (such as lines from -huge to +huge).
hypot(...input: number[]): number
...input
- Two or more numbers
returns the hypotenuse given those numbers. (number
)
The Euclidean hypotenuse function
image(imgOrURL: Image|string, x: number, y: number, w: number, h:
number): Image
imgOrURL
- The image to draw either as Image object,
or image URL.
x
- The draw position's x pixel valuey
- The draw position's y pixel valuew
- The width over which to draw the imageh
- The height over which to draw the imagereturns the drawn image (Image
)
image(imgOrURL: Image|string, p: PointLike, w: number, h: number):
Image
imgOrURL
- The image to draw either as Image object,
or image URL.
p
- The draw position as {x,y} coordinatew
- The width over which to draw the imageh
- The height over which to draw the imagereturns the drawn image (Image
)
Draw an image in a given location with an optional width and height. If omitted, the width and height will be the image's own dimensions. Note that the image may be either a URL, or an element.
Note that this is an async function: if it is important that nothing
gets drawn until the image has been drawn, remember to
await
its call.
async function draw() {
clear(`white`);
await image(`https://dummyimage.com/100x100`, 50, 50, 100, 100);
}
imul(a: number, b: number): number
a
- Any 32 bit integerb
- Any 32 bit integer
returns the 32 bit integer result of a * b (number
)
The 32 bit integer multiplication function.
invertMatrix(M: Matrix): number[][]
M
- The matrix to invert
returns the matrix inverse as 2D number array
(number[][]
)
Invert a matrix, or undefined if the matrix is not invertible.
isMovable(The: PointLike): boolean
The
- point that we want to check "movability" for
returns true if our point is in the list of movable points,
otherwise false (boolean
)
Check whether a point is registered as movable.
const points = [];
function setup() {
setSize(200, 200);
addButton(`lock`, () => {
clearMovable();
redraw();
});
}
function draw() {
clear(`white`);
for (let p of points) {
setColor(isMovable(p) ? `red` : `grey`);
point(p);
}
}
function pointerDown(x, y) {
if (currentMovable) return;
const p = new Point(x, y);
points.push(p);
setMovable(p);
redraw();
}
constant
The keyboard
object is a truth table that can be checked to
see if any key is currently pressed, and if so, when that keypress was
initiated, by storing:
{
[key:string]: datetime
}
When a key is released, its mapping is removed entirely, rather than it being set to a falsey value.
line(x1: number, y1: number, x2: number, y2: number)
x1
- The first point's x pixel valuey1
- The first point's y pixel valuex2
- The second point's x pixel valuey2
- The second point's y pixel valueline(p1: PointLike, p2: PointLike)
p1
- The first point's {x,y} coordinatep2
- The second point's {x,y} coordinateDraw a line from one coordinate to another.
function draw() {
clear(`white`);
setStroke(`black`);
range(0, height, 20, (i) => line(0, 0, width, i));
}
lli(x1: number, y1: number, x2: number, y2: number, x3: number, y3:
number, x4: number, y4: number): PointLike|false
x1
- The first point's x coordinatey1
- The first point's y coordinatex2
- The second point's x coordinatey2
- The second point's y coordinatex3
- The third point's x coordinatey3
- The third point's y coordinatex4
- The fourth point's x coordinatey4
- The fourth point's y coordinate
returns either the intersection point, or false if there is no
intersection (PointLike|false
)
lli(p1: PointLine, p2: PointLine, p3: PointLine, p4: PointLine):
PointLike|false
p1
- The first coordinatep2
- The second coordinatep3
- The third coordinatep4
- The fourth coordinate
returns either the intersection point, or false if there is no
intersection (PointLike|false
)
Performs a line/line intersection test give either four points defining the lines (p1--p2) and (p3--p4), or eight coordinates spanning lines (x1,y1)--(x2,y2) and (x3,y3)--(x4,y4).
This function covers both "line/line" and
"segment"/"segment" testing by setting a boolean
value inBounds
on the result: when false, there is only a
line/line intersection, but when true, the actual line segments
intersect.
function draw() {
clear();
center();
// ...code goes here...
}
ln(input: number): number
input
- Any number
returns the natural logarithm of that number (number
)
The natural logarithm function, i.e. the base-E logarithm
(Note that in JS this function is called "log" rather than "ln")
log(input: number): number
input
- Any number
returns the common logarithm of that number (number
)
The "common logarithm" function, i.e. the base-10 logarithm.
(Note that in JS this function is called "log10" rather than "log")
log2(input: number): number
input
- Any number
returns the base 2 logarithm of that number (number
)
The binary logarithm function, i.e. the base-2 logarithm.
map(value: number, originalStart: number, originalEnd: number,
newStart: number, newEnd: number, constrain?: boolean): number
value
- Our input valueoriginalStart
- The lower bound of our domainoriginalEnd
- The upper bound of our domainnewStart
- The lower bound of our target interval
newEnd
- The upper bound on our target interval
constrain?
- A boolean that determines whether or not
to constrain the resultant value to [newStart,newEnd] (default =
false)
returns the result of mapping our value from our domain interval to
our target interval, optionally constrained to the target interval.
(number
)
Map a value from one interval to another, optionally constrained to the target interval.
max(...input: number): number
...input
- Any two or more numbers
returns the highest valued number from among the input.
(number
)
Find the maximum value in a set of numbers
millis(): number
returns number of milliseconds since the graphic loaded in
(number
)
Get the number of milliseconds that this graphic has been running.
function setup() {
setSize(200, 200);
setColor(`black`);
play();
}
function draw() {
clear();
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
const seconds = (millis() / 1000) | 0;
text(`${seconds}s`, width / 2, height / 2);
}
min(...input: number): number
...input
- Any two or more numbers
returns the lowest valued number from among the input.
(number
)
Find the minimum value in a set of numbers
multiplyMatrix(m1: Matrix, m2: Matrix): number[][]
m1
-m2
-
returns the result of m1 * m2 as 2D number array
(number[][]
)
Multiply two matrices
newSegment(close?: boolean)
close?
- Closes the current segment before opening a
new one (default = true)
Start a new segment in a shape.
noBorder()
Ensure that there is no border around the canvas element.
function setup() {
setSize(200, 200);
setBorder(5, `red`);
}
function draw() {
clear(`white`);
setColor(`black`);
setTextAlign(CENTER, MIDDLE);
setFontSize(25);
text(`click me`, width / 2, height / 2);
}
function pointerUp(x, y) {
setBorder(5, `red`);
redraw();
}
function pointerDown(x, y) {
noBorder();
redraw();
}
noColor()
Disable both stroke and fill color.
function draw() {
clear(`white`);
setColor(`black`);
setTextAlign(CENTER, MIDDLE);
setFontSize(25);
text(`Now you see me`, width / 2, height / 2 - 25);
noColor();
text(`Now you don't`, width / 2, height / 2 + 25);
}
noCursor()
Hide the cursor.
function draw() {
clear(`white`);
setColor(`#FF02`);
rect(0, 0, width / 2, height);
setColor(`#0FF2`);
rect(width / 2, 0, width / 2, height);
}
function pointerMove(x, y) {
if (x < width / 2) {
setCursor(AUTO);
} else {
noCursor();
}
}
noFill()
Disable the fill color.
function draw() {
clear(`white`);
setTextAlign(CENTER, MIDDLE);
setFontSize(25);
setTextStroke(1);
setColor(`black`);
rect(20, 70, 20, 20);
text(`filled`, width / 2, height / 2 - 25);
noFill();
rect(30, 80, 20, 20);
text(`not filled`, width / 2, height / 2 + 25);
}
noGrid()
Disable the default grid background.
function draw() {
clear(`white`);
setColor(`black`);
setTextAlign(CENTER, MIDDLE);
setFontSize(25);
text(`click me`, width / 2, height / 2);
}
function pointerUp(x, y) {
setGrid(20, `lightgrey`);
redraw();
}
function pointerDown(x, y) {
noGrid();
redraw();
}
noLineDash()
Set the line stroke to "solid".
function draw() {
clear(`white`);
setColor(`black`);
setLineDash(1);
line(0, 20, width, 50);
setLineDash(5);
line(0, 30, width, 90);
setLineDash(1, 2, 3, 4);
line(0, 40, width, 130);
noLineDash();
line(0, 50, width, 180);
}
noProjection()
(Temporarily) disable the 3D projector without unbinding it, allowing you to mix projective 3D and regular 2D with relatively little effort.
const plane = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
function setup() {
setSize(200, 200);
setProjector(HOMOGENEOUS);
scaleProjector(50);
}
function draw() {
clear(`white`);
center();
noProjection();
setFill(`#F0F5`);
poly(plane.map((v) => [50 * v[0], 50 * v[1]]));
useProjection();
setStroke(`#333`);
setFill(`#FF05`);
poly(plane);
}
noProjector()
Unset the 3D projector, if one is currently active. This is equivalent
to calling setProjector(false)
, and will turn off
projection and unbind the current projector. This can
be useful, but most of the time you'll want to use the
useProjection and
noProjection functions instead.
const plane = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
function setup() {
setSize(200, 200);
setProjector(HOMOGENEOUS);
scaleProjector(50);
}
function draw() {
clear(`white`);
center();
setStroke(`#333`);
setFill(`#FF05`);
poly(plane);
noProjector();
setFill(`#F0F5`);
poly(plane.map((v) => [50 * v[0], 50 * v[1]]));
}
noStroke()
Disable the stroke color.
function draw() {
clear(`white`);
setTextAlign(CENTER, MIDDLE);
setFontSize(25);
setTextStroke(1);
setColor(`red`);
setStroke(`black`);
rect(20, 70, 20, 20);
text(`stroked`, width / 2, height / 2 - 25);
noStroke();
rect(42, 82, 20, 20);
text(`not stroked`, width / 2, height / 2 + 25);
}
noTextStroke()
Disable text stroking, but not regular shape stroking.
function draw() {
clear(`white`);
setTextAlign(CENTER, MIDDLE);
setFontSize(25);
setTextStroke(1);
setColor(`red`);
setStroke(`black`);
rect(20, 70, 20, 20);
text(`stroked`, width / 2, height / 2 - 25);
noTextStroke();
rect(42, 82, 20, 20);
text(`not stroked`, width / 2, height / 2 + 25);
}
pause()
Pause the graphic if its currently playing.
function setup() {
setSize(200, 200);
setColor(`black`);
play();
}
function draw() {
clear();
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
const seconds = (millis() / 1000).toFixed(1);
text(`${seconds}s`, width / 2, height / 2);
}
function pointerActive(state) {
if (state) {
pause();
} else {
play();
}
}
constant
The ratio of a circle's circumference to its diameter.
See https://en.wikipedia.org/wiki/Pi
play()
Start playing your graphic, meaning it will call draw() at whatever rate the requestAnimationFrame loop is allowed to run on your computer.
let fps = 0;
let checked = false;
let lastFrameCheck = 0;
function setup() {
setSize(200, 200);
setColor(`black`);
play();
}
function draw() {
clear();
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
const seconds = (millis() / 1000).toFixed(1);
text(`fps: ${fps}`, width / 2, height / 2);
if (seconds.endsWith(`.0`)) {
if (!checked) {
checked = true;
fps = frame - lastFrameCheck;
lastFrameCheck = frame;
}
} else {
checked = false;
}
}
constant
The current play state
plot(f: Function, a?: number, b?: number, steps?: number, xscale?:
number, yscale?: number, ignoreDiscontinuity?: boolean)
f
- the `y = f(x)` function to plota?
- The lower bound for the input value (default =
0)
b?
- The upper bound for the input value (default =
1)
steps?
- The number of plot points to plot over the
interval [a,b] (default = 100)
xscale?
- An optional scaling factor to apply to each
plot point's x value (default = 1)
yscale?
- An optional scaling factor to apply to each
plot point's y value (default = 1)
ignoreDiscontinuity?
- Do not draw special elements
for discontinuities (default = false)
Plot a y=f(x) function. The input to the function will span the interval [a,b] using the indicated number of steps, and the re sult may be scaled both in the x and y direction in order to draw something that you can actually see (e.g. if you're plotting to the domain [0,1] you wouldn't be able to see the result without scaling).
This function is aware of, and will plot, discontinuities using the
standard open circle notation, unless instructed not to do so using the
ignoreDiscontinuity
boolean flag.
function draw() {
clear(`white`);
noFill();
setStroke(`black`);
translate(0, height / 2);
const fn = (x) => cos(x) ** 6 / sin(x) - sin(x) / 2;
plot(fn, 0, 2 * TAU, 120, width / TAU, height / 2);
}
plotData(data: object[], x?: number|string, y?:
number|string)
data
- The any-dimensional data from which to plot
one dimension again another
x?
- The property name or individual element array
index to use as x dimension
y?
- The property name or individual element array
index to use as y dimension
Plot a 2D graph using a collection of any-dimensional data, by
indicating which dimension should be treated as the x
and
which dimension should be treated as the y
. If no
x
and y
are provided, data
will
be treated a 1D array and will plot with the array index as
x
and element at that index as y
.
function draw() {
clear(`white`);
noFill();
translate(0, height / 2);
setStroke(`darkgreen`);
let data = array(width, (i) => [i, (height / 2) * sin(i / 25)]);
plotData(data, 0, 1);
setStroke(`purple`);
data = array(width, (i) => ({
meep: i,
moop: (height / 2) * cos(i / 25),
}));
plotData(data, `meep`, `moop`);
}
point(x: number, y: number)
x
- The point's center x pixel valuey
- The point's center y pixel valuepoint(p: PointLike)
p
- The point's center {x,y} coordinateDraw a point (either from x/y or point-like).
function draw() {
clear(`white`);
translate(width / 2, height / 2);
range(0, TAU, (a) => {
point(40 * cos(a), 40 * sin(a));
});
}
constant
The pointer
object represents the mouse cursor (when using
a mouse) or finger position (for touch devices), and models several
aspects:
active
(boolean) Whether the pointer is even on or over
the canvas.
x
(number) The pointer's x offset in pixels with
respect to the canvas
y
(number) The pointer's y offset in pixels with
respect to the canvas
down
(boolean) Whether the pointer is "engaged"
or not
drag
(boolean) Whether a click/touch-drag is in progress
mark
({x,y}) When dragging, this represents the original
coordinate of the pointer "down" event
poly(coordinates: number[])
coordinates
- The array of polygon vertices as
point-likes or number arrays.
Draw a closed polygon from an array of point likes or number arrays.
function draw() {
clear(`white`);
center();
setStroke(`black`);
setFill(`orange`);
poly([[-50, -50], [-50, 50], { x: 50, y: 50 }, new Point(50, -50)]);
}
pow(a: number, b: number): number|NaN
a
- Any numberb
- Any number
returns output a ** b or NaN if that is undefined
(number|NaN
)
The power function.
Note that this function is a holdover from before JS had the
**
operator for performing this calculation.
project(x: number, y: number, z: number): PointLike
x
- The 3D coordinate's x valuey
- The 3D coordinate's x valuez
- The 3D coordinate's x value
returns p The projected 2D {x,y} coordinate (PointLike
)
project(p: PointLike): PointLike
p
- The 2D coordinate as {x,y,z} coordinate
returns p The projected 2D {x,y} coordinate (PointLike
)
Project a 3D "world" coordinate to a 2D "screen" coordinate.
const plane = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
function setup() {
setSize(200, 200);
setProjector(HOMOGENEOUS);
scaleProjector(50);
}
function draw() {
clear(`white`);
translate(width / 2, height / 4);
setColor(`orange`);
setStroke(`black`);
// Note that this is not "useful" code, as you will
// rarely, if ever, need to manually project coordinate.
// In this case, you could just call `poly(plane)` instead.
start();
plane.forEach((p) => vertex(project(...p)));
vertex(project(...plane[0]));
end();
}
radians(value: number, constrain?: boolean): number
value
- The value to constrainconstrain?
- A boolean that determines whether or not
to constrain the resultant value to [0, TAU] (default = false)
returns the radians value corresponding to the input value in
degrees, optionally constrained to [0, TAU] (number
)
Convert a number in degrees to a number in radians. This is really nothing more than a convenient function wrapper around the statement:
v/180 * PI
With one trick, in that it allows you to constrain the resultant value to the standard [0, TAU] interval.
random(): number
returns a random number in the interval [0,1) (number
)
random(a: number): number
a
- The upper bound for the random number
returns a random number in the interval [0,a) (number
)
random(a: number, b: number): number
a
- The lower bound for the random numberb
- The upper bound for the random number
returns a random number in the interval [a, b) (number
)
Generate a pseudo-random number.
This is based on the SplitMix32 algorithm, covered over on https://stackoverflow.com/a/47593316/740553
function draw() {
clear(`white`);
setColor(`black`);
setFontSize(20);
range(0, height + 20, 20, (v) => {
text(random(), 5, v);
});
}
randomColor(opacity: number, cycle?: number)
opacity
- The opacity value in the range [0,1]cycle?
- A boolean that indicates whether or not to
move on to the next colour (default = true)
Generate a random colour. Note that this function allows you to get
"the currently generated random colour" in different opacities
by calling the function with an opacity value, and false
as
cycle argument.
function draw() {
clear(randomColor());
}
function pointerDown() {
redraw();
}
randomSeed(seed?: number)
seed?
- The random seed value.Set the pseudo-random number generator seed. If no seed value is provided, this is equivalent to calling:
randomSeed(Date.now() * Math.random())
range(start: number, end: number, step?: number, runFunction:
Function)
start
- The equivalent of a for loop's initial `let i
= ...`
end
- The equivalent of a for loop's `i < end`step?
- The step size by which to increment at each
iteration (defaults = `(start-end)/10`)
runFunction
- The function to run at each iteration
An alternative to writing for loops, because no one wants to constantly write var allocations that only live for the duration of a loop.
function draw() {
clear(`white`);
translate(width / 2, height / 2);
range(0, TAU, (a) => point(40 * cos(a), 40 * sin(a)));
}
rect(x: number, y: number, w: number, h: number)
x
- The rect's corner x pixel valuey
- The rect's corner y pixel valuew
- The width over which to draw the imageh
- The height over which to draw the imagerect(p: PointLike, w: number, h: number)
p
- The rect;s corder {x,y} coordinatew
- The width over which to draw the imageh
- The height over which to draw the imageDraw a rectangle at the specified coordinate, with the specific width and height.
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`red`);
rect(40, 40, width - 80, height - 80);
}
redraw()
Safely trigger a new draw pass. If the graphic is running in animated mode, or a redraw() is triggered during a redraw(), this call will do nothing.
function draw() {
const h = map(pointer.x, 0, width, 0, 360);
const l = map(pointer.y, 0, height, 50, 0);
clear(color(h, 100, l));
}
function pointerMove() {
redraw();
}
resetTransform()
Reset the coordinate transform matrix.
function setup() {
setSize(200, 200);
noGrid();
}
function draw() {
clear(`lightgrey`);
setColor(`red`);
translate(50, 50);
line(0, 0, 100, 0);
point(0, 0);
setColor(`darkgreen`);
point(10, 0);
rotate(PI / 4);
point(10, 0);
line(0, 0, 100, 0);
setColor(`blue`);
rotate(-PI / 6);
point(100, 0);
scale(0.5, 0.5);
point(100, 0);
line(100, 0, 200, 0);
resetTransform();
setColor(`black`);
line(0, 3, 100, 3);
point(0, 3);
point(10, 3);
point(100, 3);
}
restore()
Restore the graphics context (transforms, current colors, etc) to what they were when save() was called.
const points = [];
function draw() {
clear();
translate(width / 2, height / 2);
setColor(`blue`);
line(0, 0, 80, 0);
save();
setColor(`darkgreen`);
range(0, 5, 1, (a) => {
rotate(PI / 8);
line(0, 0, 80, 0);
});
restore();
line(-20, 0, -80, 0);
}
rotate(angle: number)
angle
- The angle by which to rotate the coordinate
system in radians
Rotate the coordinate system wrt the current origin.
function setup() {
setSize(200, 200);
noGrid();
}
function draw() {
clear(`lightgrey`);
translate(width / 2, height / 2);
setColor(`black`);
point(0, 0);
setColor(`darkgreen`);
line(0, 0, 20, 20);
point(20, 20);
rotate(PI / 4);
line(0, 0, 20, 20);
point(20, 20);
}
rotateProjector(x: number, y: number, z: number)
x
- The angle of rotation over the x axis in radians
y
- The angle of rotation over the y axis in radians
z
- The angle of rotation over the z axis in radians
Set the projector's x, y, and z axes of rotation in radians.
const cabinet = setProjector(CABINET);
const homogeneous = setProjector(HOMOGENEOUS);
const bottom = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
const top = bottom.map((v) => [v[0], v[1], 1]);
function setup() {
setSize(400, 200);
cabinet.setScale(50);
homogeneous.setScale(50);
play();
}
function draw() {
clear(`white`);
translate(-width / 4, height / 2);
const m = millis() / 5000;
[cabinet, homogeneous].forEach((projector) => {
setProjector(projector);
projector.setRotation(m, 2 * m, 3 * m);
translate(width / 2, 0);
drawAxisPoints();
drawCube();
});
}
function drawAxisPoints() {
setColor(`black`);
point(...bottom[0]);
setColor(`red`);
point(...bottom[1]);
setColor(`green`);
point(...bottom[3]);
setColor(`blue`);
point(...top[0]);
}
function drawCube() {
noFill();
setStroke(`red`);
[bottom, top].forEach((r) => {
line(...r[0], ...r[1]);
line(...r[2], ...r[3]);
});
setStroke(`green`);
[bottom, top].forEach((r) => {
line(...r[1], ...r[2]);
line(...r[3], ...r[0]);
});
setStroke(`blue`);
[0, 1, 2, 3].forEach((i) => line(...bottom[i], ...top[i]));
}
round(input: number): number
input
- Any number
returns the integer result after rounding. (number
)
The "round to the nearest integer" function, rounding any value [x.0, x.4999...] to x, and any value [x.5, x.999...] to x + 1.
save()
Save the current graphics context (transforms, current colors, etc) so that those can be restored after changing them.
const points = [];
function draw() {
clear();
translate(width / 2, height / 2);
setColor(`blue`);
line(0, 0, 80, 0);
save();
setColor(`darkgreen`);
range(0, 5, 1, (a) => {
rotate(PI / 8);
line(0, 0, 80, 0);
});
restore();
line(-20, 0, -80, 0);
}
scale(x: number, y?: number)
x
- The amount by which to scale the x coordinates.
y?
- The amount by which to scale the x coordinates
(default = same as x)
Scale the coordinate system wrt the current origin.
function setup() {
setSize(200, 200);
noGrid();
}
function draw() {
clear(`lightgrey`);
translate(width / 2, height / 2);
setColor(`black`);
point(0, 0);
setColor(`darkgreen`);
line(0, 0, 20, 20);
point(20, 20);
rotate(PI / 4);
scale(2);
line(0, 0, 20, 20);
point(20, 20);
}
scaleProjector(s: number)
s
- The scale factor for all three axesscaleProjector(x: number, y: number, z: number)
x
- The scale factor for the x axisy
- The scale factor for the y axisz
- The scale factor for the z axis
Set the projector's x, y, and z coordinate offsets. Note that this
value does not reset across successive draw calls. To reset the
translation, you must issue translateProjector(0,0,0)
.
const plane1 = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
const plane2 = [
[-1, -1, 1],
[1, -1, 1],
[1, 1, 1],
[-1, 1, 1],
];
function setup() {
setSize(200, 200);
setProjector(HOMOGENEOUS);
play();
}
function draw() {
clear(`white`);
center();
scaleProjector(
25 + 20 * sin(frame / 500),
25 + 20 * sin(frame / 500),
50 * sin(frame / 200),
);
setColor(`orange`);
poly(plane1);
setColor(`purple`);
poly(plane2);
}
screenToWorld(x: number, y: number): PointLike
x
- The screen coordinate's x value in pixelsy
- The screen coordinate's y value in pixelsreturns p The world {x,y} coordinate (PointLike
)
screenToWorld(p: PointLike): PointLike
p
- The screen {x,y} coordinatereturns p The world {x,y} coordinate (PointLike
)
Convert a screen (e.g. browser) coordinate into its corresponding "transformed" coordinate.
function setup() {
setSize(200, 200);
noGrid();
}
function draw() {
clear(`lightgrey`);
translate(width / 2, height / 2);
rotate(PI / 4);
scale(0.5);
if (pointer.active) {
setColor(`red`);
point(pointer.x, pointer.y);
setColor(`blue`);
point(screenToWorld(pointer.x, pointer.y));
}
}
function pointerMove() {
redraw();
}
sec(value: number): number
value
- The input value, in radians.returns the secant of our value. (number
)
The secant function, which is:
1 / cos(v)
setBorder(width?: number|boolean, color?: string)
width?
- The width of the border in pixels, disabling
the border omitted
color?
- The CSS color to use for the border (default
= black)
Set a border around the canvas.
function setup() {
setSize(200, 200);
setBorder(10, `red`);
}
setColor(color: string)
color
- The CSS color to use for the borderSet the current stroke and fill colour at the same time.
function draw() {
clear();
setColor(`blue`);
rect(50, 50, 100, 100);
}
setCursor(type: string)
type
- The CSS cursor typeChange the cursor to a specific icon:
Use any other string found over on the MDN cursor article to set a cursor not covered by the above constants.
function draw() {
clear(`white`);
setColor(`#FF02`);
rect(0, 0, width / 2, height);
setColor(`#0FF2`);
rect(width / 2, 0, width / 2, height);
}
function pointerMove(x, y) {
if (x < width / 2) {
setCursor(AUTO);
} else {
noCursor();
}
}
setFill(color: string)
color
- The CSS color to use for the border (default
= black)
Set the current fill colour.
function draw() {
clear();
setStroke(`black`);
setFill(`red`);
rect(50, 50, 100, 100);
}
setFont(font: string)
font
- A CSS shorthand font propertySet the current font using a single string. For the syntax, see https://developer.mozilla.org/en-US/docs/Web/CSS/font
setFontFamily(name: string)
name
- The CSS font family nameSet the current font family.
setFontSize(px: number)
px
- The font size in pixelsSet the current font size
setFontWeight(val: number|string)
val
- The CSS weight number or one of the special
strings "normal", "bold", "bolder", or "lighter".
Set the current font weight
setGrid(spacing?: number, color?: string)
spacing?
- The spacing between grid lines in pixels
(default = 20)
color?
- The CSS color to use for the border (default
= lightgrey)
Set the background grid spacing and colour.
function setup() {
setSize(200, 200);
setGrid(20, `lavender`);
}
function draw() {
clear(`white`);
}
setHighlightColor(color: string)
color
- The CSS color to use for the borderSet the color that should be used to replace whatever highlight() marked as the "to highlight" color.
function setup() {
setSize(200, 200);
setHighlightColor(`lime`);
}
function draw() {
clear();
setColor(`red`);
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
text("let's go", width / 2, height / 2);
}
function pointerActive(state) {
if (state) highlight(`red`);
else highlight(false);
}
setLineDash(...values: number[])
...values
- The dash intervals in pixelSet the line dash property. See the following MDN article for the details:
https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash
setLineWidth(width?: number)
width?
- The line width in pixels (default = 1)
Set the line width in pixels.
function draw() {
clear(`white`);
setColor(`black`);
range(1, 10, (i) => {
setLineWidth(i);
line(20, i * 20, 180, i * 20);
});
}
setMovable(points: PointLike[n])
points
- One or more points to mark as movable.
Mark one or more points as movable, meaning that the user can reposition the point around on the canvas by touch/click-dragging.
const points = [];
function setup() {
setSize(200, 200);
for (let i = 40; i < 200; i += 20) {
points.push(new Point(i - 20, 120));
}
setMovable(...points);
}
function draw() {
clear();
noFill();
setStroke(`purple`);
bspline(...points);
for (let p of points) point(p);
}
setProjector(falsey: implied): false
falsey
- when called with a falsey argument (or no
argument), disables projector related functionality.
returns false. (false
)
setProjector(projectorType: Symbol, project: boolean):
Projector
projectorType
- This sets up a new projector, of type
CABINET or
HOMOGENOUS.
project
- Optional. When true, immediately enable
coordinate projection. Default: true
returns the current projector. (Projector
)
setProjector(projector: Projector, project: boolean):
Projector
projector
- This sets the projector to the one passed
as argument.
project
- Optional. When true, immediately enable
coordinate projection. Default: true
returns the current projector. (Projector
)
Set up a 3D to 2D projector. This can be either a
CABINET
or HOMOGENEOUS
projector, supporting
the following API:
projector.setRotation(x, y, z)
projector.setTranslation(tx, ty, tz)
projector.setScale(tx, ty, tz)
furthermore, the CABINET
projector supports setting the
default cabinet angle using:
projector.setPhi(phi)
and the HOMOGENEOUS
projection supports setting the
distance of the point-at-infinity by using:
projector.setInfinity(distance)
(note,
distance
can be Infinity
)
const cabinet = createProjector(CABINET);
const homogeneous = createProjector(HOMOGENEOUS);
const bottom = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
const top = bottom.map((v) => [v[0], v[1], 1]);
function setup() {
setSize(400, 200);
cabinet.setScale(50);
homogeneous.setScale(50);
}
function draw() {
clear(`white`);
translate(-width / 4, height / 2);
[cabinet, homogeneous].forEach((projector) => {
setProjector(projector);
translate(width / 2, 0);
drawAxisPoints();
drawCube();
});
}
function drawAxisPoints() {
setColor(`black`);
point(...bottom[0]);
setColor(`red`);
point(...bottom[1]);
setColor(`green`);
point(...bottom[3]);
setColor(`blue`);
point(...top[0]);
}
function drawCube() {
noFill();
setStroke(`red`);
[bottom, top].forEach((r) => {
line(...r[0], ...r[1]);
line(...r[2], ...r[3]);
});
setStroke(`green`);
[bottom, top].forEach((r) => {
line(...r[1], ...r[2]);
line(...r[3], ...r[0]);
});
setStroke(`blue`);
[0, 1, 2, 3].forEach((i) => line(...bottom[i], ...top[i]));
}
setSize(width: number, height: number)
width
- The graphics width in pixelsheight
- The graphics height in pixelsSet (or change) the graphic's size. Note that your width and height values will get rounded to integer values.
Note that setSize
will immediately trigger a redraw,
whether you want it to or not, because changing canvas dimensions clears
the canvas, necessitating a redraw.
function setup() {
setSize(400, 200);
}
function draw() {
clear();
center();
setColor(`black`);
setFontSize(25);
text(`${width}/${height}`, 0, 0, CENTER, MIDDLE);
}
function pointerUp() {
setSize(random(100, 400), 200);
// Note that there is no redraw() here!
}
setStroke(color: string)
color
- The CSS color to use for the border (default
= black)
Set the current stroke colour.
function draw() {
clear();
setStroke(`black`);
setFill(`red`);
rect(50, 50, 100, 100);
}
setTextAlign(xAlign: string, yAlign: string)
xAlign
- The CSS horizontal alignmentyAlign
- The CSS vertical alignmentSet the current text alignment values.
Valid xAlign
values are:
Valid yAlign
values are:
function draw() {
clear(`white`);
setFontSize(20);
setColor(`black`);
line(width / 2, 0, width / 2, height);
line(0, height / 2, width, height / 2);
setTextAlign(CENTER, MIDDLE);
text("center middle", width / 2, height / 2);
line(0, height / 2 - 50, width, height / 2 - 50);
setTextAlign(RIGHT, TOP);
text("right top", width / 2, height / 2 - 50);
line(0, height / 2 + 50, width, height / 2 + 50);
setTextAlign(LEFT, BOTTOM);
text("left bottom", width / 2, height / 2 + 50);
}
setTextStroke(color: string, width?: number)
color
- The CSS color to use for the borderwidth?
- The text stroke width in pixels (default =
1)
Set the text outline stroking properties.
function draw() {
clear(`white`);
setFontSize(25);
setTextStroke(`red`, 1);
setFill(`yellow`);
text("fancy text", width / 2, 80, CENTER, CENTER);
setFontSize(65);
setTextStroke(`red`, 3);
setFill(`yellow`);
text("fancy text", width / 2, 140, CENTER, CENTER);
}
sign(input: number): number
input
- Any number
returns +1 if the number was positive, -1 if it was negative, or 0
if the input was zero. (number
)
Get the sign of a number
sin(input: number): number
input
- Any numberreturns the sine (number
)
The sine function
sinh(input: number): number
input
- Any numberreturns the hyperbolic sine (number
)
The hyperbolic sine function
See https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Definitions_in_terms_of_logarithms
spline(...points: PointLike[], virtual?: boolean, tightness?:
number)
...points
- The points across which to fit a spline
virtual?
- Whether or not to invent new mathematical
points that ensure the curve starts and ends at the provided start
and end points. (default = true)
tightness?
- How tight this spline should be fit
through the points provided. The higher the tightness, the more
polygonal the curve becomes (default = 1)
Draw a cardinal (hermite) spline that passes through each point
provided, using a mathematically virtual start and end to ensure the
curve starts and ends at the provided start and end point. This can be
bypassed by setting the virtual
argument to
false
.
Additionally, the spline's tightness, which controls how
"bendy" the spline is (the tighter the spline, the sharper
bends become) can be controlled by setting the
tightness
value.
const points = [];
function setup() {
setSize(200, 200);
range(0, TAU, PI / 5, (a) =>
points.push(new Point(random(30) + 50 * cos(a), random(30) + 50 * sin(a))),
);
setMovable(...points);
}
function draw() {
clear(`white`);
translate(width / 2, height / 2);
setFill(`#0002`);
spline(...points);
setColor(`red`);
points.forEach((p) => point(p));
}
sqrt(input: number): number
input
- Any numberreturns the square root of that number (number
)
The square root function.
Note that this function is a holdover from before JS had the
**
operator for performing this calculation by using
x ** 0.5
.
start()
Starts a (new) shape.
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`gold`);
start();
vertex(0, height / 2);
vertex(width / 2, 0);
vertex(width, height / 2);
vertex(width / 2, height);
end(true);
}
startShape(): Shape
returns the newly created shape object (Shape
)
Start a new shape. This yields a Shape
object with the
following API:
makeMovable(movable?: boolean)
- allow this shape to be
moved around with the pointer (movable
is true if
omitted)
allowResizing(allowed?: boolean)
- allow the points that
make up this shape to be moved around (allowed
is true if
omitted)
showPoints(showPoints?: boolean)
- determines whether or
not to draw the pathing points on top of the shape during draw().
close()
- close the current segment so no new points can
be added.
newSegment(closeExisting?: boolean)
- start a new segment
in this shape, closing the previous segment if
closeExisting
is true (default=false)
A Shape also supports the following utility functions:
offset(x, y)
- (temporarily) move this shape by (x,y)
commit()
- commit the temporary offset by rewriting all
coordinates.
reset()
- reset the shape to having no offset.draw()
- draws the shape using its current stroke, fill,
and "show points" settings.
inside(x, y): boolean
- returns whether or not a point
lies inside this (implicitly closed) shape.
And it supports the following pathing functions, with arguments that can
either consist of (the necessary number of) pairs of coordinate values,
or (the necessary number of) point-likes, being objects with an
x
and y
property.
moveTo(x,y OR p:pointLike)
- start a new segment and mark
its path as starting at (x,y).
lineTo(x,y,... OR p,...)
- add one or more points that
connect to the previous point with a straight line.
quadTo(cx,cy,x,y,... OR cp,p,...)
- add one or more
quadratic bezier curves, where (cx,cy)/cp is the control point, and
(x,y)/p the end point.
curveTo(cx1,cy1,cx2,cy2,x,y,... OR c1p,c2p,p,...)
- add
one or more cubic bezier curves, which have two control points.
splineTo(x1,y1,... OR p1,...)
- add one or more cardinal
spline pathing coordinates.
Cardinal spline coordinates are rendered by treating the path as closed (even if it is not), performing wrap-around lookups as needed in order to draw "something sensible".
let shape;
function setup() {
setSize(200, 200);
shape = startShape();
shape.allowResizing();
shape.showPoints();
shape.makeMovable();
// Create a diamond shape
shape.add(10, height / 2);
shape.add(width / 2, 10);
shape.add(width - 10, height / 2);
shape.add(width / 2, height - 10);
// With a rectangular cutout
shape.newSegment(true);
shape.add(75, 75);
shape.add(125, 75);
shape.add(125, 125);
shape.add(75, 125);
shape.flipSegment();
shape.close();
shape.setStroke(`black`);
shape.setFill(`gold`);
}
function draw() {
clear(`white`);
shape.draw(true);
}
tan(input: number): number
input
- Any numberreturns the tangent (number
)
The tangent function
tanh(input: number): number
input
- Any numberreturns the hyperbolic tangent (number
)
The hyperbolic tangent function
See https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions#Definitions_in_terms_of_logarithms
constant
The ratio of a circle's circumference to its radius, i.e. 2*PI
See https://en.wikipedia.org/wiki/Turn_(angle)#Tau_proposals
text(str: string, x: number, y: number, xAlign?: string, yAlign?:
string)
str
- The text we want to showx
- The text location's x pixel valuey
- The text location's y pixel valuexAlign?
- An optional horizontal alignment string
yAlign?
- An optional vertical alignment string
text(str: string, p: PointLike, xAlign?: string, yAlign?:
string)
str
- The text we want to showp
- The text location's {x,y} coordinatexAlign?
- An optional horizontal alignment string
yAlign?
- An optional vertical alignment string
Draw some text to the screen. Its placement is determined by both the
coordinate provided, and the x/y alignment provided. Valid
xAlign
values are:
Valid yAlign
values are:
Note that the primary text colour uses the fill colour. If text stroking is enabled, the the text outline will be coloured using the current stroke colour.
function draw() {
clear(`white`);
setColor(`black`);
setFontSize(25);
text("normal text", width / 2, 60, CENTER, CENTER);
noFill();
setTextStroke(1);
text("unfilled text", width / 2, 100, CENTER, CENTER);
setStroke(`red`);
setFill(`yellow`);
text("fancy text", width / 2, 140, CENTER, CENTER);
}
toDataURL(): string
returns the current canvas as PNG data URL (string
)
Convert the current canvas into an data URL that represents a PNG image.
togglePlay(): boolean
returns the new play state (boolean
)
If the graphic is currently playing, pause it, and if it's paused, play it.
function setup() {
setSize(200, 200);
setColor(`black`);
play();
}
function draw() {
clear();
setFontSize(25);
setTextAlign(CENTER, MIDDLE);
const seconds = (millis() / 1000).toFixed(1);
text(`${seconds}s`, width / 2, height / 2);
}
function pointerActive(state) {
togglePlay();
}
transform(a: number, b: number, c: number, d: number, e: number, f:
number)
a
- (default = 1)b
- (default = 0)c
- (default = 0)d
- (default = 0)e
- (default = 1)f
- (default = 0)Set the current transform matrix, based on applying:
| a b c |
m = | d e f |
| 0 0 1 |
With the parameters defaulting to the identity matrix.
See the following MDN article for more details about this function: https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/transform
translate(x: number, y: number)
x
- The x value in pixels to be treated as the new
"zero"
y
- The y value in pixels to be treated as the new
"zero"
translate(p: PointLike)
p
- The {x,y} coordinate to be treated as the new
"zero"
Translate the coordinate system by some amount of x and y units.
function draw() {
clear();
translate(width / 2, height / 2);
point(0, 0);
}
translateProjector(x: number, y: number, z: number)
x
- The offset along the x axisy
- The offset along the y axisz
- The offset along the z axis
Set the projector's x, y, and z coordinate offsets. Note that this
value does not reset across successive draw calls. To reset the
translation, you must issue translateProjector(0,0,0)
.
const plane = [
[-1, -1, 0],
[1, -1, 0],
[1, 1, 0],
[-1, 1, 0],
];
function setup() {
setSize(200, 200);
const p = setProjector(HOMOGENEOUS);
p.setScale(50);
play();
}
function draw() {
clear(`white`);
center();
setColor(`orange`);
translateProjector(0, 0, sin(frame / 100));
poly(plane);
}
transposeMatrix(M: Matrix): number[][]
M
- The matrix to transpose
returns the matrix transpose as 2D number array
(number[][]
)
Transpose a matrix
triangle(x1: number, y1: number, x2: number, y2: number, x3:
number, y3: number)
x1
- The first point's x pixel valuey1
- The first point's y pixel valuex2
- The second point's x pixel valuey2
- The second point's y pixel valuex3
- The third point's x pixel valuey3
- The third point's y pixel valuetriangle(p1: PointLike, p2: PointLike, p3: PointLike)
p1
- The first point's {x,y} coordinatep2
- The second point's {x,y} coordinatep3
- The third point's {x,y} coordinateDraw a triangle.
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`red`);
triangle(width / 2, 30, (1 / 4) * width, 160, (3 / 4) * width, 110);
}
trunc(input: number): number
input
- Any number
returns the integer part only of that number (number
)
Truncate a fraction to an integer by simply dropping the fractional
part. Note that this differs from the floor
function:
floor(4.2); // 4
floor(-4.2); // -5
trunc(4.2); // 4
trunc(-4.2); // -4
useProjection()
Enable a currently disabled 3D projector, allowing you to mix projective 3D and regular 2D with relatively little effort.
const plane = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
];
function setup() {
setSize(200, 200);
setProjector(HOMOGENEOUS);
scaleProjector(50);
}
function draw() {
clear(`white`);
center();
noProjection();
setFill(`#F0F5`);
poly(plane.map((v) => [50 * v[0], 50 * v[1]]));
useProjection();
setStroke(`#333`);
setFill(`#FF05`);
poly(plane);
}
vertex(x: number, y: number)
x
- The vertex's x pixel valuey
- The vertex's y pixel valuevertex(p: PointLike)
p
- The vertex {x,y} coordinateAdd a vertex to the currently active shape.
function draw() {
clear(`white`);
setStroke(`black`);
setFill(`red`);
start();
vertex(width / 2, 30);
vertex((1 / 4) * width, 160);
vertex((3 / 4) * width, 110);
end();
}
constant
The width of the canvas in pixels
worldToScreen(x: number, y: number): PointLike
x
- The world coordinate's x value in pixelsy
- The world coordinate's y value in pixelsreturns p The screen {x,y} coordinate (PointLike
)
worldToScreen(p: PointLike): PointLike
p
- The world {x,y} coordinatereturns p The screen {x,y} coordinate (PointLike
)
Convert an in-canvas "transformed" coordinate into its corresponding "screen" (i.e. browser canvas offset) coordinate.
function setup() {
setSize(200, 200);
play();
}
function draw() {
clear();
translate(width / 2, height / 2);
rotate(millis() / 2000);
setFontSize(25);
const p = new Point(30, 0);
point(p);
text(`${p.x},${p.y}`, p.x + 10, p.y + 10);
const { x, y } = worldToScreen(p);
resetTransform();
setFontSize(16);
text(`${x.toFixed()},${y.toFixed()}`, x - 25, y - 15);
}