Question

I have the following fiddle which distills an issue I am having with a larger project

http://jsfiddle.net/zhaocnus/6N3v8/

in Firefox and Safari, this animation will start having a jittering effect left and right on odd zoom levels (zoom in/out using Ctrl+/- or Cmd+/- on Mac). I believe this is do to sub-pixel rendering issues and the differences between the various browsers round up or down pixels during the zoom calculations, but I have no idea how to fix it and am looking for any suggestions.

I can't use more modern CSS3 animation features as I need to support legacy browsers like IE7.

(code from fiddle below, can't seem to post without it, although not sure it makes sense without CSS and HTML)

// js spritemap animation
// constants
var COUNTER_MAX = 9,
    OFFSET = -50,
    FRAMERATE = 100;

// variables
var _counter = 0,
    _animElm = document.getElementById('animation'),
    _supportBgPosX = false;

// functions    
function play() {
    // update counter
    _counter++;
    if (_counter > COUNTER_MAX) {
        _counter = 0;
    }

    // show current frame
    if (_supportBgPosX) {
        _animElm.style.backgroundPositionX = (_counter * OFFSET) + 'px';
    } else {
        _animElm.style.backgroundPosition = (_counter * OFFSET) + 'px 0';
    }

    // next frame    
    setTimeout(play, FRAMERATE);
}

// check if browser support backgroundPositionX
if (_animElm.style.backgroundPositionX != undefined) {
    _supportBgPosX = true;
}

// start animation
play();
Was it helpful?

Solution

Instead of moving the background to the new frame, have a canvas tag re-draw the frame. The canvas tag handles sub-pixel interpretation independent of the browser and because of this you not only control the render (browser agnostic) but also solve the jitter issue as it's being re-drawn frame-by-frame into the canvas' dimensions in realtime.

Zooming is specifically tough because there's no reliable way to detect the zoom level from the browser using jQuery or plain-ole javascript.

Check out the demo here: http://jsfiddle.net/zhaocnus/Gr9TF/

*Credit goes to my coworker zhaocnus for the solution. I'm simply answering this question on his behalf.

// js spritemap animation
// constants
var COUNTER_MAX = 14,
    OFFSET = -200,
    FRAMERATE = 100;

// variables
var _counter = 0,
    _sprite = document.getElementById("sprite"),
    _canvas = document.getElementById("anim-canvas"),
    _ctx = _canvas.getContext("2d"),
    _img = null;

// functions    
function play() {
    // update counter
    _counter++;
    if (_counter > COUNTER_MAX) {
        _counter = 0;
    }

    // show current frame
    _ctx.clearRect(0, 0, _canvas.width, _canvas.height);
    _ctx.drawImage(_img, _counter * OFFSET, 0);

    // next frame    
    setTimeout(play, FRAMERATE);
}

function getStyle(oElm, strCssRule) {
    var strValue = '';
    if (document.defaultView && document.defaultView.getComputedStyle) {
        strValue = document.defaultView.getComputedStyle(oElm, null).getPropertyValue(strCssRule);
    } else if (oElm.currentStyle) {
        var strCssRule = strCssRule.replace(_styleRegExp, function (strMatch, p1) {
            return p1.toUpperCase();
        });
        strValue = oElm.currentStyle[strCssRule];
    }
    return String(strValue);
}

function initCanvas(callback) {
    var url = getStyle(_sprite, 'background-image');
        url = url.replace(/^url\(["']?/, '').replace(/["']?\)$/, '');
    _img = new Image();
    _img.onload = function(){
        _ctx.drawImage(_img, 0, 0); 
        callback();
    };
    _img.src = url;
}

// start animation
initCanvas(play);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top