diff --git a/static/css/combo-style.css b/static/css/combo-style.css
index 3dcbd96..fdbdf81 100644
--- a/static/css/combo-style.css
+++ b/static/css/combo-style.css
@@ -815,3 +815,21 @@ div.textcell.transition {
color: #eee;
}
}
+
+span#counter {
+ position: absolute;
+ bottom: 1em;
+ right: 0px;
+ font-size: 60px;
+ max-width: 6em;
+ line-height: 100%;
+ text-align: right;
+ font-family: Abeezee;
+ color: #444;
+}
+
+@media(max-width: 900px) {
+ span#counter {
+ display: none;
+ }
+}
diff --git a/static/js/combo.public.js b/static/js/combo.public.js
index b26bdee..8adcd86 100644
--- a/static/js/combo.public.js
+++ b/static/js/combo.public.js
@@ -16,4 +16,19 @@ $(function() {
$ecrans.css('background-position', (offset + pos/2) + 'px 0px');
});
}
+ if ($('div[id|=chiffres]').length) {
+ var $chiffres_section = $('div[id|=chiffres]');
+ $chiffres_section.css('position', 'relative');
+ var total = $chiffres_section.attr('id').split('-')[1];
+ var $counter = $('').appendTo($chiffres_section);
+ var options = {
+ useEasing : true,
+ useGrouping : true,
+ separator : ' ',
+ prefix : '',
+ suffix : ' usagers'
+ };
+ var count = new CountUp("counter", 1234, parseInt(total), 0, 4.5, options);
+ $chiffres_section.on('inview', function() { count.start(); });
+ }
});
diff --git a/static/js/countUp.js b/static/js/countUp.js
new file mode 100644
index 0000000..f378668
--- /dev/null
+++ b/static/js/countUp.js
@@ -0,0 +1,196 @@
+/*
+
+ countUp.js
+ by @inorganik
+
+*/
+
+// target = id of html element or var of previously selected 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, default 0
+// duration = duration of animation in seconds, default 2
+// options = optional object of options (see below)
+
+var CountUp = function(target, startVal, endVal, decimals, duration, options) {
+
+ // 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', '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, 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);
+ };
+ }
+
+ // default options
+ this.options = {
+ useEasing : true, // toggle easing
+ useGrouping : true, // 1,000,000 vs 1000000
+ separator : ',', // character to use as a separator
+ decimal : '.' // character to use as a decimal
+ };
+ // extend default options with passed options object
+ for (var key in options) {
+ if (options.hasOwnProperty(key)) {
+ this.options[key] = options[key];
+ }
+ }
+ if (this.options.separator === '') this.options.useGrouping = false;
+ if (!this.options.prefix) this.options.prefix = '';
+ if (!this.options.suffix) this.options.suffix = '';
+
+ this.d = (typeof target === 'string') ? document.getElementById(target) : target;
+ this.startVal = Number(startVal);
+ this.endVal = Number(endVal);
+ this.countDown = (this.startVal > this.endVal);
+ this.frameVal = this.startVal;
+ this.decimals = Math.max(0, decimals || 0);
+ this.dec = Math.pow(10, this.decimals);
+ this.duration = Number(duration) * 1000 || 2000;
+ var self = this;
+
+ this.version = function () { return '1.6.0'; };
+
+ // Print value to target
+ this.printValue = function(value) {
+ var result = (!isNaN(value)) ? self.formatNumber(value) : '--';
+ if (self.d.tagName == 'INPUT') {
+ this.d.value = result;
+ }
+ else if (self.d.tagName == 'text' || self.d.tagName == 'tspan') {
+ this.d.textContent = result;
+ }
+ else {
+ this.d.innerHTML = result;
+ }
+ };
+
+ // 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) self.startTime = timestamp;
+
+ self.timestamp = timestamp;
+
+ var progress = timestamp - self.startTime;
+ self.remaining = self.duration - progress;
+
+ // to ease or not to ease
+ if (self.options.useEasing) {
+ if (self.countDown) {
+ self.frameVal = self.startVal - self.easeOutExpo(progress, 0, self.startVal - self.endVal, self.duration);
+ } else {
+ self.frameVal = self.easeOutExpo(progress, self.startVal, self.endVal - self.startVal, self.duration);
+ }
+ } else {
+ if (self.countDown) {
+ self.frameVal = self.startVal - ((self.startVal - self.endVal) * (progress / self.duration));
+ } else {
+ self.frameVal = self.startVal + (self.endVal - self.startVal) * (progress / self.duration);
+ }
+ }
+
+ // don't go past endVal since progress can exceed duration in the last frame
+ if (self.countDown) {
+ self.frameVal = (self.frameVal < self.endVal) ? self.endVal : self.frameVal;
+ } else {
+ self.frameVal = (self.frameVal > self.endVal) ? self.endVal : self.frameVal;
+ }
+
+ // decimal
+ self.frameVal = Math.round(self.frameVal*self.dec)/self.dec;
+
+ // format and print value
+ self.printValue(self.frameVal);
+
+ // whether to continue
+ if (progress < self.duration) {
+ self.rAF = requestAnimationFrame(self.count);
+ } else {
+ if (self.callback) self.callback();
+ }
+ };
+ // start your animation
+ this.start = function(callback) {
+ self.callback = callback;
+ self.rAF = requestAnimationFrame(self.count);
+ return false;
+ };
+ // toggles pause/resume animation
+ this.pauseResume = function() {
+ if (!self.paused) {
+ self.paused = true;
+ cancelAnimationFrame(self.rAF);
+ } else {
+ self.paused = false;
+ delete self.startTime;
+ self.duration = self.remaining;
+ self.startVal = self.frameVal;
+ requestAnimationFrame(self.count);
+ }
+ };
+ // reset to startVal so animation can be run again
+ this.reset = function() {
+ self.paused = false;
+ delete self.startTime;
+ self.startVal = startVal;
+ cancelAnimationFrame(self.rAF);
+ self.printValue(self.startVal);
+ };
+ // pass a new endVal and start animation
+ this.update = function (newEndVal) {
+ cancelAnimationFrame(self.rAF);
+ self.paused = false;
+ delete self.startTime;
+ self.startVal = self.frameVal;
+ self.endVal = Number(newEndVal);
+ self.countDown = (self.startVal > self.endVal);
+ self.rAF = requestAnimationFrame(self.count);
+ };
+ this.formatNumber = function(nStr) {
+ nStr = nStr.toFixed(self.decimals);
+ nStr += '';
+ var x, x1, x2, rgx;
+ x = nStr.split('.');
+ x1 = x[0];
+ x2 = x.length > 1 ? self.options.decimal + x[1] : '';
+ rgx = /(\d+)(\d{3})/;
+ if (self.options.useGrouping) {
+ while (rgx.test(x1)) {
+ x1 = x1.replace(rgx, '$1' + self.options.separator + '$2');
+ }
+ }
+ return self.options.prefix + x1 + x2 + self.options.suffix;
+ };
+
+ // format startVal on initialization
+ self.printValue(self.startVal);
+};
+
+// Example:
+// var numAnim = new countUp("SomeElementYouWantToAnimate", 0, 99.99, 2, 2.5);
+// numAnim.start();
+// numAnim.update(135);
+// with optional callback:
+// numAnim.start(someMethodToCallOnComplete);
diff --git a/static/js/jquery.inview.js b/static/js/jquery.inview.js
new file mode 100644
index 0000000..362c34b
--- /dev/null
+++ b/static/js/jquery.inview.js
@@ -0,0 +1,147 @@
+/**
+ * author Christopher Blum
+ * - based on the idea of Remy Sharp, http://remysharp.com/2009/01/26/element-in-view-event-plugin/
+ * - forked from http://github.com/zuk/jquery.inview/
+ */
+(function (factory) {
+ if (typeof define == 'function' && define.amd) {
+ // AMD
+ define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node, CommonJS
+ module.exports = factory(require('jquery'));
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+ var inviewObjects = {}, viewportSize, viewportOffset,
+ d = document, w = window, documentElement = d.documentElement, expando = $.expando, timer;
+
+ $.event.special.inview = {
+ add: function(data) {
+ inviewObjects[data.guid + "-" + this[expando]] = { data: data, $element: $(this) };
+
+ // Use setInterval in order to also make sure this captures elements within
+ // "overflow:scroll" elements or elements that appeared in the dom tree due to
+ // dom manipulation and reflow
+ // old: $(window).scroll(checkInView);
+ //
+ // By the way, iOS (iPad, iPhone, ...) seems to not execute, or at least delays
+ // intervals while the user scrolls. Therefore the inview event might fire a bit late there
+ //
+ // Don't waste cycles with an interval until we get at least one element that
+ // has bound to the inview event.
+ if (!timer && !$.isEmptyObject(inviewObjects)) {
+ timer = setInterval(checkInView, 250);
+ }
+ },
+
+ remove: function(data) {
+ try { delete inviewObjects[data.guid + "-" + this[expando]]; } catch(e) {}
+
+ // Clear interval when we no longer have any elements listening
+ if ($.isEmptyObject(inviewObjects)) {
+ clearInterval(timer);
+ timer = null;
+ }
+ }
+ };
+
+ function getViewportSize() {
+ var mode, domObject, size = { height: w.innerHeight, width: w.innerWidth };
+
+ // if this is correct then return it. iPad has compat Mode, so will
+ // go into check clientHeight/clientWidth (which has the wrong value).
+ if (!size.height) {
+ mode = d.compatMode;
+ if (mode || !$.support.boxModel) { // IE, Gecko
+ domObject = mode === 'CSS1Compat' ?
+ documentElement : // Standards
+ d.body; // Quirks
+ size = {
+ height: domObject.clientHeight,
+ width: domObject.clientWidth
+ };
+ }
+ }
+
+ return size;
+ }
+
+ function getViewportOffset() {
+ return {
+ top: w.pageYOffset || documentElement.scrollTop || d.body.scrollTop,
+ left: w.pageXOffset || documentElement.scrollLeft || d.body.scrollLeft
+ };
+ }
+
+ function checkInView() {
+ var $elements = [], elementsLength, i = 0;
+
+ $.each(inviewObjects, function(i, inviewObject) {
+ var selector = inviewObject.data.selector,
+ $element = inviewObject.$element;
+ $elements.push(selector ? $element.find(selector) : $element);
+ });
+
+ elementsLength = $elements.length;
+ if (elementsLength) {
+ viewportSize = viewportSize || getViewportSize();
+ viewportOffset = viewportOffset || getViewportOffset();
+
+ for (; i viewportOffset.top &&
+ elementOffset.top < viewportOffset.top + viewportSize.height &&
+ elementOffset.left + elementSize.width > viewportOffset.left &&
+ elementOffset.left < viewportOffset.left + viewportSize.width) {
+ visiblePartX = (viewportOffset.left > elementOffset.left ?
+ 'right' : (viewportOffset.left + viewportSize.width) < (elementOffset.left + elementSize.width) ?
+ 'left' : 'both');
+ visiblePartY = (viewportOffset.top > elementOffset.top ?
+ 'bottom' : (viewportOffset.top + viewportSize.height) < (elementOffset.top + elementSize.height) ?
+ 'top' : 'both');
+ visiblePartsMerged = visiblePartX + "-" + visiblePartY;
+ if (!inView || inView !== visiblePartsMerged) {
+ $element.data('inview', visiblePartsMerged).trigger('inview', [true, visiblePartX, visiblePartY]);
+ }
+ } else if (inView) {
+ $element.data('inview', false).trigger('inview', [false]);
+ }
+ }
+ }
+ }
+
+ $(w).bind("scroll resize scrollstop", function() {
+ viewportSize = viewportOffset = null;
+ });
+
+ // IE < 9 scrolls to focused elements without firing the "scroll" event
+ if (!documentElement.addEventListener && documentElement.attachEvent) {
+ documentElement.attachEvent("onfocusin", function() {
+ viewportOffset = null;
+ });
+ }
+}));
diff --git a/templates/combo/page_template.html b/templates/combo/page_template.html
index dcf4e2a..a9e9589 100644
--- a/templates/combo/page_template.html
+++ b/templates/combo/page_template.html
@@ -11,6 +11,8 @@
+
+