SWCross — Class Reference

SketchWaveJS — SWWheel Saga — Stage 2

A four-armed plus-sign class that extends SWWheel, with locked constraints and an initialRotation property

Overview

SWCross is a four-armed plus-sign (crosshair) shape that extends SWWheel. It hard-wires three design constraints — always 4 spokes, no visible rim, no visible hub — and adds an initialRotation property that pre-tilts the arms before animation begins.

All of SWWheel’s animation and drawing machinery (drawOnGrid(), breathe(), all setters) is inherited unchanged. SWCross only overrides rotate() and reset() to bake in the initial-rotation offset.

SWCross extends SWWheel │ ├── Locked: numSpokes = 4, rimThickness = 0, hub invisible ├── New: initialRotation (degrees) ├── New: setInitialRotation(deg) ├── Override: rotate(degPerSec, t) → adds initialRotation offset └── Override: reset() → returns to initialRotation, not 0 Inherited from SWWheel (unchanged): drawOnGrid(grid), breathe(sinusoid, t), setSpokeThickness(), setSpokeColor(), setSpokeCapStyle(), …
Default arm caps: SWCross defaults to SQUARE (flat-tip) cap style, overriding p5.js’s global default of ROUND. Flat tips make the crosshair geometry precise and clean. See the Cap Styles section for a full explanation.

Inheritance

SWCross uses single inheritance via the extends keyword. The constructor calls super() with three locked values, then adds its own initialRotation state.

CategoryItemHow SWCross handles it
Inherited (unchanged) drawOnGrid(grid), breathe(sinusoid, t) Used exactly as defined in SWWheel
Inherited (unchanged) All setters: setSpokeThickness(), setSpokeColor(), setSpokeCapStyle(), etc. Available on every SWCross instance
Overridden rotate(degPerSec, t) Sets rotationAngle = initialRotation + degPerSec × t instead of just degPerSec × t
Overridden reset() Returns arms to initialRotation (not 0°) and restores originalOuterRadius
New setInitialRotation(deg) Live setter that immediately repositions arms to the new base angle
Locked (not exposed) numSpokes, rimThickness, hub colors Hard-wired in super(); not constructor options

Dependencies

All six must be loaded in your HTML before SWCross.js:

Class / LibraryFileRole
p5.js CDN Canvas and rendering engine
SWColor shapeClasses/swColor.js HSB color objects for arm stroke color
SWPoint shapeClasses/swPoint.js Center point and computed arm endpoints
SWLine shapeClasses/swLine.js Each individual arm (spoke)
SWDisk shapeClasses/swDisk.js Hub and rim components (invisible in SWCross)
SWGrid shapeClasses/swGrid.js Required only for drawOnGrid()
SWWheel shapeClasses/swWheel.js Parent class — must load immediately before SWCross.js

Constructor

const ps = new SWCross({ /* options — all optional */ });

All options are passed as a single destructured object. numSpokes, rimThickness, and hub colors are not accepted as options — they are locked:

OptionTypeDefaultDescription
center SWPoint SWPoint(0, 0) Shape center in user/grid coordinates
outerRadius number 100 Arm length in user units
hubRadius number 6 Hub size in user units (hub is invisible; value kept for internal mechanics)
spokeThickness number 25 Arm stroke weight in pixels
spokeColor SWColor undefined Arm stroke color (SWColor instance)
initialRotation number 0 Pre-tilt angle in degrees. 0° = plus ✚, 45° = times ✕
Locked valueForced toWhy
numSpokes 4 Defines the plus-sign shape; other counts produce different shapes
rimThickness 0 Arms only — no enclosing ring
hubFillColor null Hub fill invisible
rimColor null Hub outline invisible
arm cap style 'SQUARE' Flat tips; set via setSpokeCapStyle() after super()

Public Properties

All properties listed for SWWheel are present. The following are specific to SWCross:

PropertyTypeNotes
initialRotation number Pre-tilt offset in degrees. Arms rest here at t = 0. Set via setInitialRotation().
Inherited properties of note: rotationAngle stores the current computed angle (initialRotation + degPerSec × t). originalOuterRadius is what reset() restores currentRadius to.

Methods

Overridden Methods

SignatureParametersBehavior change from SWWheel
rotate(degPerSec, t) degPerSec: number
t: number (s)
Sets rotationAngle = initialRotation + degPerSec × t. At t = 0, arms rest at initialRotation, not 0°.
reset() Restores rotationAngle to initialRotation (not 0) and currentRadius to originalOuterRadius.

New Setters

MethodParameterNotes
setInitialRotation(deg) deg: number Sets this.initialRotation = deg, this.rotationAngle = deg, and immediately repositions the arms via _repositionSpokes(). Always zero tElapsed after calling this so the animation clock restarts from the new pre-tilt baseline.

Key Inherited Methods (from SWWheel)

The full list is in the SWWheel Reference → Methods. The most commonly used ones are summarized here.
MethodNotes
drawOnGrid(grid) Draw in user coordinates. Preferred over draw().
breathe(sinusoid, t) Oscillate arm length using an SWSinusoid. Call every frame.
setSpokeThickness(w) Arm stroke weight in pixels.
setSpokeColor(swColor) Arm color (each arm gets a defensive copy).
setSpokeCapStyle(cap) Set cap style: 'ROUND', 'SQUARE', or 'PROJECT'. Propagates to all four arms. See Cap Styles for details.
setOuterRadius(r) Arm length in user units. Also updates originalOuterRadius.

Line Cap Styles — A p5.js Global State Lesson

⚠️ p5.js global state alert: strokeCap() is a global setting in p5.js. If any shape changes it during a frame, every subsequent shape drawn that frame inherits the new setting — unless something resets it. SWLine now brackets every line() call with explicit set & restore, so it never leaks its cap style to other shapes.

By default, p5.js draws all line endpoints with round caps. This is fine for general lines, but a geometric crosshair looks better with flat tips. The cap style is controlled per SWLine via this.capStyle ('ROUND' | 'SQUARE''PROJECT').

The pattern used in SWLine.draw() and SWLine.drawOnGrid():

// Resolve string → p5 constant at draw time strokeCap(window[this.capStyle] ?? ROUND); line(x1, y1, x2, y2); strokeCap(ROUND); // restore p5's default so other shapes are unaffected

window[this.capStyle] looks up the p5 constant by name at draw time — so the string 'SQUARE' becomes the integer constant SQUARE without needing p5’s globals to be available when the class is first defined.

The Three Options

Valuep5 ConstantVisual ResultDefault for
'ROUND' ROUND Semicircular end cap; line length equals exact nominal length SWLine (p5 default)
'SQUARE' SQUARE Flat, blunt end; line length equals exact nominal length SWCross — cleanest crosshair
'PROJECT' PROJECT Flat end that extends beyond the endpoint by ½ the stroke weight None
Classroom tip: Set all three cap styles on the same plus sign using the Arm caps selector in swCross1.html to compare the visual difference. With a thick stroke weight (≥ 20 px), the difference between ROUND and SQUARE is very obvious. PROJECT visually lengthens the arms.

Usage Examples

Minimal plus sign at the grid origin

// All defaults — 4 arms, outerRadius 100, 25 px weight, no color set let ps, grid; function setup() { createCanvas(400, 400); colorMode(HSB, 360, 100, 100, 100); grid = new SWGrid( /* your grid params */ ); ps = new SWCross(); } function draw() { background(0, 0, 90); ps.drawOnGrid(grid); }

Diagonal cross (45° pre-tilt) with red arms

const cross = new SWCross({ outerRadius : 120, spokeThickness : 20, spokeColor : SWColor.fromHex('#ff0000', 100), initialRotation : 45 // ✕ orientation });

Animated rotation with initialRotation offset

let ps, grid, tElapsed = 0; function setup() { // ... ps = new SWCross({ spokeColor : new SWColor(0, 90, 90), initialRotation : 30 // starts 30° off the cardinal axes }); } function draw() { tElapsed += min(deltaTime / 1000, 0.1); background(0, 0, 90); ps.rotate(60, tElapsed); // 60 °/sec, offset by initialRotation ps.drawOnGrid(grid); }

Changing initialRotation at runtime

// Wire a slider to setInitialRotation. // IMPORTANT: reset tElapsed so animation restarts cleanly from the new angle. document.getElementById('initialRotSlider') .addEventListener('input', e => { const deg = +e.target.value; ps.setInitialRotation(deg); tElapsed = 0; // ← required to avoid jump redraw(); });

Breathing plus sign

let wave = new SWSinusoid(); wave.adjustWaveUsingExtrema(40, 160); // arms pulse from 40 to 160 user units wave.setPeriod(3); function draw() { tElapsed += min(deltaTime / 1000, 0.1); background(0, 0, 90); ps.rotate(45, tElapsed); ps.breathe(wave, tElapsed); // inherited from SWWheel unchanged ps.drawOnGrid(grid); }

Switching cap style at runtime

// Wire the Arm caps dropdown to setSpokeCapStyle(). document.getElementById('capStyleSelect') .addEventListener('change', e => { ps.setSpokeCapStyle(e.target.value); // 'ROUND' | 'SQUARE' | 'PROJECT' redraw(); });

Source — shapeClasses/SWCross.js

Loaded live from the file so this view always reflects the current version. Use the button to copy the full source to the clipboard.

Loading source…