@omnedia/ngx-number-ticker
Version:
A simple number ticker effect to animate counting.
1 lines • 11.8 kB
Source Map (JSON)
{"version":3,"file":"omnedia-ngx-number-ticker.mjs","sources":["../../../projects/ngx-number-ticker/src/lib/ngx-number-ticker.component.ts","../../../projects/ngx-number-ticker/src/lib/ngx-number-ticker.component.html","../../../projects/ngx-number-ticker/src/public-api.ts","../../../projects/ngx-number-ticker/src/omnedia-ngx-number-ticker.ts"],"sourcesContent":["import {CommonModule} from \"@angular/common\";\r\nimport {ChangeDetectionStrategy, Component, Input, signal} from \"@angular/core\";\r\n\r\n@Component({\r\n selector: \"om-number-ticker\",\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: \"./ngx-number-ticker.component.html\",\r\n styleUrl: \"./ngx-number-ticker.component.scss\",\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class NgxNumberTickerComponent {\r\n @Input(\"styleClass\")\r\n styleClass?: string;\r\n\r\n @Input(\"countTo\")\r\n set countTo(number: number) {\r\n this.targetNumber = number;\r\n this.countToNumber(number);\r\n }\r\n\r\n @Input(\"countDuration\")\r\n set countDuration(countDuration: number) {\r\n this.countDurationValue = countDuration;\r\n\r\n if (this.frameId) {\r\n cancelAnimationFrame(this.frameId);\r\n this.frameId = undefined;\r\n this.countToNumber(this.targetNumber);\r\n }\r\n }\r\n\r\n countDurationValue = 2000;\r\n\r\n @Input(\"transformFunction\")\r\n transformFunction?: (number: number) => string;\r\n\r\n targetNumber = 0;\r\n currentNumber = 0;\r\n displayNumber = signal(\"0\");\r\n\r\n private frameId?: number;\r\n\r\n private countToNumber(number: number): void {\r\n if (number > this.currentNumber) {\r\n this.countUp(number);\r\n return;\r\n }\r\n\r\n this.countDown(number);\r\n }\r\n\r\n private countUp(target: number): void {\r\n const direction = \"up\";\r\n this.executeCount(target, direction);\r\n }\r\n\r\n private countDown(target: number): void {\r\n const direction = \"down\";\r\n this.executeCount(target, direction);\r\n }\r\n\r\n setCountValue(): void {\r\n if (!this.transformFunction) {\r\n this.displayNumber.set(`${this.currentNumber}`);\r\n } else {\r\n this.displayNumber.set(this.transformFunction(this.currentNumber));\r\n }\r\n }\r\n\r\n private executeCount(target: number, direction: \"up\" | \"down\"): void {\r\n const startNumber = this.currentNumber;\r\n const difference = Math.abs(target - startNumber);\r\n\r\n // Check if we have fewer than 10 digits to count\r\n const isSmallDifference = difference <= 10;\r\n const duration = this.countDurationValue;\r\n\r\n // If the difference is small, handle all of them in the easing phase\r\n if (isSmallDifference) {\r\n const slowCountingDuration = duration;\r\n const startTime = performance.now();\r\n\r\n const updateSmallDifference = (currentTime: number) => {\r\n const elapsed = currentTime - startTime;\r\n const percentComplete = Math.min(elapsed / slowCountingDuration, 1);\r\n const easedPercent = this.easeOutQuad(percentComplete);\r\n\r\n // Calculate the current number based on the eased percent\r\n this.currentNumber = this.calculateCurrentNumber(\r\n startNumber,\r\n target,\r\n easedPercent,\r\n direction,\r\n );\r\n\r\n if (elapsed < slowCountingDuration) {\r\n this.setCountValue();\r\n this.frameId = requestAnimationFrame(updateSmallDifference);\r\n } else {\r\n this.currentNumber = target; // Ensure final number is set\r\n this.setCountValue();\r\n }\r\n };\r\n\r\n this.frameId = requestAnimationFrame(updateSmallDifference);\r\n } else {\r\n // Normal case: Handle large differences with two phases\r\n const last10DigitsDuration = 1000; // 1 second for the last 10 digits\r\n const mainCountingDuration = duration - last10DigitsDuration;\r\n\r\n const last10Start = direction === \"up\" ? target - 10 : target + 10;\r\n const startTime = performance.now();\r\n\r\n const update = (currentTime: number) => {\r\n const elapsed = currentTime - startTime;\r\n\r\n if (\r\n (direction === \"up\" && this.currentNumber < last10Start) ||\r\n (direction === \"down\" && this.currentNumber > last10Start)\r\n ) {\r\n // Phase 1: Main counting phase\r\n const percentComplete = Math.min(elapsed / mainCountingDuration, 1);\r\n\r\n // Calculate current number based on the percentage of completion\r\n this.currentNumber = this.calculateCurrentNumber(\r\n startNumber,\r\n last10Start,\r\n percentComplete,\r\n direction,\r\n );\r\n\r\n if (elapsed < mainCountingDuration) {\r\n this.setCountValue();\r\n this.frameId = requestAnimationFrame(update);\r\n } else {\r\n this.currentNumber = last10Start;\r\n this.setCountValue();\r\n this.frameId = requestAnimationFrame(update);\r\n }\r\n } else {\r\n // Phase 2: Slow down for the last 10 digits\r\n const elapsedForLast10 = elapsed - mainCountingDuration;\r\n const percentComplete = Math.min(\r\n elapsedForLast10 / last10DigitsDuration,\r\n 1,\r\n );\r\n const easedPercent = this.easeOutQuad(percentComplete);\r\n\r\n // Calculate the number for the last 10 digits\r\n this.currentNumber = this.calculateCurrentNumber(\r\n last10Start,\r\n target,\r\n easedPercent,\r\n direction,\r\n );\r\n\r\n if (elapsedForLast10 < last10DigitsDuration) {\r\n this.setCountValue();\r\n this.frameId = requestAnimationFrame(update);\r\n } else {\r\n this.currentNumber = target; // Ensure final number is set\r\n this.setCountValue();\r\n }\r\n }\r\n };\r\n\r\n this.frameId = requestAnimationFrame(update);\r\n }\r\n }\r\n\r\n // Helper function to calculate current number based on direction\r\n private calculateCurrentNumber(\r\n start: number,\r\n end: number,\r\n percent: number,\r\n direction: \"up\" | \"down\",\r\n ): number {\r\n if (direction === \"up\") {\r\n return Math.floor(start + (end - start) * percent);\r\n } else {\r\n return Math.floor(start - (start - end) * percent);\r\n }\r\n }\r\n\r\n // Easing function to slow down progressively\r\n private easeOutQuad(t: number): number {\r\n return t * (2 - t);\r\n }\r\n}\r\n","<p class=\"om-number-ticker\" [ngClass]=\"styleClass\">\r\n {{ displayNumber() }}\r\n</p>\r\n","/*\r\n * Public API Surface of ngx-number-ticker\r\n */\r\n\r\nexport * from \"./lib/ngx-number-ticker.component\";\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}