@armniko/ticker
Advanced tools
| import { Time } from '../interfaces/time.interface'; | ||
| export declare class Fps { | ||
| private _minFps?; | ||
| private _currentFps; | ||
| private _lastChecks; | ||
| private _calculateFpsEachMs; | ||
| private _msSinceLastCalculation; | ||
| private _lowFpsInRow; | ||
| private _lowFpsCallback?; | ||
| currentFps(): number; | ||
| calculate(time: Time): void; | ||
| onLowFps(callback: () => void): void; | ||
| setMinFps(minFps: number): this; | ||
| private collectFps; | ||
| private calculateAverageFps; | ||
| private checkAndNotifyLowFps; | ||
| } |
| import { Time } from './time.interface'; | ||
| export interface DrawQueueItem { | ||
| callback: (time: Time) => void; | ||
| } |
| import { Time } from './time.interface'; | ||
| export interface LogicQueueItem { | ||
| callback: (time: Time) => void; | ||
| } |
| export interface LowFpsQueueItem { | ||
| callback: (fps: number) => void; | ||
| } |
| export interface TickerTaskId { | ||
| index: number; | ||
| type: 'draw' | 'logic' | 'low-fps'; | ||
| } |
| export interface Time { | ||
| delta: number; | ||
| deltaMs: number; | ||
| } |
| import { Ticker } from './ticker'; | ||
| export declare class TickerMock extends Ticker { | ||
| private _isStarted; | ||
| start(): void; | ||
| stop(): void; | ||
| isStarted(): boolean; | ||
| fps(): number; | ||
| msBetweenTicks(): number; | ||
| ticksMissed(): number; | ||
| simulateLogicTick(): void; | ||
| simulateDrawTick(): void; | ||
| simulateLowFps(): void; | ||
| } |
| import { TickerOptions } from '../interfaces/ticker-options.interface'; | ||
| import { TickerTaskId } from '../interfaces/ticker-task-id.interface'; | ||
| import { DrawQueueItem } from '../interfaces/draw-queue-item.interface'; | ||
| import { LogicQueueItem } from '../interfaces/logic-queue-item.interface'; | ||
| import { LowFpsQueueItem } from '../interfaces/low-fps-queue-item.interface'; | ||
| export declare class Ticker { | ||
| private readonly _fps; | ||
| private readonly _drawQueue; | ||
| private readonly _logicQueue; | ||
| private readonly _lowFpsQueue; | ||
| private _maxFps; | ||
| private _expectedFps; | ||
| private _time; | ||
| private _lastTimestamp; | ||
| private _logicTicksAccumulatedMs; | ||
| private _requestFrameId?; | ||
| constructor(options?: TickerOptions); | ||
| start(): void; | ||
| stop(): void; | ||
| isStarted(): boolean; | ||
| setFps(options: { | ||
| min?: number; | ||
| max?: number; | ||
| expected?: number; | ||
| }): this; | ||
| addDrawTask(callback: DrawQueueItem['callback']): TickerTaskId; | ||
| addLogicTask(callback: LogicQueueItem['callback']): TickerTaskId; | ||
| addLowFpsTask(callback: LowFpsQueueItem['callback']): TickerTaskId; | ||
| remove(taskId: TickerTaskId): void; | ||
| fps(): number; | ||
| /** | ||
| * @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead. | ||
| */ | ||
| msBetweenTicks(): number; | ||
| /** | ||
| * @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead. | ||
| */ | ||
| ticksMissed(): number; | ||
| private loop; | ||
| private runQueue; | ||
| private runLogicQueue; | ||
| private runDrawQueue; | ||
| private compensatedMaxFps; | ||
| } |
+4
-1
@@ -1,1 +0,4 @@ | ||
| export * from './libraries/ticker'; | ||
| export * from './ticker/ticker'; | ||
| export * from './ticker/ticker-mock'; | ||
| export * from './interfaces/time.interface'; | ||
| export * from './interfaces/ticker-task-id.interface'; |
@@ -1,1 +0,1 @@ | ||
| var s={d:(t,e)=>{for(var i in e)s.o(e,i)&&!s.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},o:(s,t)=>Object.prototype.hasOwnProperty.call(s,t)},t={};s.d(t,{R:()=>a});class e{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(s){this.collectFps(s),this._msSinceLastCalculation+=s,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(s,t){this._minFps=s,this._lowFpsCallback=t}collectFps(s){this._lastChecks.push(Math.round(1e3/s))}calculateAverageFps(){const s=this._lastChecks.reduce(((s,t)=>s+t),0);this._currentFps=Math.round(s/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}}class i{_maxMsBetweenTicks;_expectedMsBetweenTicks;_ticksMissed=1;_msBetweenTicks=0;_lastTickTime=0;_requestFrameId;_tickCallback;constructor(s,t){this._maxMsBetweenTicks=1e3/s,this._expectedMsBetweenTicks=1e3/t}start(){this._tickCallback&&(this._lastTickTime=performance.now(),this.loop())}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}onTick(s){this._tickCallback=s}msBetweenTicks(){return this._msBetweenTicks}ticksMissed(){return this._ticksMissed}loop(){const s=performance.now();this._msBetweenTicks=s-this._lastTickTime,this._ticksMissed=this._msBetweenTicks/this._expectedMsBetweenTicks,this._msBetweenTicks>=this._maxMsBetweenTicks&&(this._lastTickTime=s,this._tickCallback&&this._tickCallback(this._msBetweenTicks)),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}}class c{_expectedMsBetweenTicks;_ticksMissed=1;_msBetweenTicks=0;_lastTickTime=0;_timeoutId;_tickCallback;constructor(s){this._expectedMsBetweenTicks=1e3/s}start(){this._tickCallback&&(this._lastTickTime=performance.now(),this.delayLoop())}stop(){this._timeoutId&&(clearTimeout(this._timeoutId),this._timeoutId=void 0)}isStarted(){return!!this._timeoutId}onTick(s){this._tickCallback=s}msBetweenTicks(){return this._msBetweenTicks}ticksMissed(){return this._ticksMissed}delayLoop(){this._timeoutId=setTimeout((()=>this.loop()),this._expectedMsBetweenTicks)}loop(){const s=performance.now();this._msBetweenTicks=s-this._lastTickTime,this._ticksMissed=this._msBetweenTicks/this._expectedMsBetweenTicks,this._lastTickTime=s,this._tickCallback&&this._tickCallback(this._msBetweenTicks),this.delayLoop()}}class a{_fps=new e;_logicTicker;_drawTicker;constructor(s){const t=s?.minFps||0,e=this.compensatedMaxFps(s?.maxFps||60),a=s?.expectedFps||60,r=s?.onLogicTick,o=s?.onDrawTick,h=s?.onLowFps;this._logicTicker=new c(a),this._drawTicker=new i(e,a),r&&this._logicTicker.onTick(r),o&&this._drawTicker.onTick((s=>{o(),this._fps.calculate(s)})),h&&this._fps.onLowFps(t,h)}start(){this._logicTicker.start(),this._drawTicker.start()}stop(){this._logicTicker.stop(),this._drawTicker.stop()}isStarted(){return this._logicTicker.isStarted()||this._drawTicker.isStarted()}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._logicTicker.isStarted()?this._logicTicker.msBetweenTicks():this._drawTicker.msBetweenTicks()}ticksMissed(){return this._logicTicker.isStarted()?this._logicTicker.ticksMissed():this._drawTicker.ticksMissed()}compensatedMaxFps(s){return Math.floor(1.1*s)+10*Math.floor(s/100)}}var r=t.R;export{r as Ticker}; | ||
| var s={d:(e,t)=>{for(var i in t)s.o(t,i)&&!s.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},o:(s,e)=>Object.prototype.hasOwnProperty.call(s,e)},e={};s.d(e,{R:()=>i,D:()=>a});class t{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(s){this.collectFps(s),this._msSinceLastCalculation+=s.deltaMs,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(s){this._lowFpsCallback=s}setMinFps(s){return this._minFps=s,this}collectFps(s){this._lastChecks.push(Math.round(1e3/s.deltaMs))}calculateAverageFps(){const s=this._lastChecks.reduce(((s,e)=>s+e),0);this._currentFps=Math.round(s/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}}class i{_fps=new t;_drawQueue=[];_logicQueue=[];_lowFpsQueue=[];_maxFps;_expectedFps;_time={delta:0,deltaMs:0};_lastTimestamp=0;_logicTicksAccumulatedMs=0;_requestFrameId;constructor(s){this.setFps({min:s?.minFps||0,max:s?.maxFps||60,expected:s?.expectedFps||60}),s?.onDrawTick&&this.addDrawTask(s.onDrawTick),s?.onLogicTick&&this.addLogicTask(s.onLogicTick),s?.onLowFps&&this.addLowFpsTask(s.onLowFps),this._fps.onLowFps((()=>{this._lowFpsQueue.forEach((s=>s.callback(this.fps())))}))}start(){this._lastTimestamp=performance.now(),this.loop(this._lastTimestamp)}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}setFps(s){return s.min&&s.min>0&&this._fps.setMinFps(s.min),s.max&&s.max>0&&(this._maxFps=this.compensatedMaxFps(s.max)),s.expected&&s.expected>0&&(this._expectedFps=s.expected),this}addDrawTask(s){return{index:this._drawQueue.push({callback:s})-1,type:"draw"}}addLogicTask(s){return{index:this._logicQueue.push({callback:s})-1,type:"logic"}}addLowFpsTask(s){return{index:this._lowFpsQueue.push({callback:s})-1,type:"low-fps"}}remove(s){switch(s.type){case"draw":this._drawQueue.splice(s.index,1);break;case"logic":this._logicQueue.splice(s.index,1);break;case"low-fps":this._lowFpsQueue.splice(s.index,1)}}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._time.deltaMs}ticksMissed(){return this._time.deltaMs/(1e3/this._expectedFps)}loop(s){const e=1e3/this._maxFps,t=s-this._lastTimestamp;t>=e&&(this._time={delta:t/1e3,deltaMs:t},this._lastTimestamp=s,this._fps.calculate(this._time),this.runQueue()),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}runQueue(){this._logicQueue.length>0&&this.runLogicQueue(),this._drawQueue.length>0&&this.runDrawQueue()}runLogicQueue(){const s=1e3/this._expectedFps;this._logicTicksAccumulatedMs+=this._time.deltaMs;const e={delta:s/1e3,deltaMs:s};for(;this._logicTicksAccumulatedMs>=s;)this._logicQueue.forEach((s=>s.callback(e))),this._logicTicksAccumulatedMs-=s}runDrawQueue(){this._drawQueue.forEach((s=>s.callback(this._time)))}compensatedMaxFps(s){return Math.floor(1.1*s)+10*Math.floor(s/100)}}class a extends i{_isStarted=!1;start(){this._isStarted=!0}stop(){this._isStarted=!1}isStarted(){return this._isStarted}fps(){return 60}msBetweenTicks(){return 1e3/60}ticksMissed(){return 1}simulateLogicTick(){this._logicQueue.forEach((s=>s.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateDrawTick(){this._drawQueue.forEach((s=>s.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateLowFps(){this._lowFpsQueue.forEach((s=>s.callback(this.fps())))}}var c=e.R,l=e.D;export{c as Ticker,l as TickerMock}; |
@@ -1,1 +0,1 @@ | ||
| !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Ticker",[],t):"object"==typeof exports?exports.Ticker=t():e.Ticker=t()}(self,(()=>(()=>{"use strict";var e={d:(t,s)=>{for(var i in s)e.o(s,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:s[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{Ticker:()=>r});class s{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(e){this.collectFps(e),this._msSinceLastCalculation+=e,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(e,t){this._minFps=e,this._lowFpsCallback=t}collectFps(e){this._lastChecks.push(Math.round(1e3/e))}calculateAverageFps(){const e=this._lastChecks.reduce(((e,t)=>e+t),0);this._currentFps=Math.round(e/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}}class i{_maxMsBetweenTicks;_expectedMsBetweenTicks;_ticksMissed=1;_msBetweenTicks=0;_lastTickTime=0;_requestFrameId;_tickCallback;constructor(e,t){this._maxMsBetweenTicks=1e3/e,this._expectedMsBetweenTicks=1e3/t}start(){this._tickCallback&&(this._lastTickTime=performance.now(),this.loop())}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}onTick(e){this._tickCallback=e}msBetweenTicks(){return this._msBetweenTicks}ticksMissed(){return this._ticksMissed}loop(){const e=performance.now();this._msBetweenTicks=e-this._lastTickTime,this._ticksMissed=this._msBetweenTicks/this._expectedMsBetweenTicks,this._msBetweenTicks>=this._maxMsBetweenTicks&&(this._lastTickTime=e,this._tickCallback&&this._tickCallback(this._msBetweenTicks)),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}}class c{_expectedMsBetweenTicks;_ticksMissed=1;_msBetweenTicks=0;_lastTickTime=0;_timeoutId;_tickCallback;constructor(e){this._expectedMsBetweenTicks=1e3/e}start(){this._tickCallback&&(this._lastTickTime=performance.now(),this.delayLoop())}stop(){this._timeoutId&&(clearTimeout(this._timeoutId),this._timeoutId=void 0)}isStarted(){return!!this._timeoutId}onTick(e){this._tickCallback=e}msBetweenTicks(){return this._msBetweenTicks}ticksMissed(){return this._ticksMissed}delayLoop(){this._timeoutId=setTimeout((()=>this.loop()),this._expectedMsBetweenTicks)}loop(){const e=performance.now();this._msBetweenTicks=e-this._lastTickTime,this._ticksMissed=this._msBetweenTicks/this._expectedMsBetweenTicks,this._lastTickTime=e,this._tickCallback&&this._tickCallback(this._msBetweenTicks),this.delayLoop()}}class r{_fps=new s;_logicTicker;_drawTicker;constructor(e){const t=e?.minFps||0,s=this.compensatedMaxFps(e?.maxFps||60),r=e?.expectedFps||60,o=e?.onLogicTick,a=e?.onDrawTick,n=e?.onLowFps;this._logicTicker=new c(r),this._drawTicker=new i(s,r),o&&this._logicTicker.onTick(o),a&&this._drawTicker.onTick((e=>{a(),this._fps.calculate(e)})),n&&this._fps.onLowFps(t,n)}start(){this._logicTicker.start(),this._drawTicker.start()}stop(){this._logicTicker.stop(),this._drawTicker.stop()}isStarted(){return this._logicTicker.isStarted()||this._drawTicker.isStarted()}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._logicTicker.isStarted()?this._logicTicker.msBetweenTicks():this._drawTicker.msBetweenTicks()}ticksMissed(){return this._logicTicker.isStarted()?this._logicTicker.ticksMissed():this._drawTicker.ticksMissed()}compensatedMaxFps(e){return Math.floor(1.1*e)+10*Math.floor(e/100)}}return t})())); | ||
| !function(e,s){"object"==typeof exports&&"object"==typeof module?module.exports=s():"function"==typeof define&&define.amd?define("Ticker",[],s):"object"==typeof exports?exports.Ticker=s():e.Ticker=s()}(self,(()=>(()=>{"use strict";var e={d:(s,t)=>{for(var i in t)e.o(t,i)&&!e.o(s,i)&&Object.defineProperty(s,i,{enumerable:!0,get:t[i]})},o:(e,s)=>Object.prototype.hasOwnProperty.call(e,s),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},s={};e.r(s),e.d(s,{Ticker:()=>i,TickerMock:()=>a});class t{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(e){this.collectFps(e),this._msSinceLastCalculation+=e.deltaMs,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(e){this._lowFpsCallback=e}setMinFps(e){return this._minFps=e,this}collectFps(e){this._lastChecks.push(Math.round(1e3/e.deltaMs))}calculateAverageFps(){const e=this._lastChecks.reduce(((e,s)=>e+s),0);this._currentFps=Math.round(e/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}}class i{_fps=new t;_drawQueue=[];_logicQueue=[];_lowFpsQueue=[];_maxFps;_expectedFps;_time={delta:0,deltaMs:0};_lastTimestamp=0;_logicTicksAccumulatedMs=0;_requestFrameId;constructor(e){this.setFps({min:e?.minFps||0,max:e?.maxFps||60,expected:e?.expectedFps||60}),e?.onDrawTick&&this.addDrawTask(e.onDrawTick),e?.onLogicTick&&this.addLogicTask(e.onLogicTick),e?.onLowFps&&this.addLowFpsTask(e.onLowFps),this._fps.onLowFps((()=>{this._lowFpsQueue.forEach((e=>e.callback(this.fps())))}))}start(){this._lastTimestamp=performance.now(),this.loop(this._lastTimestamp)}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}setFps(e){return e.min&&e.min>0&&this._fps.setMinFps(e.min),e.max&&e.max>0&&(this._maxFps=this.compensatedMaxFps(e.max)),e.expected&&e.expected>0&&(this._expectedFps=e.expected),this}addDrawTask(e){return{index:this._drawQueue.push({callback:e})-1,type:"draw"}}addLogicTask(e){return{index:this._logicQueue.push({callback:e})-1,type:"logic"}}addLowFpsTask(e){return{index:this._lowFpsQueue.push({callback:e})-1,type:"low-fps"}}remove(e){switch(e.type){case"draw":this._drawQueue.splice(e.index,1);break;case"logic":this._logicQueue.splice(e.index,1);break;case"low-fps":this._lowFpsQueue.splice(e.index,1)}}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._time.deltaMs}ticksMissed(){return this._time.deltaMs/(1e3/this._expectedFps)}loop(e){const s=1e3/this._maxFps,t=e-this._lastTimestamp;t>=s&&(this._time={delta:t/1e3,deltaMs:t},this._lastTimestamp=e,this._fps.calculate(this._time),this.runQueue()),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}runQueue(){this._logicQueue.length>0&&this.runLogicQueue(),this._drawQueue.length>0&&this.runDrawQueue()}runLogicQueue(){const e=1e3/this._expectedFps;this._logicTicksAccumulatedMs+=this._time.deltaMs;const s={delta:e/1e3,deltaMs:e};for(;this._logicTicksAccumulatedMs>=e;)this._logicQueue.forEach((e=>e.callback(s))),this._logicTicksAccumulatedMs-=e}runDrawQueue(){this._drawQueue.forEach((e=>e.callback(this._time)))}compensatedMaxFps(e){return Math.floor(1.1*e)+10*Math.floor(e/100)}}class a extends i{_isStarted=!1;start(){this._isStarted=!0}stop(){this._isStarted=!1}isStarted(){return this._isStarted}fps(){return 60}msBetweenTicks(){return 1e3/60}ticksMissed(){return 1}simulateLogicTick(){this._logicQueue.forEach((e=>e.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateDrawTick(){this._drawQueue.forEach((e=>e.callback({delta:1/this.fps(),deltaMs:1e3/this.fps()})))}simulateLowFps(){this._lowFpsQueue.forEach((e=>e.callback(this.fps())))}}return s})())); |
@@ -1,8 +0,26 @@ | ||
| export interface TickerOptionsInterface { | ||
| export interface TickerOptions { | ||
| /** | ||
| * @deprecated Passing `maxFps` in ticker options is deprecated. Use `ticker.setFps({ max: 60 })` instead. | ||
| */ | ||
| maxFps?: number; | ||
| /** | ||
| * @deprecated Passing `expectedFps` in ticker options is deprecated. Use `ticker.setFps({ min: 10 })` instead. | ||
| */ | ||
| minFps?: number; | ||
| /** | ||
| * @deprecated Passing `expectedFps` in ticker options is deprecated. Use `ticker.setFps({ expected: 60 })` instead. | ||
| */ | ||
| expectedFps?: number; | ||
| /** | ||
| * @deprecated Passing `onLogicTick` in ticker options is deprecated. Use `ticker.addLogicTask(callback)` instead. | ||
| */ | ||
| onLogicTick?: () => void; | ||
| /** | ||
| * @deprecated Passing `onDrawTick` in ticker options is deprecated. Use `ticker.addDrawTask(callback)` instead. | ||
| */ | ||
| onDrawTick?: () => void; | ||
| /** | ||
| * @deprecated Passing `onLowFps` in ticker options is deprecated. Use `ticker.addLowFpsTask(callback)` instead. | ||
| */ | ||
| onLowFps?: () => void; | ||
| } |
+1
-1
| { | ||
| "name": "@armniko/ticker", | ||
| "version": "1.1.0", | ||
| "version": "2.0.0", | ||
| "description": "Javascript/typescript library for running app loop with separate logical/drawing ticks and FPS limitation.", | ||
@@ -5,0 +5,0 @@ "author": "Armīns Nikolajevs <armins.nikolajevs@gmail.com>", |
+69
-40
@@ -21,58 +21,79 @@ <h1 align="center">Ticker</h1> | ||
| ```typescript | ||
| import {Ticker} from '@armniko/ticker'; | ||
| import {Ticker, Time} from '@armniko/ticker'; | ||
| const ticker: Ticker = new Ticker({ | ||
| onLogicTick: (): void => { | ||
| // update logic | ||
| }, | ||
| onDrawTick: (): void => { | ||
| // draw | ||
| }, | ||
| const element: { position: { x: number, y: number } } = {position: {x: 0, y: 0}}; | ||
| const animation: { durationMs: number, distancePx: number } = { | ||
| durationMs: 2000, | ||
| distancePx: 500, | ||
| } | ||
| const ticker: Ticker = new Ticker(); | ||
| ticker.addLogicTask((time: Time): void => { | ||
| const pxPerMs: number = animation.distancePx / animation.durationMs; | ||
| element.position.x += pxPerMs * time.deltaMs; | ||
| }); | ||
| ticker.start(); | ||
| ticker.addDrawTask((): void => { | ||
| // draw | ||
| }); | ||
| ``` | ||
| Ticker constructor accepts options object with attributes: | ||
| Ticker instance methods: | ||
| - minFps (default: 0) - defines value at which onLowFps callback will be called. | ||
| - maxFps (default: 60) - defines drawing FPS limit. | ||
| - expectedFps (default: 60) - defines expected logical and drawing FPS at which app should work in normal conditions. | ||
| - onLogicTick (default: undefined) - callback for update app logic. | ||
| - onDrawTick (default: undefined) - callback for update app screen. | ||
| - onLowFps (default: undefined) - callback that will be called when reached minFps. | ||
| - start() - starts ticker. | ||
| - stop() - stops ticker. | ||
| - isStarted() - checks if ticker is started. | ||
| - setFps(options: { min?: number; max?: number; expected?: number }) - set min, max or expected FPS | ||
| - min (default: 0) - defines value at which lowFps task callbacks will be called. | ||
| - max (default: 60) - defines drawing FPS limit. | ||
| - expected (default: 60) - defines expected logical and drawing FPS at which app should work in normal conditions. | ||
| - addLogicTask(callback) - register callback for update app logic. Returns TickerTaskId. | ||
| - addDrawTask(callback) - register callback for update app screen. Returns TickerTaskId. | ||
| - addLowFpsTask(callback) - register callback that will be called when reached min FPS. Returns TickerTaskId. | ||
| - remove(taskId: TickerTaskId) - removes provided task. | ||
| - fps() - current FPS at witch app operate. | ||
| To compensate missed ticks, use msBetweenTicks() and ticksMissed() Ticker methods when calculate logic. | ||
| ## Migration | ||
| ### v1 -> v2 | ||
| Before (v1): | ||
| ```typescript | ||
| // frames based animation | ||
| let x: number = 0; | ||
| const pxPerTick: number = 3; | ||
| const ticker: Ticker = new Ticker({ | ||
| onLogicTick: (): void => { | ||
| x += pxPerTick * ticker.ticksMissed(); | ||
| } | ||
| }); | ||
| ``` | ||
| import {Ticker} from '@armniko/ticker'; | ||
| ```typescript | ||
| // time based animation | ||
| let x: number = 0; | ||
| const animationDurationMs: number = 2000; | ||
| const distancePx: number = 500; | ||
| const pxPerMs: number = distancePx / animationDurationMs; | ||
| const element: { position: { x: number, y: number } } = {position: {x: 0, y: 0}}; | ||
| const animation: { durationMs: number, distancePx: number } = { | ||
| durationMs: 2000, | ||
| distancePx: 500, | ||
| } | ||
| const ticker: Ticker = new Ticker({ | ||
| onLogicTick: (): void => { | ||
| x += pxPerMs * ticker.msBetweenTicks(); | ||
| } | ||
| const pxPerMs: number = distancePx / animationDurationMs; | ||
| element.position.x += pxPerMs * ticker.msBetweenTicks(); | ||
| }, | ||
| onDrawTick: (): void => { | ||
| // draw element | ||
| }, | ||
| }); | ||
| ticker.start(); | ||
| ``` | ||
| Under the hood Ticker collects draw metrics and calculate current FPS. This value can be retrieved from Ticker: | ||
| After (v2): | ||
| ```typescript | ||
| const ticker = new Ticker({ | ||
| onDrawTick: (): void => { | ||
| console.log(ticker.fps()); | ||
| } | ||
| import {Ticker, Time} from '@armniko/ticker'; | ||
| const element: { position: { x: number, y: number } } = {position: {x: 0, y: 0}}; | ||
| const animation: { durationMs: number, distancePx: number } = { | ||
| durationMs: 2000, | ||
| distancePx: 500, | ||
| } | ||
| const ticker: Ticker = new Ticker(); | ||
| ticker.addLogicTask((time: Time): void => { | ||
| const pxPerMs: number = distancePx / animationDurationMs; | ||
| element.position.x += pxPerMs * time.deltaMs; | ||
| }); | ||
| ticker.addDrawTask((): void => { | ||
| // draw element | ||
| }); | ||
| ticker.start(); | ||
| ``` | ||
@@ -84,5 +105,13 @@ | ||
| <tr> | ||
| <td>v2.0.0</td> | ||
| <td> | ||
| Multiple tick callbacks support<br> | ||
| Added TickerMock for testing<br> | ||
| Deprecated: constructor options, msBetweenTicks(), ticksMissed(). (See migration v1 -> v2) | ||
| </td> | ||
| </tr> | ||
| <tr> | ||
| <td>v1.1.0</td> | ||
| <td> | ||
| Precompile UMD and ESM<br> | ||
| Precompile UMD and ESM | ||
| </td> | ||
@@ -89,0 +118,0 @@ </tr> |
| export declare class Fps { | ||
| private _minFps?; | ||
| private _currentFps; | ||
| private _lastChecks; | ||
| private _calculateFpsEachMs; | ||
| private _msSinceLastCalculation; | ||
| private _lowFpsInRow; | ||
| private _lowFpsCallback?; | ||
| currentFps(): number; | ||
| calculate(msSinceLastTick: number): void; | ||
| onLowFps(minFps: number, callback: () => void): void; | ||
| private collectFps; | ||
| private calculateAverageFps; | ||
| private checkAndNotifyLowFps; | ||
| } |
| import { TickerOptionsInterface } from '../interfaces/ticker-options.interface'; | ||
| export declare class Ticker { | ||
| private readonly _fps; | ||
| private _logicTicker; | ||
| private _drawTicker; | ||
| constructor(options?: TickerOptionsInterface); | ||
| start(): void; | ||
| stop(): void; | ||
| isStarted(): boolean; | ||
| fps(): number; | ||
| msBetweenTicks(): number; | ||
| ticksMissed(): number; | ||
| private compensatedMaxFps; | ||
| } |
| export declare class DrawTicker { | ||
| private readonly _maxMsBetweenTicks; | ||
| private readonly _expectedMsBetweenTicks; | ||
| private _ticksMissed; | ||
| private _msBetweenTicks; | ||
| private _lastTickTime; | ||
| private _requestFrameId?; | ||
| private _tickCallback?; | ||
| constructor(maxFps: number, expectedFps: number); | ||
| start(): void; | ||
| stop(): void; | ||
| isStarted(): boolean; | ||
| onTick(callback: (msSinceLastTick: number) => void): void; | ||
| msBetweenTicks(): number; | ||
| ticksMissed(): number; | ||
| private loop; | ||
| } |
| export declare class LogicTicker { | ||
| private readonly _expectedMsBetweenTicks; | ||
| private _ticksMissed; | ||
| private _msBetweenTicks; | ||
| private _lastTickTime; | ||
| private _timeoutId?; | ||
| private _tickCallback?; | ||
| constructor(expectedFps: number); | ||
| start(): void; | ||
| stop(): void; | ||
| isStarted(): boolean; | ||
| onTick(callback: (msSinceLastTick: number) => void): void; | ||
| msBetweenTicks(): number; | ||
| ticksMissed(): number; | ||
| private delayLoop; | ||
| private loop; | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
18040
22.18%15
36.36%123
70.83%124
30.53%