...loading...
SWColor Class Reference
Overview
The SWColor class represents colors in HSB (Hue, Saturation, Brightness) color space with alpha transparency. It provides a consistent color management system for the SketchWave ecosystem and integrates seamlessly with p5.js.
Key Features:
- HSB color space with intuitive color manipulation
- Alpha transparency support (0-100)
- Predefined Colors: 35+ color constants for easy access
- Color manipulation methods (darken, brighten, saturate, desaturate)
- Color creation from RGB and Hex values
- Conversion to Hex and RGB strings
- Static copy constructor for color duplication
- Parameter cycling for animations
- Defensive programming with automatic value clamping
- Hue (H): 0-360 degrees (color wheel position)
- Saturation (S): 0-100% (color intensity)
- Brightness (B): 0-100% (lightness/darkness)
- Alpha (A): 0-100% (transparency)
Constructor
new SWColor(h, s, b, a, name)
Parameters:
| Parameter | Type | Range | Default | Description |
|---|---|---|---|---|
h |
number | 0-360 | required | Hue value (wraps around if out of range) |
s |
number | 0-100 | required | Saturation percentage |
b |
number | 0-100 | required | Brightness percentage |
a |
number | 0-100 | 100 | Alpha (opacity) percentage |
name |
string | - | "" | Optional descriptive name for the color |
Examples:
// Create a pure red color
let red = new SWColor(0, 100, 100);
// Create a named blue color with 50% transparency
let semiBlue = new SWColor(240, 100, 100, 50, "semiTransparentBlue");
// Create a desaturated yellow
let paleYellow = new SWColor(60, 41, 100, 100, "paleYellow");
// Hue wraps around automatically
let purple = new SWColor(420, 100, 80); // Same as h=60
Properties
| Property | Type | Description |
|---|---|---|
h |
number | Hue value (0-360 degrees on color wheel) |
s |
number | Saturation percentage (0-100) |
b |
number | Brightness percentage (0-100) |
a |
number | Alpha/opacity percentage (0-100) |
name |
string | Optional descriptive name for the color |
col |
p5.Color | The underlying p5.js color object (auto-synced) |
col property is automatically updated whenever h, s, b, or a values change through the class methods. Direct modification of h/s/b/a properties should be followed by manually recreating col if needed.
Static Methods
SWColor.copy(other)
Creates a new SWColor instance with the same properties as the given SWColor.
Parameters:other(SWColor): The color to copy
let originalColor = new SWColor(180, 50, 75, 100, "cyan");
let copiedColor = SWColor.copy(originalColor);
// copiedColor is independent of originalColor
SWColor.fromRGB(r, g, b, a, name)
Creates a SWColor from RGB values (0-255).
Parameters:r(number): Red value (0-255)g(number): Green value (0-255)b(number): Blue value (0-255)a(number): Alpha percentage (0-100), default: 100name(string): Optional name, default: ""
// Create orange from RGB
let orange = SWColor.fromRGB(255, 165, 0, 100, "orange");
// Semi-transparent green
let greenGlass = SWColor.fromRGB(0, 255, 0, 30, "greenGlass");
SWColor.fromHex(hex, name)
Creates a SWColor from a hexadecimal color string.
Parameters:hex(string): Hex color string (with or without #)name(string): Optional name, default: ""
// Create from hex with #
let crimson = SWColor.fromHex("#DC143C", "crimson");
// Create from hex without #
let gold = SWColor.fromHex("FFD700", "gold");
Instance Methods
Conversion Methods
toString()
Returns a string representation of the color with all properties.
Returns: stringlet myColor = new SWColor(240, 100, 100, 80, "blue");
console.log(myColor.toString());
// Output: "SWColor(name: 'blue', h: 240, s: 100, b: 100, a: 80)"
getHexStr()
Converts the color to a CSS hexadecimal string.
Returns: string - Hex color (e.g., "#FF0000")let red = new SWColor(0, 100, 100);
console.log(red.getHexStr()); // "#FF0000"
getRGBStr()
Returns RGB values as a formatted string.
Returns: string - RGB string (e.g., "(255, 0, 0)")let green = new SWColor(120, 100, 100);
console.log(green.getRGBStr()); // "(0, 255, 0)"
Color Manipulation Methods (Mutating)
These methods modify the color in place and return the color for chaining.
darkenBy(factor)
Decreases brightness by multiplying by (1 - factor).
Parameters:factor(number): Amount to darken (e.g., 0.2 = 20% darker)
let myColor = new SWColor(120, 100, 100);
myColor.darkenBy(0.3); // 30% darker
brightenBy(factor)
Increases brightness by multiplying by (1 + factor).
Parameters:factor(number): Amount to brighten (e.g., 0.2 = 20% brighter)
let myColor = new SWColor(240, 100, 50);
myColor.brightenBy(0.5); // 50% brighter
saturateBy(factor)
Increases saturation by multiplying by (1 + factor).
Parameters:factor(number): Amount to saturate (e.g., 0.2 = 20% more saturated)
let myColor = new SWColor(0, 50, 100);
myColor.saturateBy(0.4); // 40% more saturated
desaturateBy(factor)
Decreases saturation by multiplying by (1 - factor).
Parameters:factor(number): Amount to desaturate (e.g., 0.3 = 30% less saturated)
let myColor = new SWColor(180, 80, 100);
myColor.desaturateBy(0.5); // 50% less saturated
changeAlphaBy(factor)
Changes alpha by multiplying by (1 + factor). Factor can be positive or negative.
Parameters:factor(number): Amount to change alpha (e.g., 0.2 = 20% more opaque, -0.5 = 50% more transparent)
let myColor = new SWColor(0, 100, 100, 100);
myColor.changeAlphaBy(-0.5); // 50% more transparent
setAlphaTo(a)
Sets alpha to a specific value.
Parameters:a(number): New alpha value (0-100)
let myColor = new SWColor(120, 100, 100);
myColor.setAlphaTo(50); // Set to 50% transparent
Color Creation Methods (Non-Mutating)
These methods return new SWColor instances without modifying the original.
createDarkerColor(factor)
Returns a new SWColor with brightness scaled by factor (0-1 = darker, >1 = brighter).
Parameters:factor(number): Brightness multiplier
let baseColor = new SWColor(240, 100, 100, 100, "blue");
let darkerBlue = baseColor.createDarkerColor(0.5); // 50% of brightness
// baseColor is unchanged
createLighterColor(factor)
Returns a new SWColor with brightness increased by factor.
Parameters:factor(number): Brightness multiplier
let baseColor = new SWColor(0, 100, 60, 100, "red");
let lighterRed = baseColor.createLighterColor(1.3); // 130% of brightness
// baseColor is unchanged
createAdjustedSaturation(factor)
Returns a new SWColor with saturation scaled by factor.
Parameters:factor(number): Saturation multiplier
let vibrant = new SWColor(120, 100, 100, 100, "green");
let muted = vibrant.createAdjustedSaturation(0.3); // 30% saturation
// vibrant is unchanged
Animation Methods
cycleParameter(param, sinusoid)
Cycles a color parameter using a SWSinusoid object for animations.
Parameters:param(string): "h", "s", "b", or "a"sinusoid(SWSinusoid): Sinusoid object with getValue() method
// Requires SWSinusoid class
let hueSin = new SWSinusoid(0, 360, 0.01);
let myColor = new SWColor(0, 100, 100);
function draw() {
hueSin.update();
myColor.cycleParameter("h", hueSin);
// Color hue now cycles through rainbow
}
Utility Methods
verify(prop, min, max)
Internal method that clamps a property to the specified range. Automatically called by the constructor and manipulation methods.
Parameters:prop(string): Property name ("h", "s", "b", or "a")min(number): Minimum allowed valuemax(number): Maximum allowed value
Predefined Colors
SWColor includes 35+ predefined color constants. Call initializeSWColors() in your setup() function after setting colorMode(HSB, 360, 100, 100, 100).
Initialization:
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
initializeSWColors(); // Must be called after colorMode
}
Available Colors:
Grayscale
swBlackswWhiteswOffWhiteswLightGrayswDarkGray
Reds & Browns
swRedswMaroonswBrownswLightBrownswTrunkBrownswDarkFleshswLightFlesh
Oranges & Yellows
swOrangeswGoldswYellowswDarkYellowswDeepYellowswPaleYellow
Greens
swGreenswMedGreenswDarkGreenswForestGreenswCyan
Blues
swBlueswLightBlueswLightishBlueswDarkBlueswDeepBlueswNavy
Purples & Pinks
swPurpleswDarkPurpleswIndigoswVioletswMagentaswPinkswHotPinkswDeepPink
Usage Example:
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
initializeSWColors();
}
function draw() {
background(swOffWhite.col);
fill(swRed.col);
circle(200, 200, 100);
}
Usage Examples
Example 1: Basic Color Creation and Use
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
}
function draw() {
background(220);
// Create and use custom colors
let skyBlue = new SWColor(200, 60, 100);
let grass = new SWColor(120, 80, 60);
fill(skyBlue.col);
rect(0, 0, 400, 200);
fill(grass.col);
rect(0, 200, 400, 200);
}
Example 2: Color Manipulation
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
}
function draw() {
background(220);
let baseColor = new SWColor(180, 100, 80, 100, "cyan");
// Original color
fill(baseColor.col);
circle(100, 200, 80);
// Darker version (non-mutating)
let dark = baseColor.createDarkerColor(0.5);
fill(dark.col);
circle(200, 200, 80);
// Desaturated version
let muted = SWColor.copy(baseColor);
muted.desaturateBy(0.7);
fill(muted.col);
circle(300, 200, 80);
}
Example 3: Creating Colors from RGB and Hex
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
initializeSWColors();
}
function draw() {
background(swWhite.col);
// From RGB
let coral = SWColor.fromRGB(255, 127, 80, 100, "coral");
fill(coral.col);
circle(150, 200, 100);
// From Hex
let lavender = SWColor.fromHex("#E6E6FA", "lavender");
fill(lavender.col);
circle(250, 200, 100);
// Log color info
console.log(coral.toString());
console.log("Hex:", coral.getHexStr());
console.log("RGB:", coral.getRGBStr());
}
Example 4: Animated Gradient
let topColor, bottomColor;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
topColor = new SWColor(200, 100, 100);
bottomColor = new SWColor(280, 100, 100);
}
function draw() {
// Animate colors
topColor.h = (topColor.h + 0.5) % 360;
bottomColor.h = (bottomColor.h + 0.3) % 360;
// Draw gradient
for (let y = 0; y < height; y++) {
let inter = map(y, 0, height, 0, 1);
let h = lerp(topColor.h, bottomColor.h, inter);
let s = lerp(topColor.s, bottomColor.s, inter);
let b = lerp(topColor.b, bottomColor.b, inter);
let lineColor = new SWColor(h, s, b);
stroke(lineColor.col);
line(0, y, width, y);
}
}
Example 5: Method Chaining
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
}
function draw() {
background(220);
let myColor = new SWColor(300, 80, 90, 100, "magenta");
// Chain multiple operations
myColor.saturateBy(0.2)
.darkenBy(0.1)
.setAlphaTo(70);
fill(myColor.col);
circle(200, 200, 150);
}
Example 6: Using Predefined Colors
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
initializeSWColors(); // Initialize predefined colors
}
function draw() {
background(swOffWhite.col);
// Sun
fill(swYellow.col);
circle(100, 100, 60);
// Tree trunk
fill(swTrunkBrown.col);
rect(180, 250, 40, 100);
// Tree leaves
fill(swForestGreen.col);
circle(200, 230, 100);
// Sky accent
fill(swLightishBlue.col);
noStroke();
circle(320, 80, 40);
}
Integration with SketchWave Ecosystem
Dependencies
- p5.js: Required for color creation and manipulation
- SWSinusoid: Optional, for parameter cycling animations
Loading Order
Ensure scripts are loaded in this order in your HTML:
<!-- p5js CDN-->
<script src="https://cdn.jsdelivr.net/npm/p5@1.6.0/lib/p5.js"></script>
<!-- SketchWave classes -->
<script src="scripts/swColor.js"></script>
<script src="scripts/swPoint.js"></script>
<script src="scripts/swSinusoid.js"></script>
<!-- Your sketch script -->
<script src="scripts/mySketch.js"></script>
Setup Requirements
colorMode(HSB, 360, 100, 100, 100) in your setup() function before using SWColor. Call initializeSWColors() after setting the color mode if you want to use predefined colors.
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100); // REQUIRED
initializeSWColors(); // Optional, for predefined colors
}
Best Practices
- Always use
colorMode(HSB, 360, 100, 100, 100)for consistency - Use
.colproperty when passing colors to p5.js functions (fill, stroke, etc.) - Prefer non-mutating methods (
createDarkerColor) when you need to preserve the original - Use mutating methods (
darkenBy) for in-place modifications and chaining - Name your colors for easier debugging and code readability
- Use
SWColor.copy()when you need an independent duplicate - Leverage predefined colors for common use cases to ensure consistency
Common Patterns
// Pattern 1: Create variations of a base color
let base = new SWColor(180, 80, 80, 100, "baseColor");
let light = base.createLighterColor(1.3);
let dark = base.createDarkerColor(0.6);
let muted = base.createAdjustedSaturation(0.4);
// Pattern 2: Modify a color over time
let dynamicColor = new SWColor(0, 100, 100);
function draw() {
dynamicColor.h = (frameCount * 2) % 360;
dynamicColor.col = color(dynamicColor.h, dynamicColor.s, dynamicColor.b, dynamicColor.a);
fill(dynamicColor.col);
}
// Pattern 3: Use with other SketchWave classes
let myPoint = new SWPoint(100, 100, undefined, 5, swRed);
myPoint.draw();
Complete Source Code
View the complete, documented source code for the SWColor class and initialization function:
Show/Hide Source Code
/*
File: swColor.js
Date: 2026-02-20
Author: klp
Workspace: SketchWaveTNT2026-02-19-Stg4
Purpose: SWColor class and predefined colors for SketchWaveJS
Comment(s):
TODO:
=== Notes ===:
- SWColor class represents colors in HSB color space with alpha transparency.
- Includes methods for color manipulation (darken, brighten, saturate,
desaturate, change alpha).
- Predefined global SWColor instances for common colors (swRed, swBlue, swGreen, etc.).
- Initialization function to set up all predefined colors.
- Static method to create SWColor from RGB values.
- Static copy method to duplicate SWColor instances.
- Verification of color property ranges to ensure valid values.
- Script must be loaded before the p5js script, but colors are initialized in setup() after colorMode is set.
- Code is only compatible with p5.js environment.
- Additional methods: createDarkerColor(factor), createLighterColor(factor) and createAdjustedSaturation(factor)
*/
console.log("[swColor.js] SWColor class and predefined colors loaded");
// Declare all SWColor variables (uninitialized)
var swBlack, swWhite, swOffWhite, swLightGray, swDarkGray;
var swRed, swDarkFlesh, swOrange, swLightFlesh, swBrown;
var swLightBrown, swTrunkBrown, swGold, swDarkYellow, swYellow, swDeepYellow, swPaleYellow;
var swMedGreen, swDarkGreen, swForestGreen, swGreen, swCyan;
var swLightishBlue, swDarkBlue, swDeepBlue, swBlue, swLightBlue;
var swNavy, swIndigo, swViolet, swDarkPurple, swMagenta, swPurple;
var swPink, swHotPink, swDeepPink, swMaroon;
function initializeSWColors() {
console.log("...initializeSWColors...");
//must be called AFTER colorMode is set in setup()
// This function initializes all global SWColor instances
// In order of ascending hue
swBlack = new SWColor(0, 0, 0, 100, "black");
swWhite = new SWColor(0, 0, 100, 100, "white");
swOffWhite = new SWColor(0, 0, 93, 100, "offWhite");
swLightGray = new SWColor(0, 0, 80, 100, "lightGray");
swDarkGray = new SWColor(0, 0, 40, 100, "darkGray");
swRed = new SWColor(0, 100, 100, 100, "red");
swDarkFlesh = new SWColor(15, 46, 61, 100, "darkFlesh");
swOrange = new SWColor(18, 80, 100, 100, "orange");
swLightFlesh = new SWColor(18, 24, 74, 100, "lightFlesh");
swBrown = new SWColor(27, 100, 65, 100, "brown");
swLightBrown = new SWColor(30, 100, 80, 100, "lightBrown");
swTrunkBrown = new SWColor(40, 86, 54, 100, "trunkBrown");
swGold = new SWColor(45, 94, 92, 100, "gold");
swDarkYellow = new SWColor(59, 100, 80, 100, "darkYellow");
swYellow = new SWColor(60, 100, 100, 100, "yellow");
swDeepYellow = new SWColor(60, 100, 59, 100, "deepYellow");
swPaleYellow = new SWColor(60, 41, 100, 100, "paleYellow");
swMedGreen = new SWColor(110, 36, 52, 100, "medGreen");
swDarkGreen = new SWColor(133, 87, 40, 100, "darkGreen");
swForestGreen = new SWColor(146, 100, 46, 100, "forestGreen");
swGreen = new SWColor(120, 100, 100, 100, "green");
swCyan = new SWColor(180, 100, 100, 100, "cyan");
swLightishBlue = new SWColor(200, 60, 100, 100, "lightishBlue");
swDarkBlue = new SWColor(204, 100, 100, 100, "darkBlue");
swDeepBlue = new SWColor(228, 100, 100, 100, "deepBlue");
swBlue = new SWColor(240, 100, 100, 100, "blue");
swLightBlue = new SWColor(240, 22, 100, 100, "lightBlue");
swNavy = new SWColor(240, 100, 50, 100, "navy");
swIndigo = new SWColor(255, 100, 40, 100, "indigo");
swViolet = new SWColor(282, 100, 27, 100, "violet");
swDarkPurple = new SWColor(270, 100, 80, 100, "darkPurple");
swMagenta = new SWColor(300, 100, 100, 100, "magenta");
swPurple = new SWColor(300, 67, 60, 100, "purple");
swPink = new SWColor(320, 25, 100, 100, "pink");
swHotPink = new SWColor(324, 100, 100, 100, "hotPink");
swDeepPink = new SWColor(334, 100, 79, 100, "deepPink");
swMaroon = new SWColor(348, 100, 71, 100, "maroon");
}//end initializeSWColors
class SWColor {
constructor(h, s, b, a = 100, name = "") {
//hue: 0-360, saturation: 0-100, brightness: 0-100, alpha: 0-100
//wraparound hue to be within 0-360
let anH = h;
if(h < 0){
anH = 360 + (h % 360);
}else{
anH = h % 360;
}
if(anH !== h) console.log(`SWColor hue adjusted to ${anH}`);
this.h = anH;
this.s = s;
this.b = b;
this.a = a;
this.name = name;
//defensive programming: verify values are in range
//hue is verified with wraparound above
this.verify('s', 0, 100);
this.verify('b', 0, 100);
this.verify('a', 0, 100);
// Create and store the p5.js color object
//console.log(`SWColor created: ${this.toString()}`);
this.col = color(this.h, this.s, this.b, this.a);
}//end constructor
// Copy constructor: returns a new SWColor with the same
// properties as the given SWColor instance
static copy(other) {
if (!(other instanceof SWColor)) {
throw new Error('Argument to SWColor.copy must be an SWColor instance');
}
return new SWColor(other.h, other.s, other.b, other.a, other.name);
}//end copy
toString() {
return `SWColor(name: '${this.name}', h: ${this.h}, s: ${this.s}, b: ${this.b}, a: ${this.a})`;
}//end toString
getHexStr() {
// Converts this.col (p5.Color) to a CSS hex string
// p5.js: red(), green(), blue() extract RGB from color object
let r = Math.round(red(this.col));
let g = Math.round(green(this.col));
let b = Math.round(blue(this.col));
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
}//end getHexStr
getRGBStr() {
// Returns a string in the format (r, g, b)
// DWR! red, green, blue are p5.js functions!
let r = red(this.col);
let g = green(this.col);
let b = blue(this.col);
return `(${r}, ${g}, ${b})`;
}//end getRGBStr
verify(prop, min, max) {
//ensures that the given property (h, s, b, a) is within the specified range
if (this[prop] < min) {
this[prop] = min;
} else if (this[prop] > max) {
this[prop] = max;
}
}//end verify
darkenBy(factor) {
// Decrease brightness by multiplying by (1 - factor),
// e.g., factor=0.2 darkens by 20%
const originalB = this.b;
this.b = originalB * (1 - factor);
this.verify('b', 0, 100);
this.col = color(this.h, this.s, this.b, this.a);
}//end darkenBy
brightenBy(factor) {
// Increase brightness by multiplying by (1 + factor),
// e.g., factor=0.2 brightens by 20%
const originalB = this.b;
this.b = originalB * (1 + factor);
this.verify('b', 0, 100);
this.col = color(this.h, this.s, this.b, this.a);
}//end brightenBy
saturateBy(factor) {
// Increase saturation by multiplying by (1 + factor),
// e.g., factor=0.2 increases saturation by 20%
const originalS = this.s;
this.s = originalS * (1 + factor);
this.verify('s', 0, 100);
this.col = color(this.h, this.s, this.b, this.a);
return this;
}//end saturateBy
desaturateBy(factor) {
// Decrease saturation by multiplying by (1 - factor),
// e.g., factor=0.2 decreases saturation by 20%
const originalS = this.s;
this.s = originalS * (1 - factor);
this.verify('s', 0, 100);
this.col = color(this.h, this.s, this.b, this.a);
return this;
}//end desaturateBy
changeAlphaBy(factor) {
// factor can be positive or negative
// Change alpha by multiplying by (1 + factor),
// e.g., factor=0.2 increases alpha by 20%
const originalA = this.a;
this.a = originalA * (1 + factor);
this.verify('a', 0, 100);
this.col = color(this.h, this.s, this.b, this.a);
return this;
}//end changeAlphaBy
setAlphaTo(a) {
this.a = a;
this.verify('a', 0, 100);
this.col = color(this.h, this.s, this.b, this.a);
return this;
}//end setAlphaTo
// Static method: create SWColor from RGB values
static fromRGB(r, g, b, a = 100, name = "") {
// Convert RGB (0-255) to HSB (h: 0-360, s: 0-100, b: 0-100)
r /= 255; g /= 255; b /= 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, v = max;
let d = max - min;
s = max === 0 ? 0 : d / max;
if (max === min) {
h = 0;
} else {
switch (max) {
case r: h = ((g - b) / d) % 6; break;
case g: h = ((b - r) / d) + 2; break;
case b: h = ((r - g) / d) + 4; break;
}
h *= 60;
if (h < 0) h += 360;
}
return new SWColor(Math.round(h), Math.round(s * 100), Math.round(v * 100), a, name);
}//end fromRGB
static fromHex(hex, name = "") {
// Ensure hex starts with '#'
if (!hex.startsWith("#")) hex = "#" + hex;
// Use p5.js color() to parse hex
const c = color(hex);
// Extract HSB values
colorMode(HSB, 360, 100, 100, 100);
const h = hue(c);
const s = saturation(c);
const br = brightness(c);
return new SWColor(h, s, br, 100, name);
}//end fromHex
cycleParameter(param, sinusoid) {
// param: "h", "s", "b", or "a"
// sinusoid: SWSinusoid object with a getValue() method
if (!["h", "s", "b", "a"].includes(param)) {
throw new Error("Invalid parameter for SWColor.cycleParameter");
}
this[param] = sinusoid.getValue();
if (param === "h") {
//wraparound hue to be within 0-360
if(this.h < 0){
this.h = 360 + (this.h % 360);
}else{
this.h = this.h % 360;
}
}else{
this.verify(param, 0, 100);
}
this.col = color(this.h, this.s, this.b, this.a);
}//end cycleParameter
/**
* Returns a new SWColor with brightness scaled by the
* given factor (0-1 = darker, >1 = brighter)
* @param {number} factor - The factor to scale brightness (b)
* @returns {SWColor} New SWColor with adjusted brightness
*/
createDarkerColor(factor) {
// Clamp factor to non-negative
factor = Math.max(0, factor);
let newB = this.b * factor;
// Clamp brightness to [0, 100]
newB = Math.max(0, Math.min(100, newB));
return new SWColor(this.h, this.s, newB, this.a, this.name ? this.name + '_darker' : undefined);
}//end createDarkerColor
/**
* Returns a new SWColor with brightness increased by the given factor (>1 = lighter, 0-1 = dimmer)
* @param {number} factor - The factor to scale brightness (b)
* @returns {SWColor} New SWColor with adjusted brightness
*/
createLighterColor(factor) {
factor = Math.max(0, factor);
let newB = this.b * factor;
newB = Math.max(0, Math.min(100, newB));
return new SWColor(this.h, this.s, newB, this.a, this.name ? this.name + '_lighter' : undefined);
}//end createLighterColor
/**
* Returns a new SWColor with saturation scaled by the given factor
* @param {number} factor - The factor to scale saturation (s)
* @returns {SWColor} New SWColor with adjusted saturation
*/
createAdjustedSaturation(factor) {
factor = Math.max(0, factor);
let newS = this.s * factor;
newS = Math.max(0, Math.min(100, newS));
return new SWColor(this.h, newS, this.b, this.a, this.name ? this.name + '_sat' : undefined);
}//end createAdjustedSaturation
/*
--- Notes ---
'verify' method ensures color properties stay within valid ranges. It used to throw an error using code like this:
if (this[prop] < min || this[prop] > max) {
throw new Error(`${prop} value ${this[prop]} is out of range (${min}-${max})`);
}
However, this could disrupt program flow if a color value was slightly out of bounds due to calculations.
Instead, it now clamps the value to the nearest valid limit and logs a message. This makes the class more robust
Regarding static copy method:
A static copy method is used instead of a traditional
copy constructor because JavaScript does not support multiple constructors.
Using a static method allows us to create a new instance based on an existing one without overloading the constructor.
This approach is clear and idiomatic in JavaScript, providing a straightforward way to duplicate objects.
The static keyword before copy means that copy is a static method of the SWColor class. This means you call it on the class itself (SWColor.copy(...)), not on an instance (not swRed.copy(...)).
It is necessary if you want to use the method without needing an instance, and it makes sense here: copy creates a new SWColor from an existing one, but doesn't depend on the state of a particular SWColor instance.
If you removed static, you would have to call copy on an instance (e.g., swRed.copy(other)), which is less clear for a copy constructor pattern. So, static is appropriate and recommended in this case.
*/
}//end SWColor class