diff --git a/lib/Snowfall.js b/lib/Snowfall.js index bb5b70a..a8a7b5f 100644 --- a/lib/Snowfall.js +++ b/lib/Snowfall.js @@ -83,7 +83,7 @@ function (_React$Component) { ctx.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight); _this.snowflakes.forEach(function (snowflake) { - return snowflake.draw(canvas); + return snowflake.draw(canvas, ctx); }); } } diff --git a/lib/Snowflake.d.ts b/lib/Snowflake.d.ts index abb3cb5..1b6c9f2 100644 --- a/lib/Snowflake.d.ts +++ b/lib/Snowflake.d.ts @@ -32,10 +32,9 @@ declare class Snowflake { framesSinceLastUpdate: number; constructor(canvas: HTMLCanvasElement, config?: SnowflakeConfig); resized: () => boolean; - draw: (canvas: HTMLCanvasElement) => void; - translate: (framesPassed?: number) => void; + draw: (canvas: HTMLCanvasElement, inputCtx?: CanvasRenderingContext2D | undefined) => void; + translate: (canvas: HTMLCanvasElement, framesPassed?: number) => void; updateTargetParams: () => void; - handleOffScreen: (canvas: HTMLCanvasElement) => void; update: (canvas: HTMLCanvasElement, framesPassed?: number | undefined) => void; } export default Snowflake; diff --git a/lib/Snowflake.js b/lib/Snowflake.js index 1b212ee..6b841ba 100644 --- a/lib/Snowflake.js +++ b/lib/Snowflake.js @@ -47,8 +47,8 @@ var Snowflake = function Snowflake(_canvas, config) { return _this.params.isResized = true; }); - _defineProperty(this, "draw", function (canvas) { - var ctx = canvas.getContext('2d'); + _defineProperty(this, "draw", function (canvas, inputCtx) { + var ctx = inputCtx || canvas.getContext('2d'); if (ctx) { ctx.beginPath(); @@ -59,12 +59,21 @@ var Snowflake = function Snowflake(_canvas, config) { } }); - _defineProperty(this, "translate", function () { - var framesPassed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; - _this.params.y += _this.params.speed * framesPassed; - _this.params.x += _this.params.wind * framesPassed; - _this.params.speed = (0, _utils.lerp)(_this.params.speed, _this.params.nextSpeed, 0.01); - _this.params.wind = (0, _utils.lerp)(_this.params.wind, _this.params.nextWind, 0.01); + _defineProperty(this, "translate", function (canvas) { + var framesPassed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + var _this$params = _this.params, + x = _this$params.x, + y = _this$params.y, + wind = _this$params.wind, + speed = _this$params.speed, + nextWind = _this$params.nextWind, + nextSpeed = _this$params.nextSpeed; // Update current location, wrapping around if going off the canvas + + _this.params.x = (x + wind * framesPassed) % canvas.offsetWidth; + _this.params.y = (y + speed * framesPassed) % canvas.offsetHeight; // Update the wind and speed towards the desired values + + _this.params.speed = (0, _utils.lerp)(speed, nextSpeed, 0.01); + _this.params.wind = (0, _utils.lerp)(wind, nextWind, 0.01); if (_this.framesSinceLastUpdate++ > _this.config.changeFrequency) { _this.updateTargetParams(); @@ -78,20 +87,8 @@ var Snowflake = function Snowflake(_canvas, config) { _this.params.nextWind = _utils.random.apply(void 0, _toConsumableArray(_this.config.wind)); }); - _defineProperty(this, "handleOffScreen", function (canvas) { - if (_this.params.x > canvas.offsetWidth) { - _this.params.x = 0; - } - - if (_this.params.y > canvas.offsetHeight) { - _this.params.y = 0; - } - }); - _defineProperty(this, "update", function (canvas, framesPassed) { - _this.translate(framesPassed); - - _this.handleOffScreen(canvas); + _this.translate(canvas, framesPassed); }); // Merging input config with default config @@ -100,18 +97,18 @@ var Snowflake = function Snowflake(_canvas, config) { var _this$config = this.config, color = _this$config.color, radius = _this$config.radius, - wind = _this$config.wind, - speed = _this$config.speed; + _wind = _this$config.wind, + _speed = _this$config.speed; this.params = { color: color, x: (0, _utils.random)(0, _canvas.offsetWidth), y: (0, _utils.random)(-_canvas.offsetHeight, 0), radius: _utils.random.apply(void 0, _toConsumableArray(radius)), - speed: _utils.random.apply(void 0, _toConsumableArray(speed)), - wind: _utils.random.apply(void 0, _toConsumableArray(wind)), + speed: _utils.random.apply(void 0, _toConsumableArray(_speed)), + wind: _utils.random.apply(void 0, _toConsumableArray(_wind)), isResized: false, - nextSpeed: _utils.random.apply(void 0, _toConsumableArray(wind)), - nextWind: _utils.random.apply(void 0, _toConsumableArray(speed)) + nextSpeed: _utils.random.apply(void 0, _toConsumableArray(_wind)), + nextWind: _utils.random.apply(void 0, _toConsumableArray(_speed)) }; this.framesSinceLastUpdate = 0; }; diff --git a/lib/utils.d.ts b/lib/utils.d.ts index af0159b..8b4aa62 100644 --- a/lib/utils.d.ts +++ b/lib/utils.d.ts @@ -1,2 +1,14 @@ +/** + * Enhanced random function, selects a random value between a minimum and maximum. If the values provided are both + * integers then the number returned will be an integer, otherwise the return number will be a decimal. + * @param min The minimum value + * @param max The maximum value + */ export declare function random(min: number, max: number): number; +/** + * Linear interpolation function to gradually step towards a target value + * @param start The current value + * @param end The target value + * @param normal The rate of change between 0 and 1 (0 = no change, 1 = instant) + */ export declare function lerp(start: number, end: number, normal: number): number; diff --git a/lib/utils.js b/lib/utils.js index d060243..97d82b3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -6,6 +6,12 @@ Object.defineProperty(exports, "__esModule", { exports.random = random; exports.lerp = lerp; +/** + * Enhanced random function, selects a random value between a minimum and maximum. If the values provided are both + * integers then the number returned will be an integer, otherwise the return number will be a decimal. + * @param min The minimum value + * @param max The maximum value + */ function random(min, max) { var randomNumber = Math.random() * (max - min + 1) + min; @@ -15,6 +21,13 @@ function random(min, max) { return Math.floor(randomNumber); } } +/** + * Linear interpolation function to gradually step towards a target value + * @param start The current value + * @param end The target value + * @param normal The rate of change between 0 and 1 (0 = no change, 1 = instant) + */ + function lerp(start, end, normal) { return (1 - normal) * start + normal * end; diff --git a/src/Snowfall.tsx b/src/Snowfall.tsx index 823dd78..1cf69e7 100644 --- a/src/Snowfall.tsx +++ b/src/Snowfall.tsx @@ -77,7 +77,7 @@ export default class Snowfall extends React.Component { const ctx = canvas.getContext('2d') if (ctx) { ctx.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight) - this.snowflakes.forEach(snowflake => snowflake.draw(canvas)) + this.snowflakes.forEach(snowflake => snowflake.draw(canvas, ctx)) } } } diff --git a/src/Snowflake.ts b/src/Snowflake.ts index 8574892..86f114f 100644 --- a/src/Snowflake.ts +++ b/src/Snowflake.ts @@ -70,8 +70,8 @@ class Snowflake { resized = () => (this.params.isResized = true) - draw = (canvas: HTMLCanvasElement) => { - const ctx = canvas.getContext('2d') + draw = (canvas: HTMLCanvasElement, inputCtx?: CanvasRenderingContext2D) => { + const ctx = inputCtx || canvas.getContext('2d') if (ctx) { ctx.beginPath() ctx.arc(this.params.x, this.params.y, this.params.radius, 0, 2 * Math.PI) @@ -81,12 +81,16 @@ class Snowflake { } } - translate = (framesPassed: number = 1) => { - this.params.y += this.params.speed * framesPassed - this.params.x += this.params.wind * framesPassed + translate = (canvas: HTMLCanvasElement, framesPassed: number = 1) => { + const { x, y, wind, speed, nextWind, nextSpeed } = this.params - this.params.speed = lerp(this.params.speed, this.params.nextSpeed, 0.01) - this.params.wind = lerp(this.params.wind, this.params.nextWind, 0.01) + // Update current location, wrapping around if going off the canvas + this.params.x = (x + wind * framesPassed) % canvas.offsetWidth + this.params.y = (y + speed * framesPassed) % canvas.offsetHeight + + // Update the wind and speed towards the desired values + this.params.speed = lerp(speed, nextSpeed, 0.01) + this.params.wind = lerp(wind, nextWind, 0.01) if (this.framesSinceLastUpdate++ > this.config.changeFrequency) { this.updateTargetParams() @@ -99,19 +103,8 @@ class Snowflake { this.params.nextWind = random(...this.config.wind) } - handleOffScreen = (canvas: HTMLCanvasElement) => { - if (this.params.x > canvas.offsetWidth) { - this.params.x = 0 - } - - if (this.params.y > canvas.offsetHeight) { - this.params.y = 0 - } - } - update = (canvas: HTMLCanvasElement, framesPassed?: number) => { - this.translate(framesPassed) - this.handleOffScreen(canvas) + this.translate(canvas, framesPassed) } } diff --git a/src/utils.ts b/src/utils.ts index fd96606..7e3c05b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,9 @@ +/** + * Enhanced random function, selects a random value between a minimum and maximum. If the values provided are both + * integers then the number returned will be an integer, otherwise the return number will be a decimal. + * @param min The minimum value + * @param max The maximum value + */ export function random(min: number, max: number): number { const randomNumber = Math.random() * (max - min + 1) + min @@ -8,6 +14,12 @@ export function random(min: number, max: number): number { } } +/** + * Linear interpolation function to gradually step towards a target value + * @param start The current value + * @param end The target value + * @param normal The rate of change between 0 and 1 (0 = no change, 1 = instant) + */ export function lerp(start: number, end: number, normal: number) { return (1 - normal) * start + normal * end }