avances en plantillas
This commit is contained in:
parent
0f84beacf1
commit
da0530d79b
2062 changed files with 598814 additions and 22 deletions
12
storage/public/dist/libs/countup.js/.editorconfig
vendored
Normal file
12
storage/public/dist/libs/countup.js/.editorconfig
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# This file is for unifying the coding style for different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
21
storage/public/dist/libs/countup.js/.eslintrc.js
vendored
Normal file
21
storage/public/dist/libs/countup.js/.eslintrc.js
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
ignorePatterns: ['*.js', '*.html', 'node_modules/*'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'no-prototype-builtins': 'off',
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
}
|
||||
};
|
||||
13
storage/public/dist/libs/countup.js/.github/ISSUE_TEMPLATE.md
vendored
Normal file
13
storage/public/dist/libs/countup.js/.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Please enter the info below -->
|
||||
```
|
||||
[ ] Bug
|
||||
[ ] Feature request
|
||||
|
||||
CountUp.js version:
|
||||
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
<!-- If this is a bug, provide steps to reproduce the issue. -->
|
||||
<!-- If this is a feature request, describe the use case. -->
|
||||
29
storage/public/dist/libs/countup.js/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
29
storage/public/dist/libs/countup.js/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
## I'm submitting a...
|
||||
|
||||
```
|
||||
[ ] Bug Fix
|
||||
[ ] Feature
|
||||
[ ] Other (Refactoring, Added tests, Documentation, ...)
|
||||
```
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Test your changes
|
||||
- [ ] Followed the build steps
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
_please describe the changes that you are making_
|
||||
|
||||
_for features, please describe how to use the new feature_
|
||||
|
||||
_please include a reference to an existing issue, if applicable_
|
||||
|
||||
|
||||
## Does this PR introduce a breaking change?
|
||||
|
||||
```
|
||||
[ ] Yes
|
||||
[ ] No
|
||||
```
|
||||
47
storage/public/dist/libs/countup.js/.vscode/tasks.json
vendored
Normal file
47
storage/public/dist/libs/countup.js/.vscode/tasks.json
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "gulp",
|
||||
"task": "build",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Open in Chrome Mac",
|
||||
"command": "Chrome",
|
||||
"osx": {
|
||||
"command": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||
},
|
||||
"args": [
|
||||
"${file}"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Open in Chrome Linux",
|
||||
"command": "Chrome",
|
||||
"linux": {
|
||||
"command": "google-chrome"
|
||||
},
|
||||
"args": [
|
||||
"${file}"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Open in Chrome Windows",
|
||||
"command": "Chrome",
|
||||
"windows": {
|
||||
"command": "start chrome"
|
||||
},
|
||||
"args": [
|
||||
"${file}"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
18
storage/public/dist/libs/countup.js/LICENSE.md
vendored
Normal file
18
storage/public/dist/libs/countup.js/LICENSE.md
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
281
storage/public/dist/libs/countup.js/README.md
vendored
Normal file
281
storage/public/dist/libs/countup.js/README.md
vendored
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
# CountUp.js
|
||||
|
||||
CountUp.js is a dependency-free, lightweight Javascript class that animates a numerical value by counting to it.
|
||||
|
||||
Despite its name, CountUp can count in either direction, depending on the start and end values that you provide.
|
||||
|
||||
CountUp.js supports all browsers. MIT license.
|
||||
|
||||
## [Try the demo](https://inorganik.github.io/countUp.js)
|
||||
|
||||
Or tinker with CountUp in [Stackblitz](https://stackblitz.com/edit/countup-typescript)
|
||||
|
||||
## Jump to:
|
||||
|
||||
- **[Usage](#usage)**
|
||||
- **[Including CountUp](#including-countup)**
|
||||
- **[Contributing](#contributing)**
|
||||
- **[Creating Animation Plugins](#creating-animation-plugins)**
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-animate when element becomes visible.** Use option `autoAnimate = true`.
|
||||
- **Highly customizable** with a large range of options, you can even substitute numerals.
|
||||
- **Smart easing**: CountUp intelligently defers easing to make it visually noticeable. Configurable in the [options](#options).
|
||||
- **Plugins** allow for alternate animations like the [Odometer plugin](https://www.npmjs.com/package/odometer_countup)
|
||||
|
||||

|
||||
|
||||
## Usage:
|
||||
|
||||
**Use CountUp with:**
|
||||
|
||||
- [Angular 2+](https://github.com/inorganik/ngx-countUp)
|
||||
- [React](https://gist.github.com/inorganik/2cf776865a4c65c12857027870e9898e)
|
||||
- [Svelte](https://gist.github.com/inorganik/85a66941ab88cc10c5fa5b26aead5f2a)
|
||||
- [Vue](https://github.com/xlsdg/vue-countup-v2)
|
||||
- [WordPress](https://wordpress.org/plugins/countup-js/)
|
||||
- [jQuery](https://gist.github.com/inorganik/b63dbe5b3810ff2c0175aee4670a4732)
|
||||
- [custom element](https://github.com/lekoala/formidable-elements/blob/master/docs/count-up.md)
|
||||
|
||||
**Use CountUp directly:**
|
||||
|
||||
On npm as `countup.js`. You can import as a module, or include the UMD script and access CountUp as a global. See [detailed instructions](#including-countup) on including CountUp.
|
||||
|
||||
**Params**:
|
||||
|
||||
- `target: string | HTMLElement | HTMLInputElement` - id of html element, input, svg text element, or DOM element reference where counting occurs.
|
||||
- `endVal: number | null` - the value you want to arrive at. Leave null to use the number in the target element.
|
||||
- `options?: CountUpOptions` - optional configuration object for fine-grain control
|
||||
|
||||
**Options**:
|
||||
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| ---------------------- | --------------- | ------------- | ------------------------------------------------------- |
|
||||
| `startVal` | `number` | `0` | Number to start at |
|
||||
| `decimalPlaces` | `number` | `0` | Number of decimal places |
|
||||
| `duration` | `number` | `2` | Animation duration in seconds |
|
||||
| `useGrouping` | `boolean` | `true` | Example: 1,000 vs 1000 |
|
||||
| `useIndianSeparators` | `boolean` | `false` | Example: 1,00,000 vs 100,000 |
|
||||
| `useEasing` | `boolean` | `true` | Ease animation |
|
||||
| `smartEasingThreshold` | `number` | `999` | Smooth easing for large numbers above this if useEasing |
|
||||
| `smartEasingAmount` | `number` | `333` | Amount to be eased for numbers above threshold |
|
||||
| `separator` | `string` | `','` | Grouping separator |
|
||||
| `decimal` | `string` | `'.'` | Decimal character |
|
||||
| `easingFn` | `function` | `easeOutExpo` | Easing function for animation |
|
||||
| `formattingFn` | `function` | — | Custom function to format the result |
|
||||
| `prefix` | `string` | `''` | Text prepended to result |
|
||||
| `suffix` | `string` | `''` | Text appended to result |
|
||||
| `numerals` | `string[]` | — | Numeral glyph substitution |
|
||||
| `onCompleteCallback` | `function` | — | Callback called when animation completes |
|
||||
| `onStartCallback` | `function` | — | Callback called when animation starts |
|
||||
| `plugin` | `CountUpPlugin` | — | Plugin for alternate animations |
|
||||
| `autoAnimate` | `boolean` | `false` | Trigger animation when target becomes visible |
|
||||
| `autoAnimateDelay` | `number` | `200` | Animation delay in ms after auto-animate triggers |
|
||||
| `autoAnimateOnce` | `boolean` | `false` | Run animation only once for auto-animate triggers |
|
||||
| `enableScrollSpy` | `boolean` | — | *(deprecated)* Use `autoAnimate` instead |
|
||||
| `scrollSpyDelay` | `number` | — | *(deprecated)* Use `autoAnimateDelay` instead |
|
||||
| `scrollSpyOnce` | `boolean` | — | *(deprecated)* Use `autoAnimateOnce` instead |
|
||||
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```js
|
||||
const countUp = new CountUp('targetId', 5234);
|
||||
if (!countUp.error) {
|
||||
countUp.start();
|
||||
} else {
|
||||
console.error(countUp.error);
|
||||
}
|
||||
```
|
||||
|
||||
Pass options:
|
||||
|
||||
```js
|
||||
const countUp = new CountUp('targetId', 5234, options);
|
||||
```
|
||||
|
||||
with optional complete callback:
|
||||
|
||||
```js
|
||||
const countUp = new CountUp('targetId', 5234, { onCompleteCallback: someMethod });
|
||||
|
||||
// or (passing fn to start will override options.onCompleteCallback)
|
||||
countUp.start(someMethod);
|
||||
|
||||
// or
|
||||
countUp.start(() => console.log('Complete!'));
|
||||
```
|
||||
|
||||
**Other methods**:
|
||||
|
||||
Toggle pause/resume:
|
||||
|
||||
```js
|
||||
countUp.pauseResume();
|
||||
```
|
||||
|
||||
Reset the animation:
|
||||
|
||||
```js
|
||||
countUp.reset();
|
||||
```
|
||||
|
||||
Update the end value and animate:
|
||||
|
||||
```js
|
||||
countUp.update(989);
|
||||
```
|
||||
|
||||
Destroy the instance (cancels animation, disconnects observers, clears callbacks):
|
||||
|
||||
```js
|
||||
countUp.onDestroy();
|
||||
```
|
||||
---
|
||||
|
||||
### **Auto animate when element becomes visible**
|
||||
|
||||
Use the `autoAnimate` option to animate when the element is scrolled into view or appears on screen. When using autoAnimate, just initialize CountUp but do not call start().
|
||||
|
||||
```js
|
||||
const countUp = new CountUp('targetId', 989, { autoAnimate: true });
|
||||
```
|
||||
|
||||
**Note** - Auto-animate uses IntersectionObserver which is broadly supported, but if you need to support some very old browsers, v2.9.0 and earlier use a window on-scroll handler when `enableScrollSpy` is set to true.
|
||||
|
||||
---
|
||||
|
||||
### **Alternate animations with plugins**
|
||||
|
||||
Currently there's just one plugin, the **[Odometer Plugin](https://github.com/msoler75/odometer_countup.js)**.
|
||||
|
||||
To use a plugin, you'll need to first install the plugin package. Then you can include it and use the plugin option. See each plugin's docs for more detailed info.
|
||||
|
||||
```js
|
||||
const countUp = new CountUp('targetId', 5234, {
|
||||
plugin: new Odometer({ duration: 2.3, lastDigitDelay: 0 }),
|
||||
duration: 3.0
|
||||
});
|
||||
```
|
||||
|
||||
If you'd like to make your own plugin, see [the docs](#creating-animation-plugins) below!
|
||||
|
||||
### Tabular nums
|
||||
|
||||
To optimize the styling of counting number animations, you can take advantage of an OpenType feature called tabular nums which stabilizes jitteryness by using equal-width numbers.
|
||||
|
||||
In my experience, most OpenType fonts already use tabular nums, so this isn't needed. But it may help to add this style if they don't:
|
||||
|
||||
```css
|
||||
font-variant-numeric: tabular-nums;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Including CountUp
|
||||
|
||||
CountUp is distributed as an ES module, though a UMD module is [also included](#umd-module), along with a separate requestAnimationFrame polyfill (see below).
|
||||
|
||||
For the examples below, first install CountUp:
|
||||
|
||||
```
|
||||
npm i countup.js
|
||||
```
|
||||
|
||||
### Example with vanilla js
|
||||
|
||||
This is what is used in the demo. Checkout index.html and demo.js.
|
||||
|
||||
main.js:
|
||||
```js
|
||||
import { CountUp } from './js/countUp.min.js';
|
||||
|
||||
window.onload = function() {
|
||||
var countUp = new CountUp('target', 2000);
|
||||
countUp.start();
|
||||
}
|
||||
```
|
||||
|
||||
Include in your html. Notice the `type` attribute:
|
||||
|
||||
```html
|
||||
<script src="./main.js" type="module"></script>
|
||||
```
|
||||
|
||||
If you prefer not to use modules, use the `nomodule` script tag to include separate scripts:
|
||||
|
||||
```html
|
||||
<script nomodule src="js/countUp.umd.js"></script>
|
||||
<script nomodule src="js/main-for-legacy.js"></script>
|
||||
```
|
||||
|
||||
To run module-enabled scripts locally, you'll need a simple local server setup like [this](https://www.npmjs.com/package/http-server) (test the demo locally by running `npm run serve`) because otherwise you may see a CORS error when your browser tries to load the script as a module.
|
||||
|
||||
### For Webpack and other build systems
|
||||
|
||||
Import from the package, instead of the file location:
|
||||
|
||||
```js
|
||||
import { CountUp } from 'countup.js';
|
||||
```
|
||||
|
||||
### UMD module
|
||||
|
||||
CountUp is also wrapped as a UMD module in `./dist/countUp.umd.js` and it exposes CountUp as a global variable on the window scope. To use it, include `countUp.umd.js` in a script tag, and invoke it like so:
|
||||
|
||||
```js
|
||||
var numAnim = new countUp.CountUp('myTarget', 2000);
|
||||
numAnim.start()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Before you make a pull request, please be sure to follow these instructions:
|
||||
|
||||
1. Do your work on `src/countUp.ts`
|
||||
1. Lint: `npm run lint`
|
||||
1. Run tests: `npm t`
|
||||
1. Build and serve the demo by running `npm start` then check the demo to make sure it counts.
|
||||
|
||||
<!-- PUBLISHING
|
||||
|
||||
1. bump version in package.json and countUp.ts
|
||||
2. npm run build
|
||||
3. commit changes
|
||||
4. npm publish
|
||||
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
## Creating Animation Plugins
|
||||
|
||||
CountUp supports plugins as of v2.6.0. Plugins implement their own render method to display each frame's formatted value. A class instance or object can be passed to the `plugin` property of CountUpOptions, and the plugin's render method will be called instead of CountUp's.
|
||||
|
||||
```ts
|
||||
export declare interface CountUpPlugin {
|
||||
render(elem: HTMLElement, formatted: string): void;
|
||||
}
|
||||
```
|
||||
|
||||
An example of a plugin:
|
||||
|
||||
```ts
|
||||
export class SomePlugin implements CountUpPlugin {
|
||||
// ...some properties here
|
||||
|
||||
constructor(options: SomePluginOptions) {
|
||||
// ...setup code here if you need it
|
||||
}
|
||||
|
||||
render(elem: HTMLElement, formatted: string): void {
|
||||
// render DOM here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you make a plugin, be sure to create a PR to add it to this README!
|
||||
221
storage/public/dist/libs/countup.js/demo/demo-nomodule.js
vendored
Normal file
221
storage/public/dist/libs/countup.js/demo/demo-nomodule.js
vendored
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
// same as demo.js but with a different instantiation of CountUp,
|
||||
// and no lambdas
|
||||
|
||||
window.onload = function () {
|
||||
var el = function (id) {
|
||||
return document.getElementById(id);
|
||||
};
|
||||
var code, stars, endVal, options;
|
||||
var demo = new countUp.CountUp('myTargetElement', 100);
|
||||
var codeVisualizer = el('codeVisualizer');
|
||||
var errorSection = el('errorSection');
|
||||
el('version').innerHTML = demo.version;
|
||||
|
||||
var changeEls = document.querySelectorAll('.updateCodeVis');
|
||||
for (var i = 0, len = changeEls.length; i < len; i++) {
|
||||
changeEls[i].onchange = updateCodeVisualizer;
|
||||
}
|
||||
|
||||
el('swapValues').onclick = function () {
|
||||
var oldStartVal = el('startVal').value;
|
||||
var oldEndVal = el('endVal').value;
|
||||
el('startVal').value = oldEndVal;
|
||||
el('endVal').value = oldStartVal;
|
||||
updateCodeVisualizer();
|
||||
};
|
||||
el('start').onclick = createCountUp;
|
||||
el('apply').onclick = createCountUp;
|
||||
el('pauseResume').onclick = function () {
|
||||
code += '<br>demo.pauseResume();';
|
||||
codeVisualizer.innerHTML = code;
|
||||
demo.pauseResume();
|
||||
};
|
||||
el('reset').onclick = function () {
|
||||
code += '<br>demo.reset();';
|
||||
codeVisualizer.innerHTML = code;
|
||||
demo.reset();
|
||||
};
|
||||
el('update').onclick = function () {
|
||||
var updateVal = el('updateVal').value;
|
||||
var num = updateVal ? updateVal : 0;
|
||||
code += "<br>demo.update(" + num + ");";
|
||||
codeVisualizer.innerHTML = code;
|
||||
demo.update(num);
|
||||
};
|
||||
el('updateVal').onchange = function () {
|
||||
var updateVal = el('updateVal').value;
|
||||
var num = updateVal ? updateVal : 0;
|
||||
code += '<br>demo.update(' + num + ');';
|
||||
codeVisualizer.innerHTML = code;
|
||||
};
|
||||
// OPTION VALUES
|
||||
var easingFunctions = {
|
||||
easeOutExpo: function (t, b, c, d) {
|
||||
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
|
||||
},
|
||||
outQuintic: function (t, b, c, d) {
|
||||
var ts = (t /= d) * t;
|
||||
var tc = ts * t;
|
||||
return b + c * (tc * ts + -5 * ts * ts + 10 * tc + -10 * ts + 5 * t);
|
||||
},
|
||||
outCubic: function (t, b, c, d) {
|
||||
var ts = (t /= d) * t;
|
||||
var tc = ts * t;
|
||||
return b + c * (tc + -3 * ts + 3 * t);
|
||||
}
|
||||
};
|
||||
function getEasingFn() {
|
||||
var fn = el('easingFnsDropdown').value;
|
||||
if (fn === 'easeOutExpo') {
|
||||
return null;
|
||||
}
|
||||
if (typeof easingFunctions[fn] === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
return easingFunctions[fn];
|
||||
}
|
||||
function getEasingFnBody(fn) {
|
||||
fn = typeof fn === 'undefined' ? getEasingFn() : fn;
|
||||
if (typeof fn === 'undefined') {
|
||||
return 'undefined function';
|
||||
}
|
||||
if (fn !== null) {
|
||||
return fn.toString().replace(/^ {8}/gm, '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
function getNumerals() {
|
||||
var numeralsCode = el('numeralsDropdown').value;
|
||||
// optionally provide alternates for 0-9
|
||||
switch (numeralsCode) {
|
||||
case 'ea': // Eastern Arabic
|
||||
return ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
|
||||
case 'fa': // Farsi
|
||||
return ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
var stringifyArray = function (arr) { return '[\'' + arr.join('\', \'') + '\']'; };
|
||||
|
||||
// COUNTUP AND CODE VISUALIZER
|
||||
|
||||
function createCountUp() {
|
||||
establishOptionsFromInputs();
|
||||
demo = new countUp.CountUp('myTargetElement', endVal, options);
|
||||
if (!demo.error) {
|
||||
errorSection.style.display = 'none';
|
||||
demo.start();
|
||||
updateCodeVisualizer();
|
||||
}
|
||||
else {
|
||||
errorSection.style.display = 'block';
|
||||
document.getElementById('error').innerHTML = demo.error;
|
||||
console.error(demo.error);
|
||||
}
|
||||
}
|
||||
function methodToCallOnComplete() {
|
||||
console.log('COMPLETE!');
|
||||
alert('COMPLETE!');
|
||||
}
|
||||
function establishOptionsFromInputs() {
|
||||
endVal = Number(el('endVal').value);
|
||||
options = {
|
||||
startVal: el('startVal').value,
|
||||
decimalPlaces: el('decimalPlaces').value,
|
||||
duration: Number(el('duration').value),
|
||||
useEasing: el('useEasing').checked,
|
||||
useGrouping: el('useGrouping').checked,
|
||||
useIndianSeparators: el('useIndianSeparators').checked,
|
||||
easingFn: typeof getEasingFn() === 'undefined' ? null : getEasingFn(),
|
||||
separator: el('separator').value,
|
||||
decimal: el('decimal').value,
|
||||
prefix: el('prefix').value,
|
||||
suffix: el('suffix').value,
|
||||
numerals: getNumerals(),
|
||||
onCompleteCallback: el('useOnComplete').checked ? methodToCallOnComplete : null
|
||||
};
|
||||
// unset null values so they don't overwrite defaults
|
||||
for (var key in options) {
|
||||
if (options.hasOwnProperty(key)) {
|
||||
if (options[key] === null) {
|
||||
delete options[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function updateCodeVisualizer() {
|
||||
establishOptionsFromInputs();
|
||||
code = '';
|
||||
if (options.useEasing && options.easingFn) {
|
||||
code += 'const easingFn = ';
|
||||
var split = getEasingFnBody(options.easingFn).split('\n');
|
||||
for (var line in split) {
|
||||
if (split.hasOwnProperty(line)) {
|
||||
code += split[line].replace(' ', ' ') + '<br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
function indentedLine(keyPair, singleLine) {
|
||||
if (singleLine === void 0) { singleLine = false; }
|
||||
var delimeter = (singleLine) ? ';' : ',';
|
||||
return "  " + keyPair + delimeter + "<br>";
|
||||
}
|
||||
var opts = '';
|
||||
opts += (options.startVal !== '0') ? indentedLine("startVal: " + options.startVal) : '';
|
||||
opts += (options.decimalPlaces !== '0') ? indentedLine("decimalPlaces: " + options.decimalPlaces) : '';
|
||||
opts += (options.duration !== 2) ? indentedLine("duration: " + options.duration) : '';
|
||||
opts += (options.useEasing) ? '' : indentedLine("useEasing: " + options.useEasing);
|
||||
opts += (options.useEasing && options.easingFn) ? indentedLine("easingFn") : '';
|
||||
opts += (options.useGrouping) ? '' : indentedLine("useGrouping: " + options.useGrouping);
|
||||
opts += (options.useIndianSeparators) ? indentedLine("useIndianSeparators: " + options.useIndianSeparators) : '';
|
||||
opts += (options.separator !== ',') ? indentedLine("separator: '" + options.separator + "'") : '';
|
||||
opts += (options.decimal !== '.') ? indentedLine("decimal: '" + options.decimal + "'") : '';
|
||||
opts += (options.prefix.length) ? indentedLine("prefix: '" + options.prefix + "'") : '';
|
||||
opts += (options.suffix.length) ? indentedLine("suffix: '" + options.suffix + "'") : '';
|
||||
opts += (options.numerals && options.numerals.length) ?
|
||||
indentedLine("numerals: " + stringifyArray(options.numerals)) : '';
|
||||
opts += (options.onCompleteCallback) ? indentedLine("onCompleteCallback: methodToCallOnComplete") : '';
|
||||
|
||||
if (opts.length) {
|
||||
code += "const options = {<br>" + opts + "};<br>";
|
||||
code += "let demo = new CountUp('myTargetElement', " + endVal + ", options);<br>";
|
||||
}
|
||||
else {
|
||||
code += "let demo = new CountUp('myTargetElement', " + endVal + ");<br>";
|
||||
}
|
||||
code += 'if (!demo.error) {<br>';
|
||||
code += indentedLine('demo.start()', true);
|
||||
code += '} else {<br>';
|
||||
code += indentedLine('console.error(demo.error)', true);
|
||||
code += '}';
|
||||
codeVisualizer.innerHTML = code;
|
||||
}
|
||||
// get current star count
|
||||
var repoInfoUrl = 'https://api.github.com/repos/inorganik/CountUp.js';
|
||||
var getStars = new XMLHttpRequest();
|
||||
getStars.open('GET', repoInfoUrl, true);
|
||||
getStars.timeout = 5000;
|
||||
getStars.onreadystatechange = function () {
|
||||
// 2: received headers, 3: loading, 4: done
|
||||
if (getStars.readyState === 4) {
|
||||
if (getStars.status === 200) {
|
||||
if (getStars.responseText !== 'undefined') {
|
||||
if (getStars.responseText.length > 0) {
|
||||
var data = JSON.parse(getStars.responseText);
|
||||
stars = data.stargazers_count;
|
||||
// change input values
|
||||
el('endVal').value = stars;
|
||||
createCountUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
getStars.onerror = function () {
|
||||
console.error('error getting stars:', getStars.status);
|
||||
stars = getStars.status;
|
||||
demo.start();
|
||||
};
|
||||
getStars.send();
|
||||
}
|
||||
256
storage/public/dist/libs/countup.js/demo/demo.js
vendored
Normal file
256
storage/public/dist/libs/countup.js/demo/demo.js
vendored
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
import { CountUp } from '../dist/countUp.js';
|
||||
|
||||
const el = (id) => document.getElementById(id);
|
||||
|
||||
let code, stars, endVal, options;
|
||||
let demo = new CountUp('myTargetElement', 100);
|
||||
let scrollSpyCountUp, hiddenAtInitCountUp, insideModalCountUp;
|
||||
const codeVisualizer = el('codeVisualizer');
|
||||
const errorSection = el('errorSection');
|
||||
let startTime;
|
||||
el('version').textContent = demo.version;
|
||||
|
||||
document.querySelectorAll('.updateCodeVis').forEach((elem) => {
|
||||
elem.addEventListener('change', updateCodeVisualizer);
|
||||
});
|
||||
|
||||
el('swapValues').addEventListener('click', () => {
|
||||
const oldStartVal = el('startVal').value;
|
||||
const oldEndVal = el('endVal').value;
|
||||
el('startVal').value = oldEndVal;
|
||||
el('endVal').value = oldStartVal;
|
||||
updateCodeVisualizer();
|
||||
});
|
||||
el('start').addEventListener('click', createCountUp);
|
||||
el('apply').addEventListener('click', createCountUp);
|
||||
el('pauseResume').addEventListener('click', () => {
|
||||
code += '<br>demo.pauseResume();';
|
||||
codeVisualizer.innerHTML = code;
|
||||
demo.pauseResume();
|
||||
});
|
||||
el('reset').addEventListener('click', () => {
|
||||
code += '<br>demo.reset();';
|
||||
codeVisualizer.innerHTML = code;
|
||||
demo.reset();
|
||||
});
|
||||
el('update').addEventListener('click', () => {
|
||||
const num = el('updateVal').value || 0;
|
||||
code += `<br>demo.update(${num});`;
|
||||
codeVisualizer.innerHTML = code;
|
||||
demo.update(num);
|
||||
});
|
||||
el('updateVal').addEventListener('change', () => {
|
||||
const num = el('updateVal').value || 0;
|
||||
code += `<br>demo.update(${num});`;
|
||||
codeVisualizer.innerHTML = code;
|
||||
});
|
||||
|
||||
const easingFunctions = {
|
||||
easeOutExpo: (t, b, c, d) => c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b,
|
||||
outQuintic: (t, b, c, d) => {
|
||||
const ts = (t /= d) * t;
|
||||
const tc = ts * t;
|
||||
return b + c * (tc * ts + -5 * ts * ts + 10 * tc + -10 * ts + 5 * t);
|
||||
},
|
||||
outCubic: (t, b, c, d) => {
|
||||
const ts = (t /= d) * t;
|
||||
const tc = ts * t;
|
||||
return b + c * (tc + -3 * ts + 3 * t);
|
||||
}
|
||||
};
|
||||
|
||||
function getEasingFn() {
|
||||
const fn = el('easingFnsDropdown').value;
|
||||
if (fn === 'easeOutExpo') return null;
|
||||
if (easingFunctions[fn] === undefined) return undefined;
|
||||
return easingFunctions[fn];
|
||||
}
|
||||
|
||||
function getEasingFnBody(fn = getEasingFn()) {
|
||||
if (fn === undefined) return 'undefined function';
|
||||
if (fn !== null) return fn.toString().replace(/^ {4}/gm, '');
|
||||
return '';
|
||||
}
|
||||
|
||||
function getNumerals() {
|
||||
const numeralsCode = el('numeralsDropdown').value;
|
||||
switch (numeralsCode) {
|
||||
case 'ea':
|
||||
return ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
|
||||
case 'fa':
|
||||
return ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const stringifyArray = (arr) => `['${arr.join("', '")}']`;
|
||||
|
||||
function createCountUp() {
|
||||
demo.onDestroy();
|
||||
establishOptionsFromInputs();
|
||||
demo = new CountUp('myTargetElement', endVal, options);
|
||||
if (!demo.error) {
|
||||
errorSection.style.display = 'none';
|
||||
startTime = Date.now();
|
||||
demo.start();
|
||||
updateCodeVisualizer();
|
||||
} else {
|
||||
errorSection.style.display = 'block';
|
||||
el('error').textContent = demo.error;
|
||||
console.error(demo.error);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateAnimationTime() {
|
||||
const duration = Date.now() - startTime;
|
||||
console.log('actual animation duration (ms):', duration);
|
||||
alert('COMPLETE!');
|
||||
}
|
||||
|
||||
function establishOptionsFromInputs() {
|
||||
endVal = Number(el('endVal').value);
|
||||
options = {
|
||||
startVal: el('startVal').value,
|
||||
decimalPlaces: el('decimalPlaces').value,
|
||||
duration: Number(el('duration').value),
|
||||
useGrouping: el('useGrouping').checked,
|
||||
useIndianSeparators: el('useIndianSeparators').checked,
|
||||
easingFn: getEasingFn() ?? null,
|
||||
separator: el('separator').value,
|
||||
decimal: el('decimal').value,
|
||||
prefix: el('prefix').value,
|
||||
numerals: getNumerals(),
|
||||
onCompleteCallback: el('useOnComplete').checked ? calculateAnimationTime : null
|
||||
};
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
if (value === null) delete options[key];
|
||||
}
|
||||
}
|
||||
|
||||
function updateCodeVisualizer() {
|
||||
establishOptionsFromInputs();
|
||||
code = '';
|
||||
if (options.easingFn) {
|
||||
code += 'const easingFn = ';
|
||||
for (const line of getEasingFnBody(options.easingFn).split('\n')) {
|
||||
code += `${line.replace(' ', ' ')}<br>`;
|
||||
}
|
||||
}
|
||||
const indentedLine = (keyPair, singleLine = false) => {
|
||||
const delimiter = singleLine ? ';' : ',';
|
||||
return `  ${keyPair}${delimiter}<br>`;
|
||||
};
|
||||
let opts = '';
|
||||
opts += (options.startVal !== '0') ? indentedLine(`startVal: ${options.startVal}`) : '';
|
||||
opts += (options.decimalPlaces !== '0') ? indentedLine(`decimalPlaces: ${options.decimalPlaces}`) : '';
|
||||
opts += (options.duration !== 2) ? indentedLine(`duration: ${options.duration}`) : '';
|
||||
opts += options.easingFn ? indentedLine('easingFn') : '';
|
||||
opts += options.useGrouping ? '' : indentedLine(`useGrouping: ${options.useGrouping}`);
|
||||
opts += options.useIndianSeparators ? indentedLine(`useIndianSeparators: ${options.useIndianSeparators}`) : '';
|
||||
opts += (options.separator !== ',') ? indentedLine(`separator: '${options.separator}'`) : '';
|
||||
opts += (options.decimal !== '.') ? indentedLine(`decimal: '${options.decimal}'`) : '';
|
||||
opts += options.prefix.length ? indentedLine(`prefix: '${options.prefix}'`) : '';
|
||||
opts += (options.numerals && options.numerals.length) ?
|
||||
indentedLine(`numerals: ${stringifyArray(options.numerals)}`) : '';
|
||||
opts += options.onCompleteCallback ? indentedLine('onCompleteCallback: methodToCallOnComplete') : '';
|
||||
|
||||
if (opts.length) {
|
||||
code += `const options = {<br>${opts}};<br>`;
|
||||
code += `const demo = new CountUp('myTargetElement', ${endVal}, options);<br>`;
|
||||
} else {
|
||||
code += `const demo = new CountUp('myTargetElement', ${endVal});<br>`;
|
||||
}
|
||||
code += 'if (!demo.error) {<br>';
|
||||
code += indentedLine('demo.start()', true);
|
||||
code += '} else {<br>';
|
||||
code += indentedLine('console.error(demo.error)', true);
|
||||
code += '}';
|
||||
codeVisualizer.innerHTML = code;
|
||||
}
|
||||
|
||||
// auto animate options
|
||||
function getAutoAnimateOptions() {
|
||||
return {
|
||||
autoAnimate: true,
|
||||
autoAnimateOnce: el('autoAnimateOnce').checked,
|
||||
autoAnimateDelay: Number(el('autoAnimateDelay').value),
|
||||
onCompleteCallback: null,
|
||||
};
|
||||
}
|
||||
|
||||
function recreateAutoAnimateDemos() {
|
||||
createScrollSpyCountUp();
|
||||
createHiddenAtInitCountUp();
|
||||
createInsideModalCountUp();
|
||||
}
|
||||
|
||||
el('autoAnimateOnce').addEventListener('change', recreateAutoAnimateDemos);
|
||||
el('autoAnimateDelay').addEventListener('change', recreateAutoAnimateDemos);
|
||||
|
||||
// scroll spy
|
||||
function createScrollSpyCountUp() {
|
||||
if (scrollSpyCountUp) scrollSpyCountUp.onDestroy();
|
||||
establishOptionsFromInputs();
|
||||
const scrollSpyOptions = { ...options, ...getAutoAnimateOptions() };
|
||||
scrollSpyCountUp = new CountUp('scrollSpyTarget', endVal, scrollSpyOptions);
|
||||
if (scrollSpyCountUp.error) {
|
||||
console.error('scrollSpyCountUp error:', scrollSpyCountUp.error);
|
||||
}
|
||||
}
|
||||
createScrollSpyCountUp();
|
||||
el('apply').addEventListener('click', createScrollSpyCountUp);
|
||||
el('start').addEventListener('click', createScrollSpyCountUp);
|
||||
|
||||
// hidden at init
|
||||
function createHiddenAtInitCountUp() {
|
||||
if (hiddenAtInitCountUp) hiddenAtInitCountUp.onDestroy();
|
||||
establishOptionsFromInputs();
|
||||
const hiddenOptions = { ...options, ...getAutoAnimateOptions() };
|
||||
hiddenAtInitCountUp = new CountUp('hiddenAtInitTarget', endVal, hiddenOptions);
|
||||
if (hiddenAtInitCountUp.error) {
|
||||
console.error('hiddenAtInitCountUp error:', hiddenAtInitCountUp.error);
|
||||
}
|
||||
}
|
||||
createHiddenAtInitCountUp();
|
||||
el('apply').addEventListener('click', createHiddenAtInitCountUp);
|
||||
el('start').addEventListener('click', createHiddenAtInitCountUp);
|
||||
|
||||
el('toggleVisibility').addEventListener('click', () => {
|
||||
const target = el('hiddenAtInitTarget');
|
||||
target.style.display = target.style.display === 'none' ? '' : 'none';
|
||||
});
|
||||
|
||||
// inside modal
|
||||
function createInsideModalCountUp() {
|
||||
if (insideModalCountUp) insideModalCountUp.onDestroy();
|
||||
establishOptionsFromInputs();
|
||||
const modalOptions = { ...options, ...getAutoAnimateOptions() };
|
||||
insideModalCountUp = new CountUp('modalTarget', endVal, modalOptions);
|
||||
if (insideModalCountUp.error) {
|
||||
console.error('insideModalCountUp error:', insideModalCountUp.error);
|
||||
}
|
||||
}
|
||||
createInsideModalCountUp();
|
||||
el('apply').addEventListener('click', createInsideModalCountUp);
|
||||
el('start').addEventListener('click', createInsideModalCountUp);
|
||||
|
||||
el('openModal').addEventListener('click', () => el('modalDialog').showModal());
|
||||
el('closeModal').addEventListener('click', () => el('modalDialog').close());
|
||||
|
||||
// get current star count
|
||||
try {
|
||||
const response = await fetch('https://api.github.com/repos/inorganik/CountUp.js');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
stars = data.stargazers_count;
|
||||
el('endVal').value = stars;
|
||||
createCountUp();
|
||||
createScrollSpyCountUp();
|
||||
createHiddenAtInitCountUp();
|
||||
createInsideModalCountUp();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('error getting stars:', error);
|
||||
demo.start();
|
||||
}
|
||||
BIN
storage/public/dist/libs/countup.js/demo/images/odometer_plugin.gif
vendored
Normal file
BIN
storage/public/dist/libs/countup.js/demo/images/odometer_plugin.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
129
storage/public/dist/libs/countup.js/dist/countUp.d.ts
vendored
Normal file
129
storage/public/dist/libs/countup.js/dist/countUp.d.ts
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
export interface CountUpOptions {
|
||||
/** Number to start at @default 0 */
|
||||
startVal?: number;
|
||||
/** Number of decimal places @default 0 */
|
||||
decimalPlaces?: number;
|
||||
/** Animation duration in seconds @default 2 */
|
||||
duration?: number;
|
||||
/** Example: 1,000 vs 1000 @default true */
|
||||
useGrouping?: boolean;
|
||||
/** Example: 1,00,000 vs 100,000 @default false */
|
||||
useIndianSeparators?: boolean;
|
||||
/** Ease animation @default true */
|
||||
useEasing?: boolean;
|
||||
/** Smooth easing for large numbers above this if useEasing @default 999 */
|
||||
smartEasingThreshold?: number;
|
||||
/** Amount to be eased for numbers above threshold @default 333 */
|
||||
smartEasingAmount?: number;
|
||||
/** Grouping separator @default ',' */
|
||||
separator?: string;
|
||||
/** Decimal character @default '.' */
|
||||
decimal?: string;
|
||||
/** Easing function for animation @default easeOutExpo */
|
||||
easingFn?: (t: number, b: number, c: number, d: number) => number;
|
||||
/** Custom function to format the result */
|
||||
formattingFn?: (n: number) => string;
|
||||
/** Text prepended to result */
|
||||
prefix?: string;
|
||||
/** Text appended to result */
|
||||
suffix?: string;
|
||||
/** Numeral glyph substitution */
|
||||
numerals?: string[];
|
||||
/** Callback called when animation completes */
|
||||
onCompleteCallback?: () => any;
|
||||
/** Callback called when animation starts */
|
||||
onStartCallback?: () => any;
|
||||
/** Plugin for alternate animations */
|
||||
plugin?: CountUpPlugin;
|
||||
/** Trigger animation when target becomes visible @default false */
|
||||
autoAnimate?: boolean;
|
||||
/** Animation delay in ms after auto-animate triggers @default 200 */
|
||||
autoAnimateDelay?: number;
|
||||
/** Run animation only once for auto-animate triggers @default false */
|
||||
autoAnimateOnce?: boolean;
|
||||
/** @deprecated Please use autoAnimate instead */
|
||||
enableScrollSpy?: boolean;
|
||||
/** @deprecated Please use autoAnimateDelay instead */
|
||||
scrollSpyDelay?: number;
|
||||
/** @deprecated Please use autoAnimateOnce instead */
|
||||
scrollSpyOnce?: boolean;
|
||||
}
|
||||
export declare interface CountUpPlugin {
|
||||
render(elem: HTMLElement, formatted: string): void;
|
||||
}
|
||||
/**
|
||||
* Animates a number by counting to it.
|
||||
* playground: stackblitz.com/edit/countup-typescript
|
||||
*
|
||||
* @param target - id of html element, input, svg text element, or DOM element reference where counting occurs.
|
||||
* @param endVal - the value you want to arrive at.
|
||||
* @param options - optional configuration object for fine-grain control
|
||||
*/
|
||||
export declare class CountUp {
|
||||
private endVal?;
|
||||
options?: CountUpOptions;
|
||||
version: string;
|
||||
private static observedElements;
|
||||
private defaults;
|
||||
private rAF;
|
||||
private autoAnimateTimeout;
|
||||
private startTime;
|
||||
private remaining;
|
||||
private finalEndVal;
|
||||
private useEasing;
|
||||
private countDown;
|
||||
private observer;
|
||||
el: HTMLElement | HTMLInputElement;
|
||||
formattingFn: (num: number) => string;
|
||||
easingFn?: (t: number, b: number, c: number, d: number) => number;
|
||||
error: string;
|
||||
startVal: number;
|
||||
duration: number;
|
||||
paused: boolean;
|
||||
frameVal: number;
|
||||
once: boolean;
|
||||
constructor(target: string | HTMLElement | HTMLInputElement, endVal?: number | null, options?: CountUpOptions);
|
||||
/** Set up an IntersectionObserver to auto-animate when the target element appears. */
|
||||
private setupObserver;
|
||||
/** Disconnect the IntersectionObserver and stop watching this element. */
|
||||
unobserve(): void;
|
||||
/** Teardown: cancel animation, disconnect observer, clear callbacks. */
|
||||
onDestroy(): void;
|
||||
/**
|
||||
* Smart easing works by breaking the animation into 2 parts, the second part being the
|
||||
* smartEasingAmount and first part being the total amount minus the smartEasingAmount. It works
|
||||
* by disabling easing for the first part and enabling it on the second part. It is used if
|
||||
* useEasing is true and the total animation amount exceeds the smartEasingThreshold.
|
||||
*/
|
||||
private determineDirectionAndSmartEasing;
|
||||
/** Start the animation. Optionally pass a callback that fires on completion. */
|
||||
start(callback?: (args?: any) => any): void;
|
||||
/** Toggle pause/resume on the animation. */
|
||||
pauseResume(): void;
|
||||
/** Reset to startVal so the animation can be run again. */
|
||||
reset(): void;
|
||||
/** Pass a new endVal and start the animation. */
|
||||
update(newEndVal: string | number): void;
|
||||
/** Animation frame callback — advances the value each frame. */
|
||||
count: (timestamp: number) => void;
|
||||
/** Format and render the given value to the target element. */
|
||||
printValue(val: number): void;
|
||||
/** Return true if the value is a finite number. */
|
||||
ensureNumber(n: any): boolean;
|
||||
/** Validate and convert a value to a number, setting an error if invalid. */
|
||||
validateValue(value: string | number): number;
|
||||
/** Reset startTime, duration, and remaining to their initial values. */
|
||||
private resetDuration;
|
||||
/** Default number formatter with grouping, decimals, prefix/suffix, and numeral substitution. */
|
||||
formatNumber: (num: number) => string;
|
||||
/**
|
||||
* Default easing function (easeOutExpo).
|
||||
* @param t current time
|
||||
* @param b beginning value
|
||||
* @param c change in value
|
||||
* @param d duration
|
||||
*/
|
||||
easeOutExpo: (t: number, b: number, c: number, d: number) => number;
|
||||
/** Parse a formatted string back to a number using the current separator/decimal options. */
|
||||
parse(number: string): number;
|
||||
}
|
||||
364
storage/public/dist/libs/countup.js/dist/countUp.js
vendored
Normal file
364
storage/public/dist/libs/countup.js/dist/countUp.js
vendored
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
/**
|
||||
* Animates a number by counting to it.
|
||||
* playground: stackblitz.com/edit/countup-typescript
|
||||
*
|
||||
* @param target - id of html element, input, svg text element, or DOM element reference where counting occurs.
|
||||
* @param endVal - the value you want to arrive at.
|
||||
* @param options - optional configuration object for fine-grain control
|
||||
*/
|
||||
var CountUp = /** @class */ (function () {
|
||||
function CountUp(target, endVal, options) {
|
||||
var _this = this;
|
||||
this.endVal = endVal;
|
||||
this.options = options;
|
||||
this.version = '2.10.0';
|
||||
this.defaults = {
|
||||
startVal: 0,
|
||||
decimalPlaces: 0,
|
||||
duration: 2,
|
||||
useEasing: true,
|
||||
useGrouping: true,
|
||||
useIndianSeparators: false,
|
||||
smartEasingThreshold: 999,
|
||||
smartEasingAmount: 333,
|
||||
separator: ',',
|
||||
decimal: '.',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
autoAnimate: false,
|
||||
autoAnimateDelay: 200,
|
||||
autoAnimateOnce: false,
|
||||
};
|
||||
this.finalEndVal = null; // for smart easing
|
||||
this.useEasing = true;
|
||||
this.countDown = false;
|
||||
this.error = '';
|
||||
this.startVal = 0;
|
||||
this.paused = true;
|
||||
this.once = false;
|
||||
/** Animation frame callback — advances the value each frame. */
|
||||
this.count = function (timestamp) {
|
||||
if (!_this.startTime) {
|
||||
_this.startTime = timestamp;
|
||||
}
|
||||
var progress = timestamp - _this.startTime;
|
||||
_this.remaining = _this.duration - progress;
|
||||
// to ease or not to ease
|
||||
if (_this.useEasing) {
|
||||
if (_this.countDown) {
|
||||
_this.frameVal = _this.startVal - _this.easingFn(progress, 0, _this.startVal - _this.endVal, _this.duration);
|
||||
}
|
||||
else {
|
||||
_this.frameVal = _this.easingFn(progress, _this.startVal, _this.endVal - _this.startVal, _this.duration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_this.frameVal = _this.startVal + (_this.endVal - _this.startVal) * (progress / _this.duration);
|
||||
}
|
||||
// don't go past endVal since progress can exceed duration in the last frame
|
||||
var wentPast = _this.countDown ? _this.frameVal < _this.endVal : _this.frameVal > _this.endVal;
|
||||
_this.frameVal = wentPast ? _this.endVal : _this.frameVal;
|
||||
// decimal
|
||||
_this.frameVal = Number(_this.frameVal.toFixed(_this.options.decimalPlaces));
|
||||
// format and print value
|
||||
_this.printValue(_this.frameVal);
|
||||
// whether to continue
|
||||
if (progress < _this.duration) {
|
||||
_this.rAF = requestAnimationFrame(_this.count);
|
||||
}
|
||||
else if (_this.finalEndVal !== null) {
|
||||
// smart easing
|
||||
_this.update(_this.finalEndVal);
|
||||
}
|
||||
else {
|
||||
if (_this.options.onCompleteCallback) {
|
||||
_this.options.onCompleteCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
/** Default number formatter with grouping, decimals, prefix/suffix, and numeral substitution. */
|
||||
this.formatNumber = function (num) {
|
||||
var neg = (num < 0) ? '-' : '';
|
||||
var result, x1, x2, x3;
|
||||
result = Math.abs(num).toFixed(_this.options.decimalPlaces);
|
||||
result += '';
|
||||
var x = result.split('.');
|
||||
x1 = x[0];
|
||||
x2 = x.length > 1 ? _this.options.decimal + x[1] : '';
|
||||
if (_this.options.useGrouping) {
|
||||
x3 = '';
|
||||
var factor = 3, j = 0;
|
||||
for (var i = 0, len = x1.length; i < len; ++i) {
|
||||
if (_this.options.useIndianSeparators && i === 4) {
|
||||
factor = 2;
|
||||
j = 1;
|
||||
}
|
||||
if (i !== 0 && (j % factor) === 0) {
|
||||
x3 = _this.options.separator + x3;
|
||||
}
|
||||
j++;
|
||||
x3 = x1[len - i - 1] + x3;
|
||||
}
|
||||
x1 = x3;
|
||||
}
|
||||
// optional numeral substitution
|
||||
if (_this.options.numerals && _this.options.numerals.length) {
|
||||
x1 = x1.replace(/[0-9]/g, function (w) { return _this.options.numerals[+w]; });
|
||||
x2 = x2.replace(/[0-9]/g, function (w) { return _this.options.numerals[+w]; });
|
||||
}
|
||||
return neg + _this.options.prefix + x1 + x2 + _this.options.suffix;
|
||||
};
|
||||
/**
|
||||
* Default easing function (easeOutExpo).
|
||||
* @param t current time
|
||||
* @param b beginning value
|
||||
* @param c change in value
|
||||
* @param d duration
|
||||
*/
|
||||
this.easeOutExpo = function (t, b, c, d) {
|
||||
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
|
||||
};
|
||||
this.options = __assign(__assign({}, this.defaults), options);
|
||||
if (this.options.enableScrollSpy) {
|
||||
this.options.autoAnimate = true;
|
||||
}
|
||||
if (this.options.scrollSpyDelay !== undefined) {
|
||||
this.options.autoAnimateDelay = this.options.scrollSpyDelay;
|
||||
}
|
||||
if (this.options.scrollSpyOnce) {
|
||||
this.options.autoAnimateOnce = true;
|
||||
}
|
||||
this.formattingFn = (this.options.formattingFn) ?
|
||||
this.options.formattingFn : this.formatNumber;
|
||||
this.easingFn = (this.options.easingFn) ?
|
||||
this.options.easingFn : this.easeOutExpo;
|
||||
this.el = (typeof target === 'string') ? document.getElementById(target) : target;
|
||||
endVal = endVal == null ? this.parse(this.el.innerHTML) : endVal;
|
||||
this.startVal = this.validateValue(this.options.startVal);
|
||||
this.frameVal = this.startVal;
|
||||
this.endVal = this.validateValue(endVal);
|
||||
this.options.decimalPlaces = Math.max(0 || this.options.decimalPlaces);
|
||||
this.resetDuration();
|
||||
this.options.separator = String(this.options.separator);
|
||||
this.useEasing = this.options.useEasing;
|
||||
if (this.options.separator === '') {
|
||||
this.options.useGrouping = false;
|
||||
}
|
||||
if (this.el) {
|
||||
this.printValue(this.startVal);
|
||||
}
|
||||
else {
|
||||
this.error = '[CountUp] target is null or undefined';
|
||||
}
|
||||
if (typeof window !== 'undefined' && this.options.autoAnimate) {
|
||||
if (!this.error && typeof IntersectionObserver !== 'undefined') {
|
||||
this.setupObserver();
|
||||
}
|
||||
else {
|
||||
if (this.error) {
|
||||
console.error(this.error, target);
|
||||
}
|
||||
else {
|
||||
console.error('IntersectionObserver is not supported by this browser');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Set up an IntersectionObserver to auto-animate when the target element appears. */
|
||||
CountUp.prototype.setupObserver = function () {
|
||||
var _this = this;
|
||||
var existing = CountUp.observedElements.get(this.el);
|
||||
if (existing) {
|
||||
existing.unobserve();
|
||||
}
|
||||
CountUp.observedElements.set(this.el, this);
|
||||
this.observer = new IntersectionObserver(function (entries) {
|
||||
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
|
||||
var entry = entries_1[_i];
|
||||
if (entry.isIntersecting && _this.paused && !_this.once) {
|
||||
_this.paused = false;
|
||||
_this.autoAnimateTimeout = setTimeout(function () { return _this.start(); }, _this.options.autoAnimateDelay);
|
||||
if (_this.options.autoAnimateOnce) {
|
||||
_this.once = true;
|
||||
_this.observer.disconnect();
|
||||
}
|
||||
}
|
||||
else if (!entry.isIntersecting && !_this.paused) {
|
||||
clearTimeout(_this.autoAnimateTimeout);
|
||||
_this.reset();
|
||||
}
|
||||
}
|
||||
}, { threshold: 0 });
|
||||
this.observer.observe(this.el);
|
||||
};
|
||||
/** Disconnect the IntersectionObserver and stop watching this element. */
|
||||
CountUp.prototype.unobserve = function () {
|
||||
var _a;
|
||||
clearTimeout(this.autoAnimateTimeout);
|
||||
(_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
|
||||
CountUp.observedElements.delete(this.el);
|
||||
};
|
||||
/** Teardown: cancel animation, disconnect observer, clear callbacks. */
|
||||
CountUp.prototype.onDestroy = function () {
|
||||
clearTimeout(this.autoAnimateTimeout);
|
||||
cancelAnimationFrame(this.rAF);
|
||||
this.paused = true;
|
||||
this.unobserve();
|
||||
this.options.onCompleteCallback = null;
|
||||
this.options.onStartCallback = null;
|
||||
};
|
||||
/**
|
||||
* Smart easing works by breaking the animation into 2 parts, the second part being the
|
||||
* smartEasingAmount and first part being the total amount minus the smartEasingAmount. It works
|
||||
* by disabling easing for the first part and enabling it on the second part. It is used if
|
||||
* useEasing is true and the total animation amount exceeds the smartEasingThreshold.
|
||||
*/
|
||||
CountUp.prototype.determineDirectionAndSmartEasing = function () {
|
||||
var end = (this.finalEndVal) ? this.finalEndVal : this.endVal;
|
||||
this.countDown = (this.startVal > end);
|
||||
var animateAmount = end - this.startVal;
|
||||
if (Math.abs(animateAmount) > this.options.smartEasingThreshold && this.options.useEasing) {
|
||||
this.finalEndVal = end;
|
||||
var up = (this.countDown) ? 1 : -1;
|
||||
this.endVal = end + (up * this.options.smartEasingAmount);
|
||||
this.duration = this.duration / 2;
|
||||
}
|
||||
else {
|
||||
this.endVal = end;
|
||||
this.finalEndVal = null;
|
||||
}
|
||||
if (this.finalEndVal !== null) {
|
||||
// setting finalEndVal indicates smart easing
|
||||
this.useEasing = false;
|
||||
}
|
||||
else {
|
||||
this.useEasing = this.options.useEasing;
|
||||
}
|
||||
};
|
||||
/** Start the animation. Optionally pass a callback that fires on completion. */
|
||||
CountUp.prototype.start = function (callback) {
|
||||
if (this.error) {
|
||||
return;
|
||||
}
|
||||
if (this.options.onStartCallback) {
|
||||
this.options.onStartCallback();
|
||||
}
|
||||
if (callback) {
|
||||
this.options.onCompleteCallback = callback;
|
||||
}
|
||||
if (this.duration > 0) {
|
||||
this.determineDirectionAndSmartEasing();
|
||||
this.paused = false;
|
||||
this.rAF = requestAnimationFrame(this.count);
|
||||
}
|
||||
else {
|
||||
this.printValue(this.endVal);
|
||||
}
|
||||
};
|
||||
/** Toggle pause/resume on the animation. */
|
||||
CountUp.prototype.pauseResume = function () {
|
||||
if (!this.paused) {
|
||||
cancelAnimationFrame(this.rAF);
|
||||
}
|
||||
else {
|
||||
this.startTime = null;
|
||||
this.duration = this.remaining;
|
||||
this.startVal = this.frameVal;
|
||||
this.determineDirectionAndSmartEasing();
|
||||
this.rAF = requestAnimationFrame(this.count);
|
||||
}
|
||||
this.paused = !this.paused;
|
||||
};
|
||||
/** Reset to startVal so the animation can be run again. */
|
||||
CountUp.prototype.reset = function () {
|
||||
clearTimeout(this.autoAnimateTimeout);
|
||||
cancelAnimationFrame(this.rAF);
|
||||
this.paused = true;
|
||||
this.once = false;
|
||||
this.resetDuration();
|
||||
this.startVal = this.validateValue(this.options.startVal);
|
||||
this.frameVal = this.startVal;
|
||||
this.printValue(this.startVal);
|
||||
};
|
||||
/** Pass a new endVal and start the animation. */
|
||||
CountUp.prototype.update = function (newEndVal) {
|
||||
cancelAnimationFrame(this.rAF);
|
||||
this.startTime = null;
|
||||
this.endVal = this.validateValue(newEndVal);
|
||||
if (this.endVal === this.frameVal) {
|
||||
return;
|
||||
}
|
||||
this.startVal = this.frameVal;
|
||||
if (this.finalEndVal == null) {
|
||||
this.resetDuration();
|
||||
}
|
||||
this.finalEndVal = null;
|
||||
this.determineDirectionAndSmartEasing();
|
||||
this.rAF = requestAnimationFrame(this.count);
|
||||
};
|
||||
/** Format and render the given value to the target element. */
|
||||
CountUp.prototype.printValue = function (val) {
|
||||
var _a;
|
||||
if (!this.el)
|
||||
return;
|
||||
var result = this.formattingFn(val);
|
||||
if ((_a = this.options.plugin) === null || _a === void 0 ? void 0 : _a.render) {
|
||||
this.options.plugin.render(this.el, result);
|
||||
return;
|
||||
}
|
||||
if (this.el.tagName === 'INPUT') {
|
||||
var input = this.el;
|
||||
input.value = result;
|
||||
}
|
||||
else if (this.el.tagName === 'text' || this.el.tagName === 'tspan') {
|
||||
this.el.textContent = result;
|
||||
}
|
||||
else {
|
||||
this.el.innerHTML = result;
|
||||
}
|
||||
};
|
||||
/** Return true if the value is a finite number. */
|
||||
CountUp.prototype.ensureNumber = function (n) {
|
||||
return (typeof n === 'number' && !isNaN(n));
|
||||
};
|
||||
/** Validate and convert a value to a number, setting an error if invalid. */
|
||||
CountUp.prototype.validateValue = function (value) {
|
||||
var newValue = Number(value);
|
||||
if (!this.ensureNumber(newValue)) {
|
||||
this.error = "[CountUp] invalid start or end value: ".concat(value);
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
/** Reset startTime, duration, and remaining to their initial values. */
|
||||
CountUp.prototype.resetDuration = function () {
|
||||
this.startTime = null;
|
||||
this.duration = Number(this.options.duration) * 1000;
|
||||
this.remaining = this.duration;
|
||||
};
|
||||
/** Parse a formatted string back to a number using the current separator/decimal options. */
|
||||
CountUp.prototype.parse = function (number) {
|
||||
// eslint-disable-next-line no-irregular-whitespace
|
||||
var escapeRegExp = function (s) { return s.replace(/([.,' ])/g, '\\$1'); };
|
||||
var sep = escapeRegExp(this.options.separator);
|
||||
var dec = escapeRegExp(this.options.decimal);
|
||||
var num = number.replace(new RegExp(sep, 'g'), '').replace(new RegExp(dec, 'g'), '.');
|
||||
return parseFloat(num);
|
||||
};
|
||||
CountUp.observedElements = new WeakMap();
|
||||
return CountUp;
|
||||
}());
|
||||
export { CountUp };
|
||||
1
storage/public/dist/libs/countup.js/dist/countUp.min.js
vendored
Normal file
1
storage/public/dist/libs/countup.js/dist/countUp.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
storage/public/dist/libs/countup.js/dist/countUp.umd.js
vendored
Normal file
1
storage/public/dist/libs/countup.js/dist/countUp.umd.js
vendored
Normal file
File diff suppressed because one or more lines are too long
26
storage/public/dist/libs/countup.js/dist/requestAnimationFrame.polyfill.js
vendored
Normal file
26
storage/public/dist/libs/countup.js/dist/requestAnimationFrame.polyfill.js
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// make sure requestAnimationFrame and cancelAnimationFrame are defined
|
||||
// polyfill for browsers without native support
|
||||
// by Opera engineer Erik Möller
|
||||
(function () {
|
||||
var lastTime = 0;
|
||||
var vendors = ['webkit', 'moz', 'ms', 'o'];
|
||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
|
||||
window[vendors[x] + 'CancelRequestAnimationFrame'];
|
||||
}
|
||||
if (!window.requestAnimationFrame) {
|
||||
window.requestAnimationFrame = function (callback) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function () { return callback(currTime + timeToCall); }, timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
}
|
||||
if (!window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame = function (id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}
|
||||
})();
|
||||
199
storage/public/dist/libs/countup.js/index.html
vendored
Normal file
199
storage/public/dist/libs/countup.js/index.html
vendored
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="robots" content="index,follow">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<meta name="description" content="A javascript class that animates a numerical value by counting to it.">
|
||||
|
||||
<title>CountUp.js</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="https://inorganik.github.io/assets/css/style.css">
|
||||
<style>
|
||||
h1.jumbo {
|
||||
line-height: 200px;
|
||||
}
|
||||
.dot-matrix {
|
||||
background-image:radial-gradient(circle, #898989 1px, transparent 1px);
|
||||
background-size:1em 1em;
|
||||
}
|
||||
[type="button"].indigo {
|
||||
background-color: #4d63bc ;
|
||||
color: #fff;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
[type="button"].indigo {
|
||||
background-color: #6e90da;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="demo/demo.js" type="module"></script>
|
||||
<script nomodule src="dist/countUp.umd.js"></script>
|
||||
<script nomodule src="demo/demo-nomodule.js"></script>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-QXSCCPQ13N"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-QXSCCPQ13N');
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a class="forkMe" href="https://github.com/inorganik/CountUp.js"><img src="https://inorganik.github.io/assets/img/forkme_custom_indigo.png" alt="Fork me on GitHub"></a>
|
||||
<div id="wrap">
|
||||
<header>
|
||||
<div id="github"><a class="block" href="https://inorganik.github.io"></a></div>
|
||||
<div class="leaderLine">////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////</div>
|
||||
<div id="logo"><a class="block" href="https://inorganik.net" alt="inorganik produce, inc"></a></div>
|
||||
</header>
|
||||
<section>
|
||||
<div class="col full">
|
||||
<h1>CountUp.js <small id="version" class="lt-gray"></small></h1>
|
||||
</div>
|
||||
<div class="col full">
|
||||
<p>CountUp.js is a dependency-free, lightweight JavaScript class that animates a numerical value by counting to it.</p>
|
||||
<p>Install via npm/yarn using the package name <code class="indigo large">countup.js</code>.</p>
|
||||
<h3 class="marginTop marginBottom"><a class="lime weight700" href="https://github.com/inorganik/CountUp.js">View on GitHub</a></h3>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<p style="position:absolute; top:5px; left:0;">Current stars:</p>
|
||||
<h1 class="jumbo" id="myTargetElement">0</h1>
|
||||
</section>
|
||||
<section id="errorSection" style="background-color:#FFDCDC; display:none" class="col-inner">
|
||||
<h4 id="error" style="color: red" class="noMargin"></h4>
|
||||
</section>
|
||||
<section id="paramsSection">
|
||||
<form>
|
||||
<h4 class="inlineLeft noMargin weight300">Params:</h4>
|
||||
<div class="inlineLeft marginLeft marginRight">
|
||||
<input type="text" value="0" id="startVal" style="width:80px" class="updateCodeVis">
|
||||
<label class="inlineLabel">Start</label>
|
||||
</div>
|
||||
<input id="swapValues" type="button" class="inlineLeft marginRight" value="Swap" style="width:80px;">
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="text" value="94.62" id="endVal" style="width:80px" class="updateCodeVis">
|
||||
<label class="inlineLabel">End</label>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="number" value="0" id="decimalPlaces" step="1" style="width:50px" class="updateCodeVis">
|
||||
<label class="inlineLabel">Decimal places</label>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="number" value="2" id="duration" step=".1" style="width:50px" class="updateCodeVis">
|
||||
<label class="inlineLabel">Duration</label>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<section id="optionsSection">
|
||||
<form>
|
||||
<h4 class="inlineLeft noMargin weight300">Options:</h4>
|
||||
<div class="inlineLeft marginLeft marginRight">
|
||||
<input id="useGrouping" type="checkbox" checked><label class="inlineLabel updateCodeVis">Use grouping</label>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<input id="useIndianSeparators" type="checkbox"><label class="inlineLabel updateCodeVis">Use Indian separators</label>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="text" value="," id="separator" style="width:25px; padding:0 5px;" class="updateCodeVis">
|
||||
<label class="inlineLabel">Separator</label>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="text" value="." id="decimal" style="width:25px; padding:0 5px;" class="updateCodeVis">
|
||||
<label class="inlineLabel">Decimal</label>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="text" value="" id="prefix" style="width:50px; padding:0 5px;" class="updateCodeVis">
|
||||
<label class="inlineLabel">Prefix</label>
|
||||
</div>
|
||||
<h4 class="inlineLeft noMargin weight300">+ many more</h4>
|
||||
</form>
|
||||
</section>
|
||||
<section id="methodsSection">
|
||||
<form>
|
||||
<h4 class="inlineLeft noMargin weight300">Methods:</h4>
|
||||
<input type="button" value="Start" id="start" class="inlineLeft marginLeft marginRight indigo">
|
||||
<input type="button" value="Pause/Resume" id="pauseResume" class="inlineLeft marginRight">
|
||||
<input type="button" value="Reset" id="reset" class="inlineLeft marginRight">
|
||||
<input type="button" value="Update:" id="update" class="inlineLeft" style="margin-right:5px">
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="text" value="6789" id="updateVal" style="width:80px">
|
||||
</div>
|
||||
<div class="inlineLeft">
|
||||
<input type="checkbox" id="useOnComplete" class="updateCodeVis"><label class="inlineLabel">Alert on complete</label>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<section id="easingSection">
|
||||
<form>
|
||||
<h4 class="inlineLeft noMargin weight300">Custom:</h4>
|
||||
<div class="inlineLeft marginLeft">
|
||||
<label class="inlineLabel">Easing: </label>
|
||||
<select id="easingFnsDropdown" class="marginRight updateCodeVis">
|
||||
<option value="easeOutExpo" selected>easeOutExpo (default, built-in)</option>
|
||||
<option value="outQuintic">outQuintic</option>
|
||||
<option value="outCubic">outCubic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<label class="inlineLabel">Numerals: </label>
|
||||
<select id="numeralsDropdown" class="updateCodeVis">
|
||||
<option value="" selected>Default ("1234")</option>
|
||||
<option value="ea">Eastern Arabic ("١٢٣٤")</option>
|
||||
<option value="fa">Farsi ("۱۲۳۴")</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="inlineLeft">
|
||||
<input type="button" id="apply" value="Apply">
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<section id="codeVisualizerSection">
|
||||
<div class="col full marginBottom marginTop">
|
||||
<div class="code-contain indigo">
|
||||
<code id="codeVisualizer" class="indigo"></code>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="scrollSpySection">
|
||||
<form>
|
||||
<h3 class="inlineLeft noMargin">Auto animate demos (scroll down)</h3>
|
||||
<div class="inlineLeft marginLeft marginRight">
|
||||
<input id="autoAnimateOnce" type="checkbox"><label class="inlineLabel">Once</label>
|
||||
</div>
|
||||
<div class="inlineLeft marginRight">
|
||||
<input type="number" value="0" id="autoAnimateDelay" step="100" min="0" style="width:70px">
|
||||
<label class="inlineLabel">Delay (ms)</label>
|
||||
</div>
|
||||
</form>
|
||||
<p>Use the <code class="indigo">autoAnimate</code> option to animate when the target element appears.</p>
|
||||
<div class="dot-matrix" style="height:60vh;"></div>
|
||||
<h1 class="jumbo" id="scrollSpyTarget">0</h1>
|
||||
<div class="dot-matrix" style="height:20vh;"></div>
|
||||
</section>
|
||||
<section id="hiddenAtInitSection" style="padding-top:20px;">
|
||||
<h3>Hidden at init</h3>
|
||||
<p><input type="button" value="Toggle visibility" id="toggleVisibility"></p>
|
||||
<div style="height: 200px;">
|
||||
<h1 class="jumbo" id="hiddenAtInitTarget" style="display:none;">0</h1>
|
||||
</div>
|
||||
</section>
|
||||
<section id="modalSection" style="padding-top:20px;" class="marginBottom">
|
||||
<h3>Inside a modal</h3>
|
||||
<p><input type="button" value="Open modal" id="openModal"></p>
|
||||
<dialog id="modalDialog" style="width: 650px; padding:40px 60px; border:1px solid #ccc; border-radius:16px; box-shadow:0 4px 24px rgba(0,0,0,.2); text-align:center;">
|
||||
<h1 class="jumbo" id="modalTarget">0</h1>
|
||||
<p><input type="button" value="Close" id="closeModal"></p>
|
||||
</dialog>
|
||||
<div class="dot-matrix" style="height:20vh"></div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
17
storage/public/dist/libs/countup.js/jest.config.js
vendored
Normal file
17
storage/public/dist/libs/countup.js/jest.config.js
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
module.exports = {
|
||||
roots: [
|
||||
'<rootDir>/src'
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.ts?$': 'ts-jest'
|
||||
},
|
||||
testRegex: '(\\.|/)(test|spec)\\.ts?$',
|
||||
testEnvironment: 'jsdom',
|
||||
moduleFileExtensions: [
|
||||
'ts',
|
||||
'js',
|
||||
'jsx',
|
||||
'json',
|
||||
'node'
|
||||
]
|
||||
}
|
||||
44
storage/public/dist/libs/countup.js/package.json
vendored
Normal file
44
storage/public/dist/libs/countup.js/package.json
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "countup.js",
|
||||
"description": "Animates a numerical value by counting to it",
|
||||
"version": "2.10.0",
|
||||
"license": "MIT",
|
||||
"author": "Jamie Perkins",
|
||||
"main": "./dist/countUp.umd.js",
|
||||
"module": "./dist/countUp.min.js",
|
||||
"types": "./dist/countUp.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/inorganik/countUp.js.git"
|
||||
},
|
||||
"exports": {
|
||||
"types": "./dist/countUp.d.ts",
|
||||
"import": "./dist/countUp.min.js",
|
||||
"require": "./dist/countUp.umd.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run clean && tsc && rollup -c rollup.config.mjs",
|
||||
"clean": "rimraf dist/countUp.*",
|
||||
"lint": "eslint -c .eslintrc.js --ext .ts ./src",
|
||||
"serve": "http-server -o -c-1 ./",
|
||||
"start": "npm run build && npm run serve",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.6.0",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@types/eslint__js": "^8.42.3",
|
||||
"@types/jest": "^29.5.12",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"http-server": "^14.1.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"rimraf": "^5.0.9",
|
||||
"rollup": "^4.18.1",
|
||||
"ts-jest": "^29.2.2",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^7.16.0"
|
||||
}
|
||||
}
|
||||
33
storage/public/dist/libs/countup.js/rollup.config.mjs
vendored
Normal file
33
storage/public/dist/libs/countup.js/rollup.config.mjs
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import terser from '@rollup/plugin-terser';
|
||||
/**
|
||||
* Regarding "(!) `this` has been rewritten to `undefined`" warning:
|
||||
* It occurs because of typescript's Object.assign polyfill, which uses
|
||||
* `this` on the global scope. If you set `context: 'window'` in the rollup
|
||||
* config, it will silence the warning, but it will cause issues if CountUp
|
||||
* is not run in the browser. Allowing rollup to rewrite this to undefined
|
||||
* on just the global scope is harmless and doesn't break anything.
|
||||
*/
|
||||
export default [
|
||||
// minified build
|
||||
{
|
||||
input: 'dist/countUp.js',
|
||||
output: {
|
||||
file: 'dist/countUp.min.js',
|
||||
},
|
||||
plugins: [
|
||||
terser(), // minify the output
|
||||
],
|
||||
},
|
||||
// UMD build
|
||||
{
|
||||
input: 'dist/countUp.js',
|
||||
output: {
|
||||
file: 'dist/countUp.umd.js',
|
||||
name: 'countUp',
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
terser(),
|
||||
],
|
||||
}
|
||||
];
|
||||
591
storage/public/dist/libs/countup.js/src/countUp.spec.ts
vendored
Normal file
591
storage/public/dist/libs/countup.js/src/countUp.spec.ts
vendored
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
import { CountUp, CountUpPlugin } from './countUp';
|
||||
|
||||
type IntersectionCallback = (entries: Partial<IntersectionObserverEntry>[]) => void;
|
||||
|
||||
class MockIntersectionObserver {
|
||||
callback: IntersectionCallback;
|
||||
elements: Element[] = [];
|
||||
static instances: MockIntersectionObserver[] = [];
|
||||
|
||||
constructor(callback: IntersectionCallback) {
|
||||
this.callback = callback;
|
||||
MockIntersectionObserver.instances.push(this);
|
||||
}
|
||||
observe(el: Element) { this.elements.push(el); }
|
||||
unobserve(el: Element) { this.elements = this.elements.filter(e => e !== el); }
|
||||
disconnect() { this.elements = []; }
|
||||
|
||||
trigger(isIntersecting: boolean) {
|
||||
this.callback(this.elements.map(target => ({ isIntersecting, target } as Partial<IntersectionObserverEntry>)));
|
||||
}
|
||||
}
|
||||
|
||||
describe('CountUp', () => {
|
||||
|
||||
let countUp;
|
||||
let time;
|
||||
|
||||
const getTargetHtml = () => document.getElementById('target')?.innerHTML;
|
||||
const resetRAF = () => {
|
||||
time = 0;
|
||||
jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => {
|
||||
time += 100;
|
||||
if (time < 2500) {
|
||||
return cb(time) as any;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML =
|
||||
'<div>' +
|
||||
' <h1 id="target"></h1>' +
|
||||
'</div>';
|
||||
|
||||
(window as any).IntersectionObserver = MockIntersectionObserver;
|
||||
MockIntersectionObserver.instances = [];
|
||||
|
||||
countUp = new CountUp('target', 100);
|
||||
resetRAF();
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
|
||||
it('should create for a valid target, and print startVal', () => {
|
||||
expect(countUp).toBeTruthy();
|
||||
expect(countUp.error.length).toBe(0);
|
||||
expect(getTargetHtml()).toEqual('0');
|
||||
});
|
||||
|
||||
it('should set an error for a bad target', () => {
|
||||
countUp = new CountUp('notThere', 100);
|
||||
|
||||
expect(countUp.error.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should set an error for a bad endVal', () => {
|
||||
const endVal = '%' as any;
|
||||
countUp = new CountUp('target', endVal);
|
||||
|
||||
expect(countUp.error.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should set an error for a bad startVal', () => {
|
||||
const startVal = 'oops' as any;
|
||||
countUp = new CountUp('target', 100, { startVal });
|
||||
|
||||
expect(countUp.error.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should return a value for version', () => {
|
||||
expect(countUp.version).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should support getting endVal from the target element', () => {
|
||||
document.body.innerHTML =
|
||||
'<div>' +
|
||||
' <h1 id="target">1,500</h1>' +
|
||||
'</div>';
|
||||
|
||||
countUp = new CountUp('target');
|
||||
expect(countUp.endVal).toBe(1500);
|
||||
});
|
||||
|
||||
it('should set an error when endVal is omitted and not in target element', () => {
|
||||
document.body.innerHTML =
|
||||
'<div>' +
|
||||
' <h1 id="target"></h1>' +
|
||||
'</div>';
|
||||
countUp = new CountUp('target');
|
||||
expect(countUp.error.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should not call parse when an endVal is passed to the constructor', () => {
|
||||
const parseSpy = jest.spyOn(CountUp.prototype, 'parse');
|
||||
|
||||
countUp = new CountUp('target', 0, { startVal: 100 });
|
||||
expect(parseSpy).not.toHaveBeenCalled();
|
||||
parseSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('class methods', () => {
|
||||
describe('# start', () => {
|
||||
it('should count when start method is called', () => {
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should use a callback provided to start', () => {
|
||||
const cb = jest.fn();
|
||||
countUp.start(cb);
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
expect(cb).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('# pauseResume', () => {
|
||||
it('should pause when pauseResume is called', () => {
|
||||
countUp.start();
|
||||
countUp.pauseResume();
|
||||
|
||||
expect(countUp.paused).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('# reset', () => {
|
||||
it('should reset when reset is called', () => {
|
||||
countUp.start();
|
||||
countUp.reset();
|
||||
|
||||
expect(getTargetHtml()).toEqual('0');
|
||||
expect(countUp.paused).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('# update', () => {
|
||||
it('should update when update is called', () => {
|
||||
countUp.start();
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
|
||||
resetRAF();
|
||||
countUp.update(200);
|
||||
expect(getTargetHtml()).toEqual('200');
|
||||
});
|
||||
});
|
||||
|
||||
describe('# onDestroy', () => {
|
||||
it('should cancel a running animation', () => {
|
||||
const cancelSpy = jest.spyOn(window, 'cancelAnimationFrame');
|
||||
countUp.start();
|
||||
countUp.onDestroy();
|
||||
|
||||
expect(cancelSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set paused to true', () => {
|
||||
countUp.start();
|
||||
expect(countUp.paused).toBe(false);
|
||||
|
||||
countUp.onDestroy();
|
||||
expect(countUp.paused).toBe(true);
|
||||
});
|
||||
|
||||
it('should disconnect the observer', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true });
|
||||
const observer = MockIntersectionObserver.instances[MockIntersectionObserver.instances.length - 1];
|
||||
const disconnectSpy = jest.spyOn(observer, 'disconnect');
|
||||
|
||||
countUp.onDestroy();
|
||||
expect(disconnectSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clear onCompleteCallback', () => {
|
||||
const cb = jest.fn();
|
||||
countUp = new CountUp('target', 100, { onCompleteCallback: cb });
|
||||
|
||||
countUp.onDestroy();
|
||||
expect(countUp.options.onCompleteCallback).toBeNull();
|
||||
});
|
||||
|
||||
it('should clear onStartCallback', () => {
|
||||
const cb = jest.fn();
|
||||
countUp = new CountUp('target', 100, { onStartCallback: cb });
|
||||
|
||||
countUp.onDestroy();
|
||||
expect(countUp.options.onStartCallback).toBeNull();
|
||||
});
|
||||
|
||||
it('should prevent onCompleteCallback from firing after destroy', () => {
|
||||
const cb = jest.fn();
|
||||
countUp = new CountUp('target', 100, { onCompleteCallback: cb });
|
||||
countUp.onDestroy();
|
||||
|
||||
resetRAF();
|
||||
countUp.start();
|
||||
expect(cb).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be safe to call on a fresh instance', () => {
|
||||
countUp = new CountUp('target', 100);
|
||||
expect(() => countUp.onDestroy()).not.toThrow();
|
||||
expect(countUp.paused).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('# parse', () => {
|
||||
it('should properly parse numbers', () => {
|
||||
countUp = new CountUp('target', 0);
|
||||
const result0 = countUp.parse('14,921.00123');
|
||||
|
||||
countUp = new CountUp('target', 0, { separator: '.', decimal: ',' });
|
||||
const result1 = countUp.parse('1.500,0');
|
||||
|
||||
countUp = new CountUp('target', 0, { separator: ' ' });
|
||||
const result2 = countUp.parse('2 800');
|
||||
|
||||
expect(result0).toEqual(14921.00123);
|
||||
expect(result1).toEqual(1500);
|
||||
expect(result2).toEqual(2800);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('various use-cases', () => {
|
||||
it('should handle large numbers', () => {
|
||||
countUp = new CountUp('target', 6000);
|
||||
const spy = jest.spyOn(countUp, 'determineDirectionAndSmartEasing');
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('6,000');
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not use easing when specified with a large number (auto-smooth)', () => {
|
||||
countUp = new CountUp('target', 6000, { useEasing: false });
|
||||
const spy = jest.spyOn(countUp, 'easingFn');
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('6,000');
|
||||
expect(spy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should count down when endVal is less than startVal', () => {
|
||||
countUp = new CountUp('target', 10, { startVal: 500 });
|
||||
expect(getTargetHtml()).toEqual('500');
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('10');
|
||||
});
|
||||
|
||||
it('should handle negative numbers', () => {
|
||||
countUp = new CountUp('target', -500);
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('-500');
|
||||
});
|
||||
|
||||
it('should properly handle a zero duration', () => {
|
||||
countUp = new CountUp('target', 2000, { duration: 0 });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('2,000');
|
||||
});
|
||||
|
||||
it('should call the callback when finished if there is one', () => {
|
||||
const cb = jest.fn();
|
||||
countUp.start(cb);
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
expect(cb).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('options', () => {
|
||||
it('should respect the decimalPlaces option', () => {
|
||||
countUp = new CountUp('target', 100, { decimalPlaces: 2 });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100.00');
|
||||
});
|
||||
|
||||
it('should respect the duration option', () => {
|
||||
countUp = new CountUp('target', 100, { duration: 1 });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should respect the useEasing option', () => {
|
||||
countUp = new CountUp('target', 100, { useEasing: false });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should respect the useGrouping option', () => {
|
||||
countUp = new CountUp('target', 100000, { useGrouping: false });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100000');
|
||||
resetRAF();
|
||||
|
||||
countUp = new CountUp('target', 1000000, { useGrouping: true });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('1,000,000');
|
||||
});
|
||||
|
||||
it('should respect the useIndianSeparators option', () => {
|
||||
countUp = new CountUp('target', 100000, { useIndianSeparators: true });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('1,00,000');
|
||||
resetRAF();
|
||||
|
||||
countUp = new CountUp('target', 10000000, { useIndianSeparators: true });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('1,00,00,000');
|
||||
});
|
||||
|
||||
it('should respect the separator option', () => {
|
||||
countUp = new CountUp('target', 10000, { separator: ':' });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('10:000');
|
||||
});
|
||||
|
||||
it('should respect the decimal option', () => {
|
||||
countUp = new CountUp('target', 100, { decimal: ',', decimalPlaces: 1 });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100,0');
|
||||
});
|
||||
|
||||
it('should respect the easingFn option', () => {
|
||||
const easeOutQuintic = jest.fn().mockReturnValue(100);
|
||||
countUp = new CountUp('target', 100, { easingFn: easeOutQuintic });
|
||||
countUp.start();
|
||||
|
||||
expect(easeOutQuintic).toHaveBeenCalled();
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should respect the formattingFn option', () => {
|
||||
const formatter = jest.fn().mockReturnValue('~100~');
|
||||
countUp = new CountUp('target', 100, { formattingFn: formatter });
|
||||
countUp.start();
|
||||
|
||||
expect(formatter).toHaveBeenCalled();
|
||||
expect(getTargetHtml()).toEqual('~100~');
|
||||
});
|
||||
|
||||
it('should respect the prefix option', () => {
|
||||
countUp = new CountUp('target', 100, { prefix: '$' });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('$100');
|
||||
});
|
||||
|
||||
it('should respect the suffix option', () => {
|
||||
countUp = new CountUp('target', 100, { suffix: '!' });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100!');
|
||||
});
|
||||
|
||||
it('should respect the numerals option', () => {
|
||||
const numerals = [')', '!', '@', '#', '$', '%', '^', '&', '*', '('];
|
||||
countUp = new CountUp('target', 100, { numerals });
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('!))');
|
||||
});
|
||||
|
||||
it('should respect the onCompleteCallback option', () => {
|
||||
const options = { onCompleteCallback: jest.fn() };
|
||||
const callbackSpy = jest.spyOn(options, 'onCompleteCallback');
|
||||
countUp = new CountUp('target', 100, options);
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
expect(callbackSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should respect the onStartCallback option', () => {
|
||||
const options = { onStartCallback: jest.fn() };
|
||||
const callbackSpy = jest.spyOn(options, 'onStartCallback');
|
||||
countUp = new CountUp('target', 100, options);
|
||||
countUp.start();
|
||||
|
||||
expect(callbackSpy).toHaveBeenCalled();
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should respect the plugin option', () => {
|
||||
const plugin: CountUpPlugin = {
|
||||
render: (el, result) => {
|
||||
el.innerHTML = result;
|
||||
}
|
||||
};
|
||||
countUp = new CountUp('target', 1000, {
|
||||
plugin,
|
||||
useGrouping: true
|
||||
});
|
||||
countUp.start();
|
||||
|
||||
expect(getTargetHtml()).toEqual('1,000');
|
||||
});
|
||||
});
|
||||
|
||||
describe('autoAnimate (IntersectionObserver)', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers({ doNotFake: ['requestAnimationFrame'] });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should create an IntersectionObserver when autoAnimate is true', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true });
|
||||
|
||||
expect(MockIntersectionObserver.instances.length).toBe(1);
|
||||
expect(MockIntersectionObserver.instances[0].elements).toContain(countUp.el);
|
||||
});
|
||||
|
||||
it('should not create an observer when autoAnimate is false', () => {
|
||||
MockIntersectionObserver.instances = [];
|
||||
countUp = new CountUp('target', 100);
|
||||
|
||||
expect(MockIntersectionObserver.instances.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should start animation when element becomes visible', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true, autoAnimateDelay: 0 });
|
||||
resetRAF();
|
||||
const observer = MockIntersectionObserver.instances[0];
|
||||
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should respect autoAnimateDelay before starting', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true, autoAnimateDelay: 500 });
|
||||
resetRAF();
|
||||
const startSpy = jest.spyOn(countUp, 'start');
|
||||
const observer = MockIntersectionObserver.instances[0];
|
||||
|
||||
observer.trigger(true);
|
||||
expect(startSpy).not.toHaveBeenCalled();
|
||||
|
||||
jest.advanceTimersByTime(500);
|
||||
expect(startSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reset when element goes out of view', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true, autoAnimateDelay: 0 });
|
||||
resetRAF();
|
||||
const observer = MockIntersectionObserver.instances[0];
|
||||
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
|
||||
observer.trigger(false);
|
||||
expect(countUp.paused).toBe(true);
|
||||
expect(getTargetHtml()).toEqual('0');
|
||||
});
|
||||
|
||||
it('should disconnect observer when autoAnimateOnce is true', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true, autoAnimateOnce: true, autoAnimateDelay: 0 });
|
||||
const observer = MockIntersectionObserver.instances[0];
|
||||
const disconnectSpy = jest.spyOn(observer, 'disconnect');
|
||||
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
|
||||
expect(disconnectSpy).toHaveBeenCalled();
|
||||
expect(countUp.once).toBe(true);
|
||||
});
|
||||
|
||||
it('should not disconnect observer when autoAnimateOnce is false', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true, autoAnimateOnce: false, autoAnimateDelay: 0 });
|
||||
const observer = MockIntersectionObserver.instances[0];
|
||||
const disconnectSpy = jest.spyOn(observer, 'disconnect');
|
||||
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
|
||||
expect(disconnectSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not re-animate after first run when autoAnimateOnce is true', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true, autoAnimateOnce: true, autoAnimateDelay: 0 });
|
||||
resetRAF();
|
||||
const observer = MockIntersectionObserver.instances[MockIntersectionObserver.instances.length - 1];
|
||||
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
|
||||
// observer was disconnected so subsequent triggers process no entries
|
||||
observer.trigger(false);
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should allow re-animation after manual reset when autoAnimateOnce is true', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true, autoAnimateOnce: true, autoAnimateDelay: 0 });
|
||||
resetRAF();
|
||||
const observer = MockIntersectionObserver.instances[MockIntersectionObserver.instances.length - 1];
|
||||
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
expect(countUp.once).toBe(true);
|
||||
|
||||
// manual reset clears the once flag
|
||||
countUp.reset();
|
||||
expect(getTargetHtml()).toEqual('0');
|
||||
expect(countUp.once).toBe(false);
|
||||
|
||||
// re-observe and trigger — animation should play again
|
||||
observer.observe(countUp.el);
|
||||
resetRAF();
|
||||
observer.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
|
||||
expect(getTargetHtml()).toEqual('100');
|
||||
});
|
||||
|
||||
it('should support multiple independent instances', () => {
|
||||
document.body.innerHTML =
|
||||
'<h1 id="target1"></h1>' +
|
||||
'<h1 id="target2"></h1>';
|
||||
MockIntersectionObserver.instances = [];
|
||||
|
||||
const cu1 = new CountUp('target1', 50, { autoAnimate: true, autoAnimateDelay: 0 });
|
||||
const cu2 = new CountUp('target2', 200, { autoAnimate: true, autoAnimateDelay: 0 });
|
||||
|
||||
expect(MockIntersectionObserver.instances.length).toBe(2);
|
||||
|
||||
const obs1 = MockIntersectionObserver.instances[0];
|
||||
const obs2 = MockIntersectionObserver.instances[1];
|
||||
|
||||
expect(obs1.elements).toContain(cu1.el);
|
||||
expect(obs2.elements).toContain(cu2.el);
|
||||
expect(obs1).not.toBe(obs2);
|
||||
|
||||
resetRAF();
|
||||
obs1.trigger(true);
|
||||
jest.advanceTimersByTime(0);
|
||||
expect(document.getElementById('target1')!.innerHTML).toEqual('50');
|
||||
expect(cu2.paused).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow cleanup via unobserve()', () => {
|
||||
countUp = new CountUp('target', 100, { autoAnimate: true });
|
||||
const observer = MockIntersectionObserver.instances[0];
|
||||
const disconnectSpy = jest.spyOn(observer, 'disconnect');
|
||||
|
||||
countUp.unobserve();
|
||||
expect(disconnectSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should map deprecated enableScrollSpy to autoAnimate', () => {
|
||||
countUp = new CountUp('target', 100, { enableScrollSpy: true });
|
||||
expect(countUp.options.autoAnimate).toBe(true);
|
||||
expect(MockIntersectionObserver.instances.length).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
425
storage/public/dist/libs/countup.js/src/countUp.ts
vendored
Normal file
425
storage/public/dist/libs/countup.js/src/countUp.ts
vendored
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
export interface CountUpOptions {
|
||||
/** Number to start at @default 0 */
|
||||
startVal?: number;
|
||||
/** Number of decimal places @default 0 */
|
||||
decimalPlaces?: number;
|
||||
/** Animation duration in seconds @default 2 */
|
||||
duration?: number;
|
||||
/** Example: 1,000 vs 1000 @default true */
|
||||
useGrouping?: boolean;
|
||||
/** Example: 1,00,000 vs 100,000 @default false */
|
||||
useIndianSeparators?: boolean;
|
||||
/** Ease animation @default true */
|
||||
useEasing?: boolean;
|
||||
/** Smooth easing for large numbers above this if useEasing @default 999 */
|
||||
smartEasingThreshold?: number;
|
||||
/** Amount to be eased for numbers above threshold @default 333 */
|
||||
smartEasingAmount?: number;
|
||||
/** Grouping separator @default ',' */
|
||||
separator?: string;
|
||||
/** Decimal character @default '.' */
|
||||
decimal?: string;
|
||||
/** Easing function for animation @default easeOutExpo */
|
||||
easingFn?: (t: number, b: number, c: number, d: number) => number;
|
||||
/** Custom function to format the result */
|
||||
formattingFn?: (n: number) => string;
|
||||
/** Text prepended to result */
|
||||
prefix?: string;
|
||||
/** Text appended to result */
|
||||
suffix?: string;
|
||||
/** Numeral glyph substitution */
|
||||
numerals?: string[];
|
||||
/** Callback called when animation completes */
|
||||
onCompleteCallback?: () => any;
|
||||
/** Callback called when animation starts */
|
||||
onStartCallback?: () => any;
|
||||
/** Plugin for alternate animations */
|
||||
plugin?: CountUpPlugin;
|
||||
/** Trigger animation when target becomes visible @default false */
|
||||
autoAnimate?: boolean;
|
||||
/** Animation delay in ms after auto-animate triggers @default 200 */
|
||||
autoAnimateDelay?: number;
|
||||
/** Run animation only once for auto-animate triggers @default false */
|
||||
autoAnimateOnce?: boolean;
|
||||
|
||||
/** @deprecated Please use autoAnimate instead */
|
||||
enableScrollSpy?: boolean;
|
||||
/** @deprecated Please use autoAnimateDelay instead */
|
||||
scrollSpyDelay?: number;
|
||||
/** @deprecated Please use autoAnimateOnce instead */
|
||||
scrollSpyOnce?: boolean;
|
||||
}
|
||||
|
||||
export declare interface CountUpPlugin {
|
||||
render(elem: HTMLElement, formatted: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates a number by counting to it.
|
||||
* playground: stackblitz.com/edit/countup-typescript
|
||||
*
|
||||
* @param target - id of html element, input, svg text element, or DOM element reference where counting occurs.
|
||||
* @param endVal - the value you want to arrive at.
|
||||
* @param options - optional configuration object for fine-grain control
|
||||
*/
|
||||
export class CountUp {
|
||||
|
||||
version = '2.10.0';
|
||||
private static observedElements = new WeakMap<HTMLElement, CountUp>();
|
||||
private defaults: CountUpOptions = {
|
||||
startVal: 0,
|
||||
decimalPlaces: 0,
|
||||
duration: 2,
|
||||
useEasing: true,
|
||||
useGrouping: true,
|
||||
useIndianSeparators: false,
|
||||
smartEasingThreshold: 999,
|
||||
smartEasingAmount: 333,
|
||||
separator: ',',
|
||||
decimal: '.',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
autoAnimate: false,
|
||||
autoAnimateDelay: 200,
|
||||
autoAnimateOnce: false,
|
||||
};
|
||||
private rAF: any;
|
||||
private autoAnimateTimeout: any;
|
||||
private startTime: number;
|
||||
private remaining: number;
|
||||
private finalEndVal: number = null; // for smart easing
|
||||
private useEasing = true;
|
||||
private countDown = false;
|
||||
private observer: IntersectionObserver;
|
||||
el: HTMLElement | HTMLInputElement;
|
||||
formattingFn: (num: number) => string;
|
||||
easingFn?: (t: number, b: number, c: number, d: number) => number;
|
||||
error = '';
|
||||
startVal = 0;
|
||||
duration: number;
|
||||
paused = true;
|
||||
frameVal: number;
|
||||
once = false;
|
||||
|
||||
constructor(
|
||||
target: string | HTMLElement | HTMLInputElement,
|
||||
private endVal?: number | null,
|
||||
public options?: CountUpOptions
|
||||
) {
|
||||
this.options = {
|
||||
...this.defaults,
|
||||
...options
|
||||
};
|
||||
if (this.options.enableScrollSpy) {
|
||||
this.options.autoAnimate = true;
|
||||
}
|
||||
if (this.options.scrollSpyDelay !== undefined) {
|
||||
this.options.autoAnimateDelay = this.options.scrollSpyDelay;
|
||||
}
|
||||
if (this.options.scrollSpyOnce) {
|
||||
this.options.autoAnimateOnce = true;
|
||||
}
|
||||
this.formattingFn = (this.options.formattingFn) ?
|
||||
this.options.formattingFn : this.formatNumber;
|
||||
this.easingFn = (this.options.easingFn) ?
|
||||
this.options.easingFn : this.easeOutExpo;
|
||||
|
||||
this.el = (typeof target === 'string') ? document.getElementById(target) : target;
|
||||
endVal = endVal == null ? this.parse(this.el.innerHTML) : endVal;
|
||||
|
||||
this.startVal = this.validateValue(this.options.startVal);
|
||||
this.frameVal = this.startVal;
|
||||
this.endVal = this.validateValue(endVal);
|
||||
this.options.decimalPlaces = Math.max(0 || this.options.decimalPlaces);
|
||||
this.resetDuration();
|
||||
this.options.separator = String(this.options.separator);
|
||||
this.useEasing = this.options.useEasing;
|
||||
if (this.options.separator === '') {
|
||||
this.options.useGrouping = false;
|
||||
}
|
||||
if (this.el) {
|
||||
this.printValue(this.startVal);
|
||||
} else {
|
||||
this.error = '[CountUp] target is null or undefined';
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && this.options.autoAnimate) {
|
||||
if (!this.error && typeof IntersectionObserver !== 'undefined') {
|
||||
this.setupObserver();
|
||||
} else {
|
||||
if (this.error) {
|
||||
console.error(this.error, target);
|
||||
} else {
|
||||
console.error('IntersectionObserver is not supported by this browser');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Set up an IntersectionObserver to auto-animate when the target element appears. */
|
||||
private setupObserver(): void {
|
||||
const existing = CountUp.observedElements.get(this.el as HTMLElement);
|
||||
if (existing) {
|
||||
existing.unobserve();
|
||||
}
|
||||
CountUp.observedElements.set(this.el as HTMLElement, this);
|
||||
this.observer = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting && this.paused && !this.once) {
|
||||
this.paused = false;
|
||||
this.autoAnimateTimeout = setTimeout(() => this.start(), this.options.autoAnimateDelay);
|
||||
if (this.options.autoAnimateOnce) {
|
||||
this.once = true;
|
||||
this.observer.disconnect();
|
||||
}
|
||||
} else if (!entry.isIntersecting && !this.paused) {
|
||||
clearTimeout(this.autoAnimateTimeout);
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
}, { threshold: 0 });
|
||||
this.observer.observe(this.el);
|
||||
}
|
||||
|
||||
/** Disconnect the IntersectionObserver and stop watching this element. */
|
||||
unobserve(): void {
|
||||
clearTimeout(this.autoAnimateTimeout);
|
||||
this.observer?.disconnect();
|
||||
CountUp.observedElements.delete(this.el as HTMLElement);
|
||||
}
|
||||
|
||||
/** Teardown: cancel animation, disconnect observer, clear callbacks. */
|
||||
onDestroy(): void {
|
||||
clearTimeout(this.autoAnimateTimeout);
|
||||
cancelAnimationFrame(this.rAF);
|
||||
this.paused = true;
|
||||
this.unobserve();
|
||||
this.options.onCompleteCallback = null;
|
||||
this.options.onStartCallback = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smart easing works by breaking the animation into 2 parts, the second part being the
|
||||
* smartEasingAmount and first part being the total amount minus the smartEasingAmount. It works
|
||||
* by disabling easing for the first part and enabling it on the second part. It is used if
|
||||
* useEasing is true and the total animation amount exceeds the smartEasingThreshold.
|
||||
*/
|
||||
private determineDirectionAndSmartEasing(): void {
|
||||
const end = (this.finalEndVal) ? this.finalEndVal : this.endVal;
|
||||
this.countDown = (this.startVal > end);
|
||||
const animateAmount = end - this.startVal;
|
||||
if (Math.abs(animateAmount) > this.options.smartEasingThreshold && this.options.useEasing) {
|
||||
this.finalEndVal = end;
|
||||
const up = (this.countDown) ? 1 : -1;
|
||||
this.endVal = end + (up * this.options.smartEasingAmount);
|
||||
this.duration = this.duration / 2;
|
||||
} else {
|
||||
this.endVal = end;
|
||||
this.finalEndVal = null;
|
||||
}
|
||||
if (this.finalEndVal !== null) {
|
||||
// setting finalEndVal indicates smart easing
|
||||
this.useEasing = false;
|
||||
} else {
|
||||
this.useEasing = this.options.useEasing;
|
||||
}
|
||||
}
|
||||
|
||||
/** Start the animation. Optionally pass a callback that fires on completion. */
|
||||
start(callback?: (args?: any) => any): void {
|
||||
if (this.error) {
|
||||
return;
|
||||
}
|
||||
if (this.options.onStartCallback) {
|
||||
this.options.onStartCallback();
|
||||
}
|
||||
if (callback) {
|
||||
this.options.onCompleteCallback = callback;
|
||||
}
|
||||
if (this.duration > 0) {
|
||||
this.determineDirectionAndSmartEasing();
|
||||
this.paused = false;
|
||||
this.rAF = requestAnimationFrame(this.count);
|
||||
} else {
|
||||
this.printValue(this.endVal);
|
||||
}
|
||||
}
|
||||
|
||||
/** Toggle pause/resume on the animation. */
|
||||
pauseResume(): void {
|
||||
if (!this.paused) {
|
||||
cancelAnimationFrame(this.rAF);
|
||||
} else {
|
||||
this.startTime = null;
|
||||
this.duration = this.remaining;
|
||||
this.startVal = this.frameVal;
|
||||
this.determineDirectionAndSmartEasing();
|
||||
this.rAF = requestAnimationFrame(this.count);
|
||||
}
|
||||
this.paused = !this.paused;
|
||||
}
|
||||
|
||||
/** Reset to startVal so the animation can be run again. */
|
||||
reset(): void {
|
||||
clearTimeout(this.autoAnimateTimeout);
|
||||
cancelAnimationFrame(this.rAF);
|
||||
this.paused = true;
|
||||
this.once = false;
|
||||
this.resetDuration();
|
||||
this.startVal = this.validateValue(this.options.startVal);
|
||||
this.frameVal = this.startVal;
|
||||
this.printValue(this.startVal);
|
||||
}
|
||||
|
||||
/** Pass a new endVal and start the animation. */
|
||||
update(newEndVal: string | number): void {
|
||||
cancelAnimationFrame(this.rAF);
|
||||
this.startTime = null;
|
||||
this.endVal = this.validateValue(newEndVal);
|
||||
if (this.endVal === this.frameVal) {
|
||||
return;
|
||||
}
|
||||
this.startVal = this.frameVal;
|
||||
if (this.finalEndVal == null) {
|
||||
this.resetDuration();
|
||||
}
|
||||
this.finalEndVal = null;
|
||||
this.determineDirectionAndSmartEasing();
|
||||
this.rAF = requestAnimationFrame(this.count);
|
||||
}
|
||||
|
||||
/** Animation frame callback — advances the value each frame. */
|
||||
count = (timestamp: number): void => {
|
||||
if (!this.startTime) { this.startTime = timestamp; }
|
||||
|
||||
const progress = timestamp - this.startTime;
|
||||
this.remaining = this.duration - progress;
|
||||
|
||||
// to ease or not to ease
|
||||
if (this.useEasing) {
|
||||
if (this.countDown) {
|
||||
this.frameVal = this.startVal - this.easingFn(progress, 0, this.startVal - this.endVal, this.duration);
|
||||
} else {
|
||||
this.frameVal = this.easingFn(progress, this.startVal, this.endVal - this.startVal, this.duration);
|
||||
}
|
||||
} else {
|
||||
this.frameVal = this.startVal + (this.endVal - this.startVal) * (progress / this.duration);
|
||||
}
|
||||
|
||||
// don't go past endVal since progress can exceed duration in the last frame
|
||||
const wentPast = this.countDown ? this.frameVal < this.endVal : this.frameVal > this.endVal;
|
||||
this.frameVal = wentPast ? this.endVal : this.frameVal;
|
||||
|
||||
// decimal
|
||||
this.frameVal = Number(this.frameVal.toFixed(this.options.decimalPlaces));
|
||||
|
||||
// format and print value
|
||||
this.printValue(this.frameVal);
|
||||
|
||||
// whether to continue
|
||||
if (progress < this.duration) {
|
||||
this.rAF = requestAnimationFrame(this.count);
|
||||
} else if (this.finalEndVal !== null) {
|
||||
// smart easing
|
||||
this.update(this.finalEndVal);
|
||||
} else {
|
||||
if (this.options.onCompleteCallback) {
|
||||
this.options.onCompleteCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Format and render the given value to the target element. */
|
||||
printValue(val: number): void {
|
||||
if (!this.el) return;
|
||||
const result = this.formattingFn(val);
|
||||
if (this.options.plugin?.render) {
|
||||
this.options.plugin.render(this.el, result);
|
||||
return;
|
||||
}
|
||||
if (this.el.tagName === 'INPUT') {
|
||||
const input = this.el as HTMLInputElement;
|
||||
input.value = result;
|
||||
} else if (this.el.tagName === 'text' || this.el.tagName === 'tspan') {
|
||||
this.el.textContent = result;
|
||||
} else {
|
||||
this.el.innerHTML = result;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true if the value is a finite number. */
|
||||
ensureNumber(n: any): boolean {
|
||||
return (typeof n === 'number' && !isNaN(n));
|
||||
}
|
||||
|
||||
/** Validate and convert a value to a number, setting an error if invalid. */
|
||||
validateValue(value: string | number): number {
|
||||
const newValue = Number(value);
|
||||
if (!this.ensureNumber(newValue)) {
|
||||
this.error = `[CountUp] invalid start or end value: ${value}`;
|
||||
return null;
|
||||
} else {
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/** Reset startTime, duration, and remaining to their initial values. */
|
||||
private resetDuration(): void {
|
||||
this.startTime = null;
|
||||
this.duration = Number(this.options.duration) * 1000;
|
||||
this.remaining = this.duration;
|
||||
}
|
||||
|
||||
/** Default number formatter with grouping, decimals, prefix/suffix, and numeral substitution. */
|
||||
formatNumber = (num: number): string => {
|
||||
const neg = (num < 0) ? '-' : '';
|
||||
let result: string, x1: string, x2: string, x3: string;
|
||||
result = Math.abs(num).toFixed(this.options.decimalPlaces);
|
||||
result += '';
|
||||
const x = result.split('.');
|
||||
x1 = x[0];
|
||||
x2 = x.length > 1 ? this.options.decimal + x[1] : '';
|
||||
if (this.options.useGrouping) {
|
||||
x3 = '';
|
||||
let factor = 3, j = 0;
|
||||
for (let i = 0, len = x1.length; i < len; ++i) {
|
||||
if (this.options.useIndianSeparators && i === 4) {
|
||||
factor = 2;
|
||||
j = 1;
|
||||
}
|
||||
if (i !== 0 && (j % factor) === 0) {
|
||||
x3 = this.options.separator + x3;
|
||||
}
|
||||
j++;
|
||||
x3 = x1[len - i - 1] + x3;
|
||||
}
|
||||
x1 = x3;
|
||||
}
|
||||
// optional numeral substitution
|
||||
if (this.options.numerals && this.options.numerals.length) {
|
||||
x1 = x1.replace(/[0-9]/g, (w) => this.options.numerals[+w]);
|
||||
x2 = x2.replace(/[0-9]/g, (w) => this.options.numerals[+w]);
|
||||
}
|
||||
return neg + this.options.prefix + x1 + x2 + this.options.suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default easing function (easeOutExpo).
|
||||
* @param t current time
|
||||
* @param b beginning value
|
||||
* @param c change in value
|
||||
* @param d duration
|
||||
*/
|
||||
easeOutExpo = (t: number, b: number, c: number, d: number): number =>
|
||||
c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
|
||||
|
||||
/** Parse a formatted string back to a number using the current separator/decimal options. */
|
||||
parse(number: string): number {
|
||||
// eslint-disable-next-line no-irregular-whitespace
|
||||
const escapeRegExp = (s: string) => s.replace(/([.,' ])/g, '\\$1');
|
||||
const sep = escapeRegExp(this.options.separator);
|
||||
const dec = escapeRegExp(this.options.decimal);
|
||||
const num = number.replace(new RegExp(sep, 'g'), '').replace(new RegExp(dec, 'g'), '.');
|
||||
return parseFloat(num)
|
||||
}
|
||||
}
|
||||
19
storage/public/dist/libs/countup.js/tsconfig.json
vendored
Normal file
19
storage/public/dist/libs/countup.js/tsconfig.json
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es2017", "dom"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"outDir": "dist",
|
||||
"target": "es5",
|
||||
"pretty": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
},
|
||||
"compileOnSave": true,
|
||||
"include": ["src"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue