canvas drawer with prerender buffer

by mmis1000

HTML

<div id='main_wrap'>
    <canvas id='main' width='450' height='600'></canvas>
    <br/>
    <input type='button' value='toggle' id='toggle'></input>
    <input type='button' value='play / pass' id='play'></input>
    <br/>
    <span id='renderId'>-</span>
</div>

<div id='loader_out' class='loader'></div>
<div id='loader_in' class='loader'>now loading...
    <br/><span id='current'>? / ?</span>
</div>

CSS

canvas {
    border:1px solid;
}
#main_wrap {
    margin:0 auto;
    text-align:center;
}
#loader_out {
    background:rgba(127, 127, 127, 0.8);
    position:fixed;
    top:0px;
    bottom:0px;
    left:0px;
    right:0px;
}
#loader_in {
    position:fixed;
    bottom:50%;
    left:0px;
    right:0px;
    text-align:center;
    color:white;
}

JavaScript

/**Stage class for handle/wrap all image control*/

var render = {};
(function (render) {
    render.createRepeatImage = function createRepeatImage(origin, originX, originY, originWidth, originHeight, repeatedX, repeatedY, resizeOriginX, resizeOriginY) {
        var canva, ctx, image, xRepeatTime, yRepeatTime, i, j, xShift, yShift;
        resizeOriginX = resizeOriginX || originWidth;
        resizeOriginY = resizeOriginY || originHeight;
        canva = document.createElement('canvas');
        image = new Image();
        canva.width = repeatedX;
        canva.height = repeatedY;
        ctx = canva.getContext('2d');
        xRepeatTime = Math.ceil(repeatedX / resizeOriginX);
        yRepeatTime = Math.ceil(repeatedY / resizeOriginY);
        ctx.setTransform(resizeOriginX / originWidth, 0, 0, resizeOriginY / originHeight, 0, 0);
        for (i = 0; i < xRepeatTime; i++) {
            for (j = 0; j < yRepeatTime; j++) {
                xShift = i * originWidth;
                yShift = j * originHeight;
                ctx.drawImage(origin, originX, originY, originWidth, originHeight, xShift, yShift, originWidth, originHeight);
            }
        }
        
        image.src = canva.toDataURL();
        return image;
    }
    var _renderList = {};
    var renderCount = 0;
    function _renderThreadFactory(id, renderer) {
        function sRenderThread(tick) {
            if (_renderList[id].playing) {
                renderer(tick + _renderList[id].iShift);
                _renderList[id].frameId = requestAnimationFrame(sRenderThread);
                _renderList[id].lastTime = tick;
            }
        }
        return sRenderThread;
    }
    render.setRender = function setRender(renderThread, shift) {
        var renderNow = renderCount;
        shift = shift || 0;
        renderCount++;
        function getFirstRender (id, renderer) {
            function firstThread (tick) {
                _renderList[id].iShift = _renderList[id].shift - tick;
     ...