Skip to content

Commit

Permalink
Merge JonDum/develop
Browse files Browse the repository at this point in the history
Merge JonDum/wobble
  • Loading branch information
tommy-mitchell authored Feb 8, 2022
2 parents d1c29d2 + 101be22 commit 805bd0f
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 18 deletions.
1 change: 1 addition & 0 deletions demos/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<h1>Demos</h1>
<ul>
<li><a href="./1-chat-heads/index.html">Chat Heads</a></li>
<li><a href="./squares/index.html">Squares</a></li>
</ul>
</body>
</html>
15 changes: 15 additions & 0 deletions demos/squares/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<html>
<head>
<title>Squares</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
* {
margin: 0;
}
</style>
</head>
<body>
<div id="app"></div>
<script src="./index.tsx"></script>
</body>
</html>
104 changes: 104 additions & 0 deletions demos/squares/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict'

import { Spring } from "../../dist/module"


class Square {
constructor(i, x, y) {
this.i = i
this.x = x
this.y = y
this.color = '#'+Math.random().toString(16).substr(2,6)

// raf
//this.springs = {
//x: new Spring({fromValue: this.x}), // x
//y: new Spring({fromValue: this.y}) // y
//}

// no raf
this.springs = {
x: new Spring({fromValue: this.x, raf: false}), // x
y: new Spring({fromValue: this.y, raf: false}) // y
}

this.springs.x.onUpdate(s => this.x = s.currentValue)
this.springs.y.onUpdate(s => this.y = s.currentValue)
}
setPosition(x, y) {
// raf
//this.springs.x.updateConfig({toValue: x}).start()
//this.springs.y.updateConfig({toValue: y}).start()

// no raf
this.springs.x.setValue(x);
this.springs.y.setValue(y);
}
tick(now) {
this.springs.x._advanceSpringToTime(now, true)
this.springs.y._advanceSpringToTime(now, true)
//this.springs.x._step()
//this.springs.x._step()
}
}

class Renderer {
constructor() {

const COUNT = 1000
const canvas = document.createElement('canvas')
const squares = []

canvas.style.width = canvas.style.height = '100%'
document.body.appendChild(canvas)
resizeCanvasToDisplaySize(canvas)

for(var i = 0; i < COUNT; i++) {
squares.push(new Square(i, Math.random() * canvas.width, Math.random() * canvas.height))
}

this.squares = squares
this.canvas = canvas
this.ctx = canvas.getContext('2d')

}

draw = () => {
const now = Date.now()
const {canvas, squares, ctx} = this

resizeCanvasToDisplaySize(canvas)

const {width, height} = canvas

ctx.clearRect(0, 0, width, height)

const index = Math.floor(squares.length*Math.random())
squares[index].setPosition(Math.random() * canvas.width, Math.random() * canvas.height)

for(var i = 0; i < squares.length; i++) {
const square = squares[i]

// with no raf, have to manually advance simulation. comment out if using raf
square.tick(now)

ctx.fillStyle = square.color
ctx.fillRect(square.x, square.y, 10, 10)
}

requestAnimationFrame(this.draw)
}

}

function resizeCanvasToDisplaySize(canvas) {
let w = (canvas.clientWidth*devicePixelRatio) | 0
let h = (canvas.clientHeight*devicePixelRatio) | 0
if (canvas.width != w || canvas.height != h) {
canvas.width = w
canvas.height = h
}
}

const renderer = new Renderer()
renderer.draw()
51 changes: 33 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface SpringConfig {
overshootClamping: boolean; // False when overshooting is allowed, true when it is not. Defaults to false.
restVelocityThreshold: number; // When spring's velocity is below `restVelocityThreshold`, it is at rest. Defaults to .001.
restDisplacementThreshold: number; // When the spring's displacement (current value) is below `restDisplacementThreshold`, it is at rest. Defaults to .001.
raf: boolean;
[index: string]: any;
}

export type PartialSpringConfig = Partial<SpringConfig>;
Expand Down Expand Up @@ -61,6 +63,7 @@ export class Spring {
initialVelocity: withDefault(config.initialVelocity, 0),
overshootClamping: withDefault(config.overshootClamping, false),
allowsOverdamping: withDefault(config.allowsOverdamping, false),
raf: withDefault(config.raf, true),
restVelocityThreshold: withDefault(config.restVelocityThreshold, 0.001),
restDisplacementThreshold: withDefault(
config.restDisplacementThreshold,
Expand All @@ -84,9 +87,11 @@ export class Spring {

if (!this._currentAnimationStep) {
this._notifyListeners("onStart");
this._currentAnimationStep = requestAnimationFrame((t: number) => {
this._step(Date.now());
});
if (this._config.raf) {
this._currentAnimationStep = requestAnimationFrame((t: number) => {
this._step();
});
}
}
}

Expand Down Expand Up @@ -156,24 +161,34 @@ export class Spring {
// being changed in `updatedConfig`, we run the simulation with `_step()`
// and default `fromValue` and `initialVelocity` to their current values.

this._advanceSpringToTime(Date.now());
this._advanceSpringToTime();

const baseConfig = {
fromValue: this._currentValue,
initialVelocity: this._currentVelocity
};
this._config.fromValue = this._currentValue;
this._config.initialVelocity = this._currentVelocity;

this._config = {
...this._config,
...baseConfig,
...updatedConfig
};
for (const key in updatedConfig) {
if (this._config.hasOwnProperty(key)) {
this._config[key] = updatedConfig[key as keyof SpringConfig];
}
}

this._reset();

return this;
}

/**
*
*/
setValue(value: number): this {
this._config.fromValue = this._currentValue;
this._config.toValue = value;
this._config.initialVelocity = this._currentVelocity;
this.start();
this._advanceSpringToTime(undefined, true);
return this;
}

/**
* The provided callback will be invoked when the simulation begins.
*/
Expand Down Expand Up @@ -246,20 +261,20 @@ export class Spring {
* current state once per frame, and schedules the next frame if the spring is
* not yet at rest.
*/
private _step(timestamp: number) {
this._advanceSpringToTime(timestamp, true);
private _step() {
this._advanceSpringToTime(undefined, true);

// check `_isAnimating`, in case `stop()` got called during
// `_advanceSpringToTime()`
if (this._isAnimating) {
if (this._config.raf && this._isAnimating) {
this._currentAnimationStep = requestAnimationFrame((t: number) =>
this._step(Date.now())
this._step()
);
}
}

private _advanceSpringToTime(
timestamp: number,
timestamp: number = Date.now(),
shouldNotifyListeners: boolean = false
) {
// `_advanceSpringToTime` updates `_currentTime` and triggers the listeners.
Expand Down

0 comments on commit 805bd0f

Please sign in to comment.