diff --git a/src/curve.ts b/src/classic-curve.ts similarity index 81% rename from src/curve.ts rename to src/classic-curve.ts index 6115e36..ee5ee69 100644 --- a/src/curve.ts +++ b/src/classic-curve.ts @@ -1,12 +1,12 @@ -import SiriWave, { ICurveDefinition, ICurve } from "./index"; -export class Curve implements ICurve { +import SiriWave, { IClassicCurveDefinition, ICurve } from "./index"; +export class ClassicCurve implements ICurve { ctrl: SiriWave; - definition: ICurveDefinition; + definition: IClassicCurveDefinition; ATT_FACTOR = 4; GRAPH_X = 2; AMPLITUDE_FACTOR = 0.6; - constructor(ctrl: SiriWave, definition: ICurveDefinition) { + constructor(ctrl: SiriWave, definition: IClassicCurveDefinition) { this.ctrl = ctrl; this.definition = definition; } @@ -25,7 +25,7 @@ export class Curve implements ICurve { (this.globalAttFn(i) * (this.ctrl.heightMax * this.ctrl.amplitude) * (1 / this.definition.attenuation) * - Math.sin(this.ctrl.opt.frequency * i - this.ctrl.phase)) + Math.sin(this.ctrl.opt.frequency! * i - this.ctrl.phase)) ); } @@ -40,14 +40,14 @@ export class Curve implements ICurve { ctx.lineWidth = this.definition.lineWidth; // Cycle the graph from -X to +X every PX_DEPTH and draw the line - for (let i = -this.GRAPH_X; i <= this.GRAPH_X; i += this.ctrl.opt.pixelDepth) { + for (let i = -this.GRAPH_X; i <= this.GRAPH_X; i += this.ctrl.opt.pixelDepth!) { ctx.lineTo(this._xpos(i), this.ctrl.heightMax + this._ypos(i)); } ctx.stroke(); } - static getDefinition(): ICurveDefinition[] { + static getDefinition(): IClassicCurveDefinition[] { return [ { attenuation: -2, diff --git a/src/index.ts b/src/index.ts index 9eab7d9..8701796 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -import { Curve } from "./curve"; -import { iOS9Curve } from "./ios9curve"; +import { ClassicCurve } from "./classic-curve"; +import { iOS9Curve } from "./ios9-curve"; enum CurveStyle { "ios" = "ios", @@ -37,14 +37,19 @@ export type Options = { curveDefinition?: ICurveDefinition[]; }; -export type ICurveDefinition = { - attenuation?: number; - lineWidth?: number; - opacity?: number; +export type IiOS9CurveDefinition = { supportLine?: boolean; - color?: string; + color: string; +}; + +export type IClassicCurveDefinition = { + attenuation: number; + lineWidth: number; + opacity: number; }; +export type ICurveDefinition = IiOS9CurveDefinition | IClassicCurveDefinition; + export interface ICurve { draw: () => void; } @@ -66,15 +71,15 @@ export default class SiriWave { heightMax: number; color: string; interpolation: { - speed: number; - amplitude: number; + speed: number | null; + amplitude: number | null; }; canvas: HTMLCanvasElement; ctx: CanvasRenderingContext2D; - animationFrameId: number; - timeoutId: ReturnType; + animationFrameId: number | undefined; + timeoutId: ReturnType | undefined; constructor({ container, ...rest }: Options) { const csStyle = window.getComputedStyle(container); @@ -109,12 +114,12 @@ export default class SiriWave { /** * Width of the canvas multiplied by pixel ratio */ - this.width = Number(this.opt.ratio * this.opt.width); + this.width = Number(this.opt.ratio! * this.opt.width!); /** * Height of the canvas multiplied by pixel ratio */ - this.height = Number(this.opt.ratio * this.opt.height); + this.height = Number(this.opt.ratio! * this.opt.height!); /** * Maximum height for a single wave @@ -124,7 +129,7 @@ export default class SiriWave { /** * Color of the wave (used in Classic iOS) */ - this.color = `rgb(${this.hex2rgb(this.opt.color)})`; + this.color = `rgb(${this.hex2rgb(this.opt.color!)})`; /** * An object containing controller variables that need to be interpolated @@ -143,7 +148,11 @@ export default class SiriWave { /** * 2D Context from Canvas */ - this.ctx = this.canvas.getContext("2d"); + const ctx = this.canvas.getContext("2d"); + if (ctx === null) { + throw new Error("Unable to create 2D Context"); + } + this.ctx = ctx; // Set dimensions this.canvas.width = this.width; @@ -153,19 +162,23 @@ export default class SiriWave { if (this.opt.cover === true) { this.canvas.style.width = this.canvas.style.height = "100%"; } else { - this.canvas.style.width = `${this.width / this.opt.ratio}px`; - this.canvas.style.height = `${this.height / this.opt.ratio}px`; + this.canvas.style.width = `${this.width / this.opt.ratio!}px`; + this.canvas.style.height = `${this.height / this.opt.ratio!}px`; } // Instantiate all curves based on the style switch (this.opt.style) { case CurveStyle.ios9: - this.curves = (this.opt.curveDefinition || iOS9Curve.getDefinition()).map((def) => new iOS9Curve(this, def)); + this.curves = ((this.opt.curveDefinition || iOS9Curve.getDefinition()) as IiOS9CurveDefinition[]).map( + (def) => new iOS9Curve(this, def), + ); break; case CurveStyle.ios: default: - this.curves = (this.opt.curveDefinition || Curve.getDefinition()).map((def) => new Curve(this, def)); + this.curves = ((this.opt.curveDefinition || ClassicCurve.getDefinition()) as IClassicCurveDefinition[]).map( + (def) => new ClassicCurve(this, def), + ); break; } @@ -200,10 +213,13 @@ export default class SiriWave { /** * Interpolate a property to the value found in this.interpolation */ - lerp(propertyStr: "amplitude" | "speed"): number { - this[propertyStr] = this.intLerp(this[propertyStr], this.interpolation[propertyStr], this.opt.lerpSpeed); - if (this[propertyStr] - this.interpolation[propertyStr] === 0) { - this.interpolation[propertyStr] = null; + lerp(propertyStr: "amplitude" | "speed"): number | null { + const prop = this.interpolation[propertyStr]; + if (prop !== null) { + this[propertyStr] = this.intLerp(this[propertyStr], prop, this.opt.lerpSpeed!); + if (this[propertyStr] - prop === 0) { + this.interpolation[propertyStr] = null; + } } return this[propertyStr]; } @@ -232,8 +248,8 @@ export default class SiriWave { this._clear(); // Interpolate values - if (this.interpolation.amplitude !== null) this.lerp("amplitude"); - if (this.interpolation.speed !== null) this.lerp("speed"); + this.lerp("amplitude"); + this.lerp("speed"); this._draw(); this.phase = (this.phase + (Math.PI / 2) * this.speed) % (2 * Math.PI); diff --git a/src/ios9curve.ts b/src/ios9-curve.ts similarity index 88% rename from src/ios9curve.ts rename to src/ios9-curve.ts index 03c93f0..6b5f7a6 100644 --- a/src/ios9curve.ts +++ b/src/ios9-curve.ts @@ -1,8 +1,8 @@ -import SiriWave, { ICurveDefinition, ICurve } from "./index"; +import SiriWave, { ICurve, IiOS9CurveDefinition } from "./index"; export class iOS9Curve implements ICurve { ctrl: SiriWave; - definition: ICurveDefinition; + definition: IiOS9CurveDefinition; spawnAt: number; noOfCurves: number; @@ -32,10 +32,23 @@ export class iOS9Curve implements ICurve { SPEED_RANGES: [number, number] = [0.5, 1]; DESPAWN_TIMEOUT_RANGES: [number, number] = [500, 2000]; - constructor(ctrl: SiriWave, definition: ICurveDefinition) { + constructor(ctrl: SiriWave, definition: IiOS9CurveDefinition) { this.ctrl = ctrl; this.definition = definition; + this.noOfCurves = 0; + this.spawnAt = 0; + this.prevMaxY = 0; + + this.phases = []; + this.offsets = []; + this.speeds = []; + this.finalAmplitudes = []; + this.widths = []; + this.amplitudes = []; + this.despawnTimeouts = []; + this.verses = []; + this.respawn(); } @@ -98,9 +111,9 @@ export class iOS9Curve implements ICurve { // Generate a static T so that each curve is distant from each oterh let t = 4 * (-1 + (ci / (this.noOfCurves - 1)) * 2); // but add a dynamic offset - t += this.offsets[ci]; + t += this.offsets![ci]; - const k = 1 / this.widths[ci]; + const k = 1 / this.widths![ci]; const x = i * k - t; y += Math.abs(this.amplitudes[ci] * this.sin(this.verses[ci] * x, this.phases[ci]) * this.globalAttFn(x)); @@ -127,7 +140,7 @@ export class iOS9Curve implements ICurve { drawSupportLine() { const { ctx } = this.ctrl; - const coo = [0, this.ctrl.heightMax, this.ctrl.width, 1]; + const coo: [number, number, number, number] = [0, this.ctrl.heightMax, this.ctrl.width, 1]; const gradient = ctx.createLinearGradient.apply(ctx, coo); gradient.addColorStop(0, "transparent"); gradient.addColorStop(0.1, "rgba(255,255,255,.5)"); @@ -167,7 +180,7 @@ export class iOS9Curve implements ICurve { for (const sign of [1, -1]) { ctx.beginPath(); - for (let i = -this.GRAPH_X; i <= this.GRAPH_X; i += this.ctrl.opt.pixelDepth) { + for (let i = -this.GRAPH_X; i <= this.GRAPH_X; i += this.ctrl.opt.pixelDepth!) { const x = this._xpos(i); const y = this._ypos(i); ctx.lineTo(x, this.ctrl.heightMax - sign * y); @@ -192,7 +205,7 @@ export class iOS9Curve implements ICurve { return null; } - static getDefinition(): ICurveDefinition[] { + static getDefinition(): IiOS9CurveDefinition[] { return [ { color: "255,255,255", diff --git a/tsconfig.json b/tsconfig.json index 4e380db..d07d102 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,8 @@ "compilerOptions": { "noImplicitAny": true, "module": "es6", - "target": "es5" + "target": "es5", + "strict": true }, "include": ["./src/**/*"], "exclude": ["./node_modules"]