Search code examples
javascriptjqueryvariablescountdownvar

jQuery hsCountdown returns wrong values for some numbers


I use rewrited hsCountdown library and for some numbers it show wrong values:
In example above I specified "130" for increment to, but hsCountdown incrementing it only to 125. Why?

I was debug for "r" variable (on line where located #debug_console) and what you can mean? This variable magically was increment not by integer number, but float.
For example, 54.0000000001 instead of 54. JavaScript, you're so drunk!

(function(a) {
    "use strict";
    a.fn.hsCounter = function(b) {
        var c = a.extend({
            delay: 50,
            signPos: "after",
            classVisible: "countup-vis",
            decimalSeparator: ".",
            orderSeparator: " "
        }, b);
        return this.each(function() {
            b && a.extend(c, b);
            var timer, num, line, content, self = a(this),
                win = a(window),
                winTop = win.scrollTop(),
                winHeight = win.height(),
                numb = self.data("num"),
                increment = self.data("increment") ? self.data("increment") : (numb / 25 > 1.0 ? numb / 25 : 1.0),
                fractional = self.data("fractional") ? self.data("fractional") : 0,
                sign = self.data("sign") ? self.data("sign") : "",
                regExp = /(\d)(?=(\d\d\d)+([^\d]|$))/g,
                start = self.data("start") ? +self.data("start") : 0,
                amount = a(".countup-amount"),
                realMaxNumber = numb - increment;

				winTop <= self.offset().top && winTop + winHeight >= self.offset().top && (timer = setTimeout(function u() {
					var currentIncrement = (fractional > 0 ? start.toFixed(fractional) : start);
					$('#debug_console').append('[Condition debug] (currentIncrement <= realMaxNumber) equals ('+currentIncrement+' <= '+realMaxNumber+')<br>');

					return (currentIncrement <= realMaxNumber)
					
					?
					
					(start += increment, num = start.toFixed(fractional).replace(".", c.decimalSeparator).replace(regExp, "$1" + c.orderSeparator), content = self.find(amount).html(num), "after" == c.signPos ? self.html('<span class="countup-amount">' + num + '</span><span class="countup-sign">' + sign + "</span>") : "before" == c.signPos && self.html('<span class="countup-sign">' + sign + '</span><span class="countup-amount">' + num + "</span>"), self.hasClass("progress-up") && (self.html(self.html() + "<ins/>"), self.find("ins").css("width", start + "%")), self.parent().hasClass("countup-wrap") && (line = self.parent().find(".countup-line"), line.css("width", start + "%")), void(timer = setTimeout(u, c.delay)))
					
					:
					
					(start = numb, !0);
				}, c.delay));
        });
    }
})(jQuery);

function initCounter(a, b) { b ? a.hsCounter() : a.text("0"); }

initCounter($(".counterup"), 1);
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>

<h1 class="counterup js" data-num="130">...</h1>

<div id="debug_console"></div>


Solution

  • The issue relies in these lines:

    n = h.data("increment") ? h.data("increment") : (l / 25 > 1.0 ? l / 25 : 1.0), and t = l - n;

    t is basically the number that this code will count up to. t is calculated as l (which is the data-num attribute, 130 in this case minus n which is the derived from the data-increment attribute.

    As you can see, you did not provide a data-increment, and the code defaults to l / 25, which is 130 / 25 = 5.2. Then, t is will actually be l - n = 130 - 5.2 = 124.8, and this is why it counts to 125 instead of 30.

    A simple solution will be to add data-increment="1" to your h1 tag. You can consider changing the default calculation for the n variable too.

    EDIT:

    I see that you edited your code, which is great because it's much easier to debug. I think the solution whould be to change this line: (start = numb, !0); to something like this: self.find(".countup-amount").html(numb); It basically means the if the current number + increment value is greater than the target value, it means it is the last step, and we can simply populate our span with the target value.