Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Sonic</title>
  
  <script>
    (function(){
    var emptyFn = function(){};
    function Sonic(d) {
        this.converter = d.converter;
        this.data = d.path || d.data;
        this.imageData = [];
        this.multiplier = d.multiplier || 1;
        this.padding = d.padding || 0;
        this.fps = d.fps || 25;
        this.stepsPerFrame = ~~d.stepsPerFrame || 1;
        this.trailLength = d.trailLength || 1;
        this.pointDistance = d.pointDistance || .05;
        this.domClass = d.domClass || 'sonic';
        this.backgroundColor = d.backgroundColor || 'rgba(0,0,0,0)';
        this.fillColor = d.fillColor;
        this.strokeColor = d.strokeColor;
        this.stepMethod = typeof d.step == 'string' ?
            stepMethods[d.step] :
            d.step || stepMethods.square;
        this._setup = d.setup || emptyFn;
        this._teardown = d.teardown || emptyFn;
        this._preStep = d.preStep || emptyFn;
        this.pixelRatio = d.pixelRatio || null;
        this.width = d.width;
        this.height = d.height;
        this.fullWidth = this.width + 2 * this.padding;
        this.fullHeight = this.height + 2 * this.padding;
        this.domClass = d.domClass || 'sonic';
        this.setup();
    }
    var argTypes = Sonic.argTypes = {
        DIM: 1,
        DEGREE: 2,
        RADIUS: 3,
        OTHER: 0
    };
    var argSignatures = Sonic.argSignatures = {
        arc: [1, 1, 3, 2, 2, 0],
        bezier: [1, 1, 1, 1, 1, 1, 1, 1],
        line: [1,1,1,1]
    };
    var pathMethods = Sonic.pathMethods = {
        bezier: function(t, p0x, p0y, p1x, p1y, c0x, c0y, c1x, c1y) {
            t = 1-t;
            var i = 1-t,
                x = t*t,
                y = i*i,
                a = x*t,
                b = 3 * x * i,
                c = 3 * t * y,
                d = y * i;
            return [
                a * p0x + b * c0x + c * c1x + d * p1x,
                a * p0y + b * c0y + c * c1y + d * p1y
            ]
        },
        arc: function(t, cx, cy, radius, start, end) {
            var point = (end - start) * t + start;
            var ret = [
                (Math.cos(point) * radius) + cx,
                (Math.sin(point) * radius) + cy
            ];
            ret.angle = point;
            ret.t = t;
            return ret;
        },
        line: function(t, sx, sy, ex, ey) {
            return [
                (ex - sx) * t + sx,
                (ey - sy) * t + sy
            ]
        }
    };
    var stepMethods = Sonic.stepMethods = {
        square: function(point, i, f, color, alpha) {
            this._.fillRect(point.x - 3, point.y - 3, 6, 6);
        },
        fader: function(point, i, f, color, alpha) {
            this._.beginPath();
            if (this._last) {
                this._.moveTo(this._last.x, this._last.y);
            }
            this._.lineTo(point.x, point.y);
            this._.closePath();
            this._.stroke();
            this._last = point;
        }
    }
    Sonic.prototype = {
        calculatePixelRatio: function(){
            var devicePixelRatio = window.devicePixelRatio || 1;
            var backingStoreRatio = this._.webkitBackingStorePixelRatio
                    || this._.mozBackingStorePixelRatio
                    || this._.msBackingStorePixelRatio
                    || this._.oBackingStorePixelRatio
                    || this._.backingStorePixelRatio
                    || 1;
            return devicePixelRatio / backingStoreRatio;
        },
        setup: function() {
            var args,
                type,
                method,
                value,
                data = this.data;
            this.canvas = document.createElement('canvas');
            this._ = this.canvas.getContext('2d');
            if(this.pixelRatio == null){
                this.pixelRatio = this.calculatePixelRatio();
            }
            this.canvas.className = this.domClass;
            if(this.pixelRatio != 1){
                this.canvas.style.height = this.fullHeight + 'px';
                this.canvas.style.width = this.fullWidth + 'px';
                this.fullHeight *= this.pixelRatio;
                this.fullWidth  *= this.pixelRatio;
                this.canvas.height = this.fullHeight;
                this.canvas.width = this.fullWidth;
                this._.scale(this.pixelRatio, this.pixelRatio);
            }   else{
                this.canvas.height = this.fullHeight;
                this.canvas.width = this.fullWidth;
            }
            this.points = [];
            for (var i = -1, l = data.length; ++i < l;) {
                args = data[i].slice(1);
                method = data[i][0];
                if (method in argSignatures) for (var a = -1, al = args.length; ++a < al;) {
                    type = argSignatures[method][a];
                    value = args[a];
                    switch (type) {
                        case argTypes.RADIUS:
                            value *= this.multiplier;
                            break;
                        case argTypes.DIM:
                            value *= this.multiplier;
                            value += this.padding;
                            break;
                        case argTypes.DEGREE:
                            value *= Math.PI/180;
                            break;
                    };
                    args[a] = value;
                }
                args.unshift(0);
                for (var r, pd = this.pointDistance, t = pd; t <= 1; t += pd) {
                    // Avoid crap like 0.15000000000000002
                    t = Math.round(t*1/pd) / (1/pd);
                    args[0] = t;
                    r = pathMethods[method].apply(null, args);
                    this.points.push({
                        x: r[0],
                        y: r[1],
                        progress: t
                    });
                }
            }
            this.frame = 0;
            if (this.converter && this.converter.setup) {
                this.converter.setup(this);
            }
        },
        prep: function(frame) {
            if (frame in this.imageData) {
                return;
            }
            this._.clearRect(0, 0, this.fullWidth, this.fullHeight);
            this._.fillStyle = this.backgroundColor;
            this._.fillRect(0, 0, this.fullWidth, this.fullHeight);
            var points = this.points,
                pointsLength = points.length,
                pd = this.pointDistance,
                point,
                index,
                frameD;
            this._setup();
            for (var i = -1, l = pointsLength*this.trailLength; ++i < l && !this.stopped;) {
                index = frame + i;
                point = points[index] || points[index - pointsLength];
                if (!point) continue;
                this.alpha = Math.round(1000*(i/(l-1)))/1000;
                this._.globalAlpha = this.alpha;
                if (this.fillColor) {
                    this._.fillStyle = this.fillColor;
                }
                if (this.strokeColor) {
                    this._.strokeStyle = this.strokeColor;
                }
                frameD = frame/(this.points.length-1);
                indexD = i/(l-1);
                this._preStep(point, indexD, frameD);
                this.stepMethod(point, indexD, frameD);
            } 
            this._teardown();
            this.imageData[frame] = (
                this._.getImageData(0, 0, this.fullWidth, this.fullWidth)
            );
            return true;
        },
        draw: function() {
            if (!this.prep(this.frame)) {
                this._.clearRect(0, 0, this.fullWidth, this.fullWidth);
                this._.putImageData(
                    this.imageData[this.frame],
                    0, 0
                );
            }
            if (this.converter && this.converter.step) {
                this.converter.step(this);
            }
            if (!this.iterateFrame()) {
                if (this.converter && this.converter.teardown) {
                    this.converter.teardown(this);
                    this.converter = null;
                }
            }
        },
        iterateFrame: function() {
            this.frame += this.stepsPerFrame;
            if (this.frame >= this.points.length) {
                this.frame = 0;
                return false;
            }
            return true;
        },
        play: function() {
            this.stopped = false;
            var hoc = this;
            this.timer = setInterval(function(){
                hoc.draw();
            }, 1000 / this.fps);
        },
        stop: function() {
            this.stopped = true;
            this.timer && clearInterval(this.timer);
        }
    };
    window.Sonic = Sonic;
}());
  </script>
</head>
  <body>
  
</body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers