Animations with requestAnimationFrame

Recently I deceided to explore requestAnimationFrame as a way to peer behind the jQuery.animate veil. While you should absolutely use jQuery.animate (or similar) when working on a "real" project, the results were pretty interesting:

function animate(el, properties, duration, done) {
    function map(obj, transform){
        var result = {};
        Object.keys(obj).forEach(function (key) {
            result[key] = transform(key, obj[key]);
        });
        return result;
    }

    function accessor(property) {
        return {
            get: function (el) {
                var value = styles[property]
                if (value === 'auto') {
                    return 0;
                }

                return parseInt(value, 10);
            },
            set: function (el, value) {
                el.style[property] = value + "px";
            }
        };
    }

    var start,
        styles = getComputedStyle(el),
        startingValues = map(properties, function(key, value) {
            return accessor(key).get(el);
        });

    requestAnimationFrame(function step(timestamp) {
        done = done || function () {};
        start = start || timestamp;

        var elapsed = timestamp - start;

        Object.keys(properties).forEach(function (property) {
            var goal = properties[property],
                startingValue = startingValues[property],
                delta = goal - startingValue,
                progress = elapsed / duration,
                bound = (delta > 0 ? Math.min : Math.max),
                value = bound(delta * progress + startingValue, goal);

                accessor(property).set(el, value);
        });

        if (elapsed < duration) {
            requestAnimationFrame(step);
        } else {
            done();
        }
    });
}

Interestingly enough, the actual animation code is almost dwarfed by the code providing the API and fiddling with css properties to make sure they're in the right format.

Enough chit-chat, where's the bouncing ball?

I'm so glad you asked, I've even implemented the obligatory bouncing ball. Go take a look!

JavaScript Templates (redux)

In the spirit of code kata (the origional problem was a kata) here is an alternative solution to the JavaScript templating problem:

var template = (function(){
    var grammar = parsec.grammar([
        parsec.token("placeholder", "[$]\\w+"),
        parsec.token("literal", "[^$]+")
    ]);

    with(grammar){
        root("template", placeholder.or(literal).repeated().then(eof));
    }

    return {
        render: function render(source, context){
            var handlers = {
                literal: function(node){
                    return node.v;
                },

                placeholder: function(node){
                    var key = node.v.substring(1);
                    return context[key] || "";
                },

                template: function(node){
                    return $.map(node.children, evaluate).join("");
                }
            };

            function evaluate(node){
                return handlers[node.type](node);
            }

            var root = grammar.parse(source);
            return evaluate(root);
        }
    };
})(parsec.util);

It's a bunch longer. It's not quite ten time's longer, but it's kind of close... and it passes exactly the same test suite and has the same features, so what, if anything is good about it?

For one thing, it uses a completely different approach. It builds a recursive descent parser using a parsing library that I put together that's based on Parsec. The basic idea of Parsec, and other parser combinator libraries, is that you define simple parsers and then compose them into more complicated parsers using combinators. What this means is that, while it is not necessary here, this approach can handle much more complicated languages than the regex based approach.

Oh, and there was one little nugget of joy in there that deserves special mention. You, might have missed it, so I'll show it again:

with(grammar){
    root("template", placeholder.or(literal).repeated().then(eof));
}

That's right, a with statement. I bet you never though you would see somebody actually try to use one of those. Sure, with statements are widely reviled, they are not one of the good parts, and they're dead in EC5 strict mode... but embedded DSLs are one of the places where you're allowed to cheat like there's not tomorrow. 'sides, $.extend(window, grammar); is your other option for scope manipulation and that's just plain evil.

JavaScript Templates

While playing around with autotest-style QUnit, I needed something to work on that actually needed some tests. Naturally, I settled on the same problem that they did in the video: Given a string with $-placeholders, replace the placeholders with values from a context object. Here's the code I came up with:

var template = (function(){
    return {
        render: function(source, context){
            return source.replace(/\$\w+/g, function(match){
                var key = match.substring(1);
                return context[key] || "";
            }) ;
        }
    };
})();

Dead simple, right? Four actual lines of code and a bunch of setup to put it in a fake module. Here are the tests:

$(function(){
    function replace(source, expected, context, msg){
        equals(template.render(source, context), expected, msg);
    }

    module("template.render");
    test("with no tokens", function() {
        replace("", "", {},
            "returns blank string if the given string is blank"
        );

        replace("hello, world", "hello, world", {},
            "returns a non-blank string unchanged"
        );
    });

    test("with one token", function(){
        replace("$name", "", {},
            "replaces token with empty string if no value in context"
        );

        replace("$name", "Aaron", {name: "Aaron"},
            "replaces token with value from the context"
        );

        replace("Hello $name!", "Hello Aaron!", {name: "Aaron"},
            "leaves the rest of the string unchanged"
        );
    });

    test("with two tokens", function(){
        replace(
            "Hello $name! It is a $attitude day.",
            "Hello Aaron! It is a wonderful day.",
            {name: "Aaron", attitude: "wonderful"},
            "replaces each token with the value from the context"
        );

        replace(
            "Hello $name! It is a $attitude day.",
            "Hello Aaron! It is a  day.",
            {name: "Aaron"},
            "replaces each token without a value in the context with the blank string"
        );

        replace("$me$you", "AaronJohn", {me: "Aaron", you: "John"},
            "replaces adjacent tokens with their respective values"
        );
    });
});

Kind of verbose, but they're actually kind of interesting. They're written in a BDD style, or as much of a BDD style as QUnit will allow. You can easily imagine a tool that extracts:

template.render
    with no tokens
        - returns blank string if the given string is blank
        - returns a non-blank string unchanged

... from tests like these. Indeed, such tools exists for RSpec and there is a BDD JavaScript testing framework, imaginatively named: JSpec, which I expect provides similar tools for it's tests.

It was an interesting experience to work my way through the tests one at a time, implementing that simplest thing that could possibly work. Though, It is kind of discouraging that the test suite is so much longer than the implementation, especially considering this code is so easily tested.

Autotesting QUnit

I was watching a video on performance code kata and I was intrigued by the use of autotest. Basically, it's just a tool that watches the filesystem for changes and re-runs your test-suite when stuff changes. I thought it was a neat idea and wanted to try it out, but I don't really write any Ruby. Instead I turned to the world's most popular dynamic language: JavaScript. I've used QUnit to do some test driven development in JavScript, so tried the simplest thing that could possibly work, a meta-refresh:

<meta http-equiv="refresh" content="5"/>

... and that kind of worked. It was kind of cool, but the constant refreshing gets in the way of of using the JavaScript console to poke at things. Which, when you're writing JavaScript, is kind of an important thing to do. So... meta-refresh with a pause button?

$(function(){
    function startPaused(){
        return location.hash.indexOf("autotest=true") == -1;
    }

    function enable(){
        button.removeAttr("disabled");
        $("body").unbind("mousemove", enable);
    }

    var paused = startPaused();
    var button = $('<input type="button" value="{title}" id="auto-refresh">'.replace("{title}",
        (paused ? "autotest" : "pause")
    ));
    $("body").prepend(button);

    button.click(function(){
        paused = !paused;
        button.attr("value", (paused ? "resume" : "pause"));
        button.attr("disabled", "disabled");

        if(paused){
            location.hash = "";
        }

        $("body").mousemove(enable);
    });


    setInterval(function(){
        if(!paused){
            location.hash = "#autotest=true"
            location.reload(true);
        }
    }, 5000);
});
#auto-refresh {
    float: right;
    background-color: #D2E0E6;
    border: 2px solid #2B81AF;
    color: #2B81AF;
    margin-right: 1em;
    margin-top: 1em;
    border-radius: 5px;
}

#auto-refresh[disabled] {
    opacity: 0.75;
}

There you go. Thirty-odd lines to implement meta-refresh a pause button sigh.

It is actually pretty neat. If I used QUnit more and was in a better position to judge the actually usefulness of such a feature I might try hacking this into core QUnit and seeing if I could get it merged upstream. I mean, there are entire projects built around adding this kind of functionality to other tools, and it's so easy to do in a browser. I'm not planning on it though, because I've only actually used QUnit for fun-zies, and can't really judge how useful this kind of functionality would be on an actual test suite.

May I Bring Your Attention To...

One of the cool things I ended up implementing was Chrome-style disable-enable behaviour for the pause/resume button. Basically, as part of the click handler, it disabled the button and attached a mousemove event handler on the body. The handler then enables the button and unbinds itself when a mousemove event fires. The cool part is that while the button is disabled and your cursor is over it, moving your mouse doesn't fire any mousemove events, but the second your cursor leaves the button, a mousemove event fires and the button gets enabled. You get to safely reuse the pause/resume button without worrying about double clicks doing the wrong thing. Pretty spiffy, huh?

die Frequenz der Blog

Post Frequency by Month

/blog/entries/2010/12/07/die_frequenz_der_blog/by_month-6c41c7b46f47.min.png

This nicely illustrates that my blogging attention span is kind of bursty. There is a cluster of posts during the first half of 2008, another one in the first half of 2009 and then a giant dead spot from the middle of 2009 until last month. It's actually kind of funny that pretty much all of my blog posts have been written in tree bursts of attention separated by big swaths of neglect.

Histogram of Post Frequency

/blog/entries/2010/12/07/die_frequenz_der_blog/by_count-103df219d0cf.min.png

... and the runaway winner is zero! Mostly explained by the fact that there have been streches of five or six months where I haven't posted a single thing (like, for instance, the first half of 2010). November 2010 deserves special mention as it is a crazy outlier on the the complete other end of the scale with four more posts then then next most prolific month.

Making Tufte Proud

I used flot to generate the histograms and while it does a good job at producing nice looking graphs it has the annoying habit of adding lots of stuff to your plots which reduces the percentage of pixels in your plot that convey data (data ink). It took a surprising amount of fiddling to turn off all of the exta stuff, most of which was accomplished by setting the color of the grid lines and frame to white:

$.plot($("#plot"), [data], {
    bars: {show: true},
    grid: {
        backgroundColor: "#ffffff",
        borderColor: "#ffffff",
        tickColor: "#ffffff"
    },
    yaxis: { ticks: 0 }
});