Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new Feature: Flaps #304

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
npm-debug.log
.idea
.DS_Store
package-lock.json
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ interface CountUpOptions {
scrollSpyDelay?: number; // delay (ms) after target comes into view
scrollSpyOnce?: boolean; // run only once
onCompleteCallback?: () => any; // gets called when animation completes
flaps?: boolean // digits are flaps thanks to Marcel Soler
flapDuration?: number // flap animation in seconds,
flapDelay?: number // delay last digit in animation, in seconds, 0 to deactivate
}
```

Expand Down
8 changes: 7 additions & 1 deletion demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ window.onload = function () {
prefix: el('prefix').value,
suffix: el('suffix').value,
numerals: getNumerals(),
onCompleteCallback: el('useOnComplete').checked ? calculateAnimationTime : null
onCompleteCallback: el('useOnComplete').checked ? calculateAnimationTime : null,
flaps: el('useFlaps').checked,
flapDuration: el('flapDuration').value,
flapDelay: el('flapDelay').value
};
// unset null values so they don't overwrite defaults
for (var key in options) {
Expand Down Expand Up @@ -174,6 +177,9 @@ window.onload = function () {
opts += (options.suffix.length) ? indentedLine("suffix: '" + options.suffix + "'") : '';
opts += (options.numerals && options.numerals.length) ?
indentedLine("numerals: " + stringifyArray(options.numerals)) : '';
opts += (options.flaps) ? indentedLine("flaps: true") : '';
opts += (options.flapDuration) ? indentedLine("flapDuration: " + options.flapDuration) : '';
opts += (options.flapDelay) ? indentedLine("flapDelay: " + options.flapDelay) : '';
opts += (options.onCompleteCallback) ? indentedLine("onCompleteCallback: methodToCallOnComplete") : '';

if (opts.length) {
Expand Down
5 changes: 5 additions & 0 deletions dist/countUp.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export interface CountUpOptions {
scrollSpyDelay?: number;
scrollSpyOnce?: boolean;
onCompleteCallback?: () => any;
flaps?: boolean;
flapDuration?: number;
flapDelay?: number;
}
export declare class CountUp {
private endVal;
Expand All @@ -31,6 +34,7 @@ export declare class CountUp {
private finalEndVal;
private useEasing;
private countDown;
private cells_flaps;
formattingFn: (num: number) => string;
easingFn?: (t: number, b: number, c: number, d: number) => number;
error: string;
Expand All @@ -53,6 +57,7 @@ export declare class CountUp {
reset(): void;
update(newEndVal: string | number): void;
count: (timestamp: number) => void;
printFlaps(result: string): void;
printValue(val: number): void;
ensureNumber(n: any): boolean;
validateValue(value: string | number): number;
Expand Down
132 changes: 132 additions & 0 deletions dist/countUp.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@ var CountUp = /** @class */ (function () {
enableScrollSpy: false,
scrollSpyDelay: 200,
scrollSpyOnce: false,
// Marcel Soler
flaps: false,
flapDuration: 0.8,
flapDelay: 0.25,
};
this.finalEndVal = null; // for smart easing
this.useEasing = true;
this.countDown = false;
this.cells_flaps = null;
this.error = '';
this.startVal = 0;
this.paused = true;
Expand Down Expand Up @@ -257,10 +262,137 @@ var CountUp = /** @class */ (function () {
this.determineDirectionAndSmartEasing();
this.rAF = requestAnimationFrame(this.count);
};
// Marcel Soler
CountUp.prototype.printFlaps = function (result) {
var createdNow = false;
if (!this.cells_flaps) {
createdNow = true;
// avoid adding more than once
if (!document.querySelector('style[flap]')) {
// add styles for flap numbers
var style = document.createElement('style');
style.setAttribute('flap', 'flap');
style.innerHTML = "\n .flap-numbers{display: inline-flex; line-height: 100%;overflow-y: hidden;}\n .flap-numbers > span{display: flex; flex-direction:column;justify-content: start; align-items: center; height: 1em; will-change: transform; transform: translateY(0)}\n ";
document.head.appendChild(style);
}
// create wrapper
this.el.innerHTML = '<div class="flap-numbers"></div>';
// create array cells_flaps information
this.cells_flaps = [];
}
//blank space
var blank = '<span style="color:transparent">0</span>';
var transitionFlap = "transform ".concat(this.options.flapDuration, "s ease-out");
// appearing new cells_flaps
for (var i = this.cells_flaps.length; i < result.length; i++) {
// create a container
var container = document.createElement('span');
container.style.transition = transitionFlap;
// add a first transparent cell
container.innerHTML = createdNow ? '' : blank;
this.el.firstChild.appendChild(container);
// prepare data id cell
this.cells_flaps.push({
container: container,
current: undefined,
position: createdNow ? 1 : 0,
new: true,
});
}
function appendDigit(cell, newDigit) {
cell.position--;
cell.container.appendChild(newDigit);
cell.lastTimeAdd = +new Date();
// we need to stablish transition at first number, using timeout
if (cell.new) {
cell.new = false;
requestAnimationFrame(function () {
cell.container.style.transform = "translateY(".concat(cell.position, "em)");
});
}
else
cell.container.style.transform = "translateY(".concat(cell.position, "em)");
}
function pushDigit(cell, newDigit, options) {
// if there was another cell waiting to be added, we add it here
if (cell.nextToAdd) {
appendDigit(cell, cell.nextToAdd);
clearTimeout(cell.lastTimer);
cell.nextToAdd = null;
}
var now = +new Date();
var delayTime = options.flapDelay * 1000 - (now - cell.lastTimeAdd);
// if we are in slow animation, we just add digit
if (options.flapDelay <= 0 ||
now - cell.lastTimeAdd >= delayTime * 1.05) {
appendDigit(cell, newDigit);
cell.nextToAdd = null;
}
else {
// if not, we delay the push
cell.nextToAdd = newDigit;
cell.lastTimer = setTimeout(function () {
appendDigit(cell, cell.nextToAdd);
cell.nextToAdd = null;
}, options.flapDuration * 1000);
}
}
// we add all sequence cells_flaps that are new in result
// or remove cells no more exist (we put blank cells)
var len = Math.max(result.length, this.cells_flaps.length);
var _loop_1 = function () {
// cell has changed
ch = i < result.length ? result.charAt(i) : null;
var cell = this_1.cells_flaps[i];
if (cell.current != ch) {
cell.current = ch;
newDigit = document.createElement('span');
newDigit.innerHTML = ch === null ? blank : ch;
// the last delay animation only if there is a minimum of 3 elements
if (cell.container.children.length < 4) {
appendDigit(cell, newDigit);
}
else {
pushDigit(cell, newDigit, this_1.options);
}
clearTimeout(cell.timerClean);
// when animation end, we can remove all extra animated cells
cell.timerClean = setTimeout(function () {
cell.timerClean = null;
if (cell.container.children.length < 3)
return;
cell.container.style.transition = 'none'; // temporally clear animation transition
requestAnimationFrame(function () {
cell.position = -1;
// we remove all childs except last
while (cell.container.children.length > 1)
cell.container.removeChild(cell.container.firstChild);
//insert blank space (forcing width to avoid weird behaviour in comma)
var digitBlank = document.createElement('span');
digitBlank.innerHTML = blank;
cell.container.insertBefore(digitBlank, cell.container.firstChild);
// set scroll to last cell position
cell.container.style.transform = "translateY(".concat(cell.position, "em)");
requestAnimationFrame(function () {
cell.container.style.transition = transitionFlap; // restart animation transition
});
});
}, this_1.options.flapDuration * 1000 * 3);
}
};
var this_1 = this, ch, newDigit;
for (var i = 0; i < len; i++) {
_loop_1();
}
};
CountUp.prototype.printValue = function (val) {
var result = this.formattingFn(val);
if (!this.el)
return;
if (this.options.flaps) {
this.printFlaps(result);
return;
}
if (this.el.tagName === 'INPUT') {
var input = this.el;
input.value = result;
Expand Down
Loading