Full website with security hardening: - Redesigned sections: hero, services, capabilities, clients, partners, stats, about, workflow, contact - Contact form fixed (variable names, XSS sanitisation, rate limiting, open redirect removed) - .htaccess with security headers (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy) - error_log blocked from public access - Robots.txt corrected to allow JS/CSS for SEO rendering
155 lines
5.2 KiB
JavaScript
155 lines
5.2 KiB
JavaScript
/*
|
|
|
|
countUp.js
|
|
by @inorganik
|
|
v 1.0.0
|
|
|
|
*/
|
|
|
|
// target = id of Html element where counting occurs
|
|
// startVal = the value you want to begin at
|
|
// endVal = the value you want to arrive at
|
|
// decimals = number of decimal places in number, default 0
|
|
// duration = duration in seconds, default 2
|
|
|
|
function countUp(target, startVal, endVal, decimals, duration) {
|
|
|
|
// make sure requestAnimationFrame and cancelAnimationFrame are defined
|
|
// polyfill for browsers without native support
|
|
// by Opera engineer Erik Möller
|
|
var lastTime = 0;
|
|
var vendors = ['webkit', 'moz', 'ms'];
|
|
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, element) {
|
|
var currTime = new Date().getTime();
|
|
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
|
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
|
|
timeToCall);
|
|
lastTime = currTime + timeToCall;
|
|
return id;
|
|
}
|
|
}
|
|
if (!window.cancelAnimationFrame) {
|
|
window.cancelAnimationFrame = function(id) {
|
|
clearTimeout(id);
|
|
}
|
|
}
|
|
|
|
var self = this;
|
|
|
|
// toggle easing
|
|
this.useEasing = true;
|
|
|
|
this.d = document.getElementById(target);
|
|
self.startVal = Number(startVal);
|
|
endVal = Number(endVal);
|
|
this.countDown = (startVal > endVal) ? true : false;
|
|
decimals = Math.max(0, decimals || 0);
|
|
this.dec = Math.pow(10, decimals);
|
|
this.duration = duration * 1000 || 2000;
|
|
this.startTime = null;
|
|
this.timestamp = null;
|
|
this.remaining = null;
|
|
this.frameVal = startVal;
|
|
this.rAF = null;
|
|
|
|
// Robert Penner's easeOutExpo
|
|
this.easeOutExpo = function(t, b, c, d) {
|
|
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
|
|
}
|
|
this.count = function(timestamp) {
|
|
|
|
if (self.startTime === null) self.startTime = timestamp;
|
|
|
|
self.timestamp = timestamp;
|
|
|
|
var progress = timestamp - self.startTime;
|
|
self.remaining = self.duration - progress;
|
|
|
|
// to ease or not to ease
|
|
if (self.useEasing) {
|
|
if (self.countDown) {
|
|
var i = self.easeOutExpo(progress, 0, self.startVal - endVal, self.duration);
|
|
self.frameVal = startVal - i;
|
|
} else {
|
|
self.frameVal = self.easeOutExpo(progress, self.startVal, endVal - self.startVal, self.duration);
|
|
}
|
|
} else {
|
|
if (self.countDown) {
|
|
var i = (self.startVal - endVal) * (progress / self.duration);
|
|
self.frameVal = self.startVal - i;
|
|
} else {
|
|
self.frameVal = self.startVal + (endVal - self.startVal) * (progress / self.duration);
|
|
}
|
|
}
|
|
|
|
// decimal
|
|
self.frameVal = Math.round(self.frameVal*self.dec)/self.dec;
|
|
|
|
// don't go past endVal since progress can exceed duration in the last frame
|
|
if (self.countDown) {
|
|
self.frameVal = (self.frameVal < endVal) ? endVal : self.frameVal;
|
|
} else {
|
|
self.frameVal = (self.frameVal > endVal) ? endVal : self.frameVal;
|
|
}
|
|
|
|
// format and print value
|
|
self.d.innerHTML = self.addCommas(self.frameVal.toFixed(decimals));
|
|
|
|
// whether to continue
|
|
if (progress < self.duration) {
|
|
self.rAF = requestAnimationFrame(self.count);
|
|
} else {
|
|
if (self.callback != null) self.callback();
|
|
}
|
|
}
|
|
this.start = function(callback) {
|
|
self.callback = callback;
|
|
// make sure values are valid
|
|
if (!isNaN(endVal) && !isNaN(startVal)) {
|
|
self.rAF = requestAnimationFrame(self.count);
|
|
} else {
|
|
console.log('countUp error: startVal or endVal is not a number');
|
|
self.d.innerHTML = '--';
|
|
}
|
|
return false;
|
|
}
|
|
this.stop = function() {
|
|
cancelAnimationFrame(self.rAF);
|
|
}
|
|
this.reset = function() {
|
|
cancelAnimationFrame(self.rAF);
|
|
self.d.innerHTML = self.addCommas(startVal.toFixed(decimals));
|
|
}
|
|
this.resume = function() {
|
|
self.startTime = null;
|
|
self.duration = self.remaining;
|
|
self.startVal = self.frameVal;
|
|
requestAnimationFrame(self.count);
|
|
}
|
|
this.addCommas = function(nStr) {
|
|
nStr += '';
|
|
var x, x1, x2, rgx;
|
|
x = nStr.split('.');
|
|
x1 = x[0];
|
|
x2 = x.length > 1 ? '.' + x[1] : '';
|
|
rgx = /(\d+)(\d{3})/;
|
|
while (rgx.test(x1)) {
|
|
x1 = x1.replace(rgx, '$1' + ',' + '$2');
|
|
}
|
|
return x1 + x2;
|
|
}
|
|
|
|
// format startVal on initialization
|
|
self.d.innerHTML = self.addCommas(startVal.toFixed(decimals));
|
|
}
|
|
// Example:
|
|
// var numAnim = new countUp("SomeElementYouWantToAnimate", 0, 99.99, 2, 1.5);
|
|
// numAnim.start();
|
|
// with optional callback
|
|
// numAnim.start(someMethodToCallOnComplete);
|