UNPKG

canvas-sketch-util

Version:

Utilities for sketching in Canvas, WebGL and generative art

207 lines (181 loc) 5.05 kB
var defined = require('defined'); var wrap = require('./lib/wrap'); var EPSILON = Number.EPSILON; function clamp (value, min, max) { return min < max ? (value < min ? min : value > max ? max : value) : (value < max ? max : value > min ? min : value); } function clamp01 (v) { return clamp(v, 0, 1); } function lerp (min, max, t) { return min * (1 - t) + max * t; } function inverseLerp (min, max, t) { if (Math.abs(min - max) < EPSILON) return 0; else return (t - min) / (max - min); } function smoothstep (min, max, t) { var x = clamp(inverseLerp(min, max, t), 0, 1); return x * x * (3 - 2 * x); } function toFinite (n, defaultValue) { defaultValue = defined(defaultValue, 0); return typeof n === 'number' && isFinite(n) ? n : defaultValue; } function expandVector (dims) { if (typeof dims !== 'number') throw new TypeError('Expected dims argument'); return function (p, defaultValue) { defaultValue = defined(defaultValue, 0); var scalar; if (p == null) { // No vector, create a default one scalar = defaultValue; } else if (typeof p === 'number' && isFinite(p)) { // Expand single channel to multiple vector scalar = p; } var out = []; var i; if (scalar == null) { for (i = 0; i < dims; i++) { out[i] = toFinite(p[i], defaultValue); } } else { for (i = 0; i < dims; i++) { out[i] = scalar; } } return out; }; } function lerpArray (min, max, t, out) { out = out || []; if (min.length !== max.length) { throw new TypeError('min and max array are expected to have the same length'); } for (var i = 0; i < min.length; i++) { out[i] = lerp(min[i], max[i], t); } return out; } function newArray (n, initialValue) { n = defined(n, 0); if (typeof n !== 'number') throw new TypeError('Expected n argument to be a number'); var out = []; for (var i = 0; i < n; i++) out.push(initialValue); return out; } function linspace (n, opts) { n = defined(n, 0); if (typeof n !== 'number') throw new TypeError('Expected n argument to be a number'); opts = opts || {}; if (typeof opts === 'boolean') { opts = { endpoint: true }; } var offset = defined(opts.offset, 0); if (opts.endpoint) { return newArray(n).map(function (_, i) { return n <= 1 ? 0 : ((i + offset) / (n - 1)); }); } else { return newArray(n).map(function (_, i) { return (i + offset) / n; }); } } function lerpFrames (values, t, out) { t = clamp(t, 0, 1); var len = values.length - 1; var whole = t * len; var frame = Math.floor(whole); var fract = whole - frame; var nextFrame = Math.min(frame + 1, len); var a = values[frame % values.length]; var b = values[nextFrame % values.length]; if (typeof a === 'number' && typeof b === 'number') { return lerp(a, b, fract); } else if (Array.isArray(a) && Array.isArray(b)) { return lerpArray(a, b, fract, out); } else { throw new TypeError('Mismatch in value type of two array elements: ' + frame + ' and ' + nextFrame); } } function mod (a, b) { return ((a % b) + b) % b; } function degToRad (n) { return n * Math.PI / 180; } function radToDeg (n) { return n * 180 / Math.PI; } function fract (n) { return n - Math.floor(n); } function sign (n) { if (n > 0) return 1; else if (n < 0) return -1; else return 0; } // Specific function from Unity / ofMath, not sure its needed? // function lerpWrap (a, b, t, min, max) { // return wrap(a + wrap(b - a, min, max) * t, min, max) // } function pingPong (t, length) { t = mod(t, length * 2); return length - Math.abs(t - length); } function damp (a, b, lambda, dt) { return lerp(a, b, 1 - Math.exp(-lambda * dt)); } function dampArray (a, b, lambda, dt, out) { out = out || []; for (var i = 0; i < a.length; i++) { out[i] = damp(a[i], b[i], lambda, dt); } return out; } function mapRange (value, inputMin, inputMax, outputMin, outputMax, clamp) { // Reference: // https://openframeworks.cc/documentation/math/ofMath/ if (Math.abs(inputMin - inputMax) < EPSILON) { return outputMin; } else { var outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin); if (clamp) { if (outputMax < outputMin) { if (outVal < outputMax) outVal = outputMax; else if (outVal > outputMin) outVal = outputMin; } else { if (outVal > outputMax) outVal = outputMax; else if (outVal < outputMin) outVal = outputMin; } } return outVal; } } module.exports = { mod: mod, fract: fract, sign: sign, degToRad: degToRad, radToDeg: radToDeg, wrap: wrap, pingPong: pingPong, linspace: linspace, lerp: lerp, lerpArray: lerpArray, inverseLerp: inverseLerp, lerpFrames: lerpFrames, clamp: clamp, clamp01: clamp01, smoothstep: smoothstep, damp: damp, dampArray: dampArray, mapRange: mapRange, expand2D: expandVector(2), expand3D: expandVector(3), expand4D: expandVector(4) };