This is my first attempt at a jQuery plugin.  Any tips or comments in regards the the plugin setup would be appreciated.  I'm also looking for a general review over the code itself. I'm wondering if there is a better way to encode the font.  The way I'm doing it now makes it easy to see, read and create the characters, but it's bulky.One item to note it the font is not yet complete, but most screens/animations have what they need. I should have the font finished out in the next few days.You can see a working ANSI animated screen here. There is a known issue with IE that prevents this from working. I know the fix, but just haven't gotten doing it yet.The full font is not listed here as it's too large to post. A full listing is here. Only the majority of the font has been removed from the listing below.(function ($) {    var methods = {        init: function (options) {            return this.each(function () {                var $this = $(this);                $this.addClass('ansiScreen');                var data = $this.data('ansi');                if (!data) {                    data = new Object();                    data.target = $this;                    data.fontheight = 16;                    data.fontwidth = 8;                    data.canvas = $('<canvas width=' + (data.fontwidth * 80) + 'px height=' + (data.fontheight * 25) + 'px>');                    $this.append(data.canvas);                    data.ctx = data.canvas[0].getContext('2d');                    data.processInterval = null;                    data.ansi = null;                    data.ansiCode = null;                    data.ansiPos = 0;                    data.fgcolor = 'rgb(255, 255, 255)';                    data.bgcolor = 'rgb(0, 0, 0)';                    data.bold = false;                    data.blink = false;                    data.pos = [0, 0];                    data.savepos = [0, 0];                    data.screen = Array();                    data.last = 0;                    for (var i = 0; i < 25; i++) {                        data.screen.push(Array());                        for (var j = 0; j < 80; j++) {                            data.screen[i].push([data.bgcolor, data.fgcolor, ' ', false, true]);                        }                    }                    $this.data('ansi', data);                }            });        },        destroy: function () {            return this.each(function () {                var $this = $(this);                var data = $this.data('ansi');                // Clean up                $(window).unbind('.ansi');                data.tooltip.remove();                $this.removeData('ansi');            });        },        load: function (ansiUrl) {            return this.each(function () {                var $this = $(this);                var me = this;                $.ajax({                    'url': ansiUrl,                    'data': 'text',                    beforeSend: function (jqXHR, settings) {                        jqXHR.overrideMimeType('text/plain; charset=x-user-defined');                    },                    success: function(ansiData) {                        var data = $this.data('ansi');                        if (data.processInterval != null) {                            clearInterval(data.processInterval);                            clearInterval(data.screenInterval);                        }                        data.ansi = ansiData;                        data.ansiPos = 0;                        data.fgcolor = 'rgb(255, 255, 255)';                        data.bgcolor = 'rgb(0, 0, 0)';                        data.bold = false;                        data.blink = false;                        data.pos = [0, 0];                        data.savepos = [0, 0];                        var interval = setInterval(function () {                            processAnsi.call(me);                        }, 5);                        data.processInterval = interval;                        $this.data('ansi', data);                        updateDisplay.call(me);                    }                });            });        }    };    $.fn.ansi = function (method) {        // Method calling logic        if (methods[method]) {            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));        } else if (typeof method === 'object' || !method) {            return methods.init.apply(this, arguments);        } else {            $.error('Method ' + method + ' does not exist on jQuery.ansi');        }    };    // Process a byte from teh ansi data    function processAnsi() {        var $this = $(this);        var data = $this.data('ansi');        if (data.ansiPos > data.ansi.length)        {            clearInterval(data.processInterval);            return;        }        var code = data.ansi.charCodeAt(data.ansiPos) & 0xff;        data.ansiPos += 1;        $this.data('ansi', data);        var display = true;        if (code < 33 || code > 126)        {            switch (code)            {                case 0: display = false; break;                case 10: display = false; cursorStartOfLine.call(this); break;                case 13: display = false; cursorDown.call(this, 1); break;                case 27: display = false; ansiCode.call(this); break;                default: display = true; break;            }        }        if (display) {            putCharacter.call(this, code);        }        updateDisplay.call(this);    }    function ansiCode() {        var $this = $(this);        var data = $this.data('ansi');        if (data.ansiPos > data.ansi.length)            return '-';        var valid = /^[0-9;HABCDRsuJKmh]$/;        var end = /^[HABCDRsuJKmh]$/;        var char = data.ansi[data.ansiPos];        var escape = '';        if (char == '[')        {            var stop = false;            do {                data.ansiPos += 1;                var char = data.ansi[data.ansiPos];                escape += char;                stop = end.test(char);            } while (valid.test(char) && !stop)            data.ansiPos += 1;        }        switch(escape[escape.length - 1])        {            case 'J': // Clear screen                if (escape == '2J') {                    clearDisplay.call(this);                }                break;            case 'A': // Move up                var lines = parseInt(escape.substring(0, escape.length - 1));                if (isNaN(lines)) { lines = 1; }                data.pos[1] -= lines;                if (data.pos[1] < 0) { data.pos[1] = 0; }                break;            case 'B': // Move down                var lines = parseInt(escape.substring(0, escape.length - 1));                if (isNaN(lines)) { lines = 1; }                cursorDown.call(this, lines);                break;            case 'C': // Move Forward                var spaces = parseInt(escape.substring(0, escape.length - 1));                if (isNaN(spaces)) { spaces = 1; }                cursorForward.call(this, spaces);                break;            case 'D': // Move back                var spaces = parseInt(escape.substring(0, escape.length - 1));                if (isNaN(spaces)) { lines = 1; }                data.pos[0] -= spaces;                if (data.pos[0] < 0) { data.pos[0] = 0; }                break;            case 'H': // Move To                var codes = escape.substring(0, escape.length - 1).split(';');                if (isNaN(codes[0])) { codes[0] = 1; }                if (isNaN(codes[1])) { codes[1] = 1; }                data.pos[0] = codes[1] - 1;                data.pos[1] = codes[0] - 1;                break;            case 'K': // Clear                var mode = parseInt(escape.substring(0, escape.length - 1));                if (isNaN(mode)) { mode = 0; }                switch (mode)                {                    case 2: // clear current line                        for (var i=0; i< data.screen[0].length; i++)                        {                            data.screen[data.pos[1]][i] = [data.bgcolor, data.fgcolor, 32, false, true];                        }                        break;                    case 1: // clear start of line                        for (var i=0; i< data.pos[1]; i++)                        {                            data.screen[data.pos[1]][i] = [data.bgcolor, data.fgcolor, 32, false, true];                        }                        break;                    case 0: // clear end of line                    default:                        for (var i=data.pos[1]; i< data.screen[0].length; i++)                        {                            data.screen[data.pos[1]][i] = [data.bgcolor, data.fgcolor, 32, false, true];                        }                        break;                }                break;            case 's': // Save position                data.savepos[0] = data.pos[0];                data.savepos[1] = data.pos[1];                break;            case 'u': // Restore position                data.pos[0] = data.savepos[0];                data.pos[1] = data.savepos[1];                break;            case 'm': // Change attrinutes                var codes = escape.substring(0, escape.length - 1).split(';');                for (var i=0; i < codes.length; i++) {                    var code = codes[i];                    switch (code) {                        case '0':                            data.bold = false;                            data.blink = false;                            data.fgcolor = 'rgb(255, 255, 255)';                            data.bgcolor = 'rgb(0, 0, 0)';                            break;                        case '1':                            data.bold = true;                            break;                        case '5':                            data.blink = true;                            break;                        case '30':                            data.fgcolor = !data.bold ? 'rgb(0, 0, 0)' : 'rgb(85, 85, 85)';                            break;                        case '31':                            data.fgcolor = !data.bold ? 'rgb(170, 0, 0)' : 'rgb(255, 85, 85)';                            break;                        case '32':                            data.fgcolor = !data.bold ? 'rgb(0, 170, 0)' : 'rgb(85, 255, 85)';                            break;                        case '33':                            data.fgcolor = !data.bold ? 'rgb(170, 85, 0)' : 'rgb(255, 255, 0)';                            break;                        case '34':                            data.fgcolor = !data.bold ? 'rgb(0, 0, 170)' : 'rgb(85, 85, 255)';                            break;                        case '35':                            data.fgcolor = !data.bold ? 'rgb(170, 0, 170)' : 'rgb(255, 85, 255)';                            break;                        case '36':                            data.fgcolor = !data.bold ? 'rgb(0, 170, 170)' : 'rgb(85, 255, 255)';                            break;                        case '37':                            data.fgcolor = !data.bold ? 'rgb(170, 170, 170)' : 'rgb(255, 255, 255)';                            break;                        case '40':                            data.bgcolor = 'rgb(0, 0, 0)';                            break;                        case '41':                            data.bgcolor = 'rgb(170, 0, 0)';                            break;                        case '42':                            data.bgcolor = 'rgb(0, 170, 0)';                            break;                        case '43':                            data.bgcolor = 'rgb(170, 85, 0)';                            break;                        case '44':                            data.bgcolor = 'rgb(0, 0, 170)';                            break;                        case '45':                            data.bgcolor = 'rgb(170, 0, 170)';                            break;                        case '46':                            data.bgcolor = 'rgb(0, 170, 170)';                            break;                        case '47':                            data.bgcolor = 'rgb(170, 170, 170)';                            break;                        default:                            $('#debug').html($('#debug').html() + '<br>Unknown Attribute: ' + code);                            break;                    }                }                break;            default:                $('#debug').html($('#debug').html() + '<br>esc[' + escape);                break;        }        $this.data('ansi', data);        return '';    }    // Move the cursor position up a number of lines    function cursorStartOfLine(lines) {        var $this = $(this);        var data = $this.data('ansi');        data.pos[0] = 0;        $this.data('ansi', data);    }    // Move the cursor position down a number of lines    // scroll the screen if needed    function cursorDown(lines) {        var $this = $(this);        var data = $this.data('ansi');        var rows = data.screen.length;        var cols = data.screen[0].length;        data.pos[1] += lines;        if (data.pos[1] > data.screen.length - 1) {            data.pos[1] = rows - 1;            for (var i = 0; i < rows - 1; i++) {                for (var j = 0; j < cols; j++) {                    data.screen[i][j] = data.screen[i+1][j];                    data.screen[i][j][4] = true;                }            }            for (var j = 0; j < cols; ++j) {                data.screen[rows-1][j] = [data.bgcolor, data.fgcolor, 32, false, true];            }        }        $this.data('ansi', data);    }    // Move the cursor position forward a number of columns    function cursorForward(cols) {        var $this = $(this);        var data = $this.data('ansi');        data.pos[0] += cols;        if (data.pos[0] > data.screen[0].length - 1) {                data.pos[0] = 0;                cursorDown.call(this,1);        }        $this.data('ansi', data);    }    // Puts a character on screen    function putCharacter(charCode) {        var $this = $(this);        var data = $this.data('ansi');        data.screen[data.pos[1]][data.pos[0]] = [data.bgcolor, data.fgcolor, charCode, data.blink, true];        $this.data('ansi', data);        // Move forward 1 character        cursorForward.call(this, 1);    }    // Clear the screen    function clearDisplay() {        var $this = $(this);        var data = $this.data('ansi');        for (var i = 0; i < data.screen.length; i++) {            for (var j = 0; j < data.screen[i].length; j++) {                data.screen[i][j] = [data.bgcolor, data.fgcolor, ' ', data.blink, true];            }        }        data.pos = [0, 0];        $this.data('ansi', data);    }    // Update the container with the current screen    function updateDisplay() {        var $this = $(this);        var data = $this.data('ansi');        for (var i = 0, length1 = data.screen.length; i < length1; ++i) {            var a = data.screen[i]; // cache object            for (var j = 0, length2 = a.length; j < length2; ++j) {                if (a[j][4])                {                    data.ctx.save();                    data.ctx.beginPath();                    data.ctx.rect (data.fontwidth * j, data.fontheight * i, data.fontwidth, data.fontheight);                    data.ctx.clip();                    data.ctx.fillStyle = a[j][0];                    data.ctx.fillRect (data.fontwidth * j, data.fontheight * i, data.fontwidth, data.fontheight);                    data.ctx.fillStyle = a[j][1];                    drawCharater.call(this, a[j][2], [data.fontwidth * j, data.fontheight * i], 1);                    data.ctx.restore();                    a[j][4] = false;                }            }        }        $this.data('ansi', data);    }    // Draw a single character at a given location    function drawCharater(code, location, size) {        var $this = $(this);        var data = $this.data('ansi');        var template = new Array();        switch(code)        {            case 32:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 48:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,1,1,1,1,0,0]);                template.push([0,1,1,0,0,1,1,0]);                template.push([1,1,0,0,0,0,1,1]);                template.push([1,1,0,0,0,0,1,1]);                template.push([1,1,0,1,1,0,1,1]);                template.push([1,1,0,1,1,0,1,1]);                template.push([1,1,0,0,0,0,1,1]);                template.push([1,1,0,0,0,0,1,1]);                template.push([0,1,1,0,0,1,1,0]);                template.push([0,0,1,1,1,1,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 49:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,1,1,1,0,0,0]);                template.push([0,1,1,1,1,0,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,1,1,1,1,1,1,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 50:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,1,1,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,1,1,0,0,0,0]);                template.push([0,1,1,0,0,0,0,0]);                template.push([1,1,0,0,0,0,0,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,1,1,1,1,1,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 51:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,1,1,1,1,0,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 52:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,1,1,0,0]);                template.push([0,0,0,1,1,1,0,0]);                template.push([0,0,1,1,1,1,0,0]);                template.push([0,1,1,0,1,1,0,0]);                template.push([1,1,0,0,1,1,0,0]);                template.push([1,1,1,1,1,1,1,0]);                template.push([0,0,0,0,1,1,0,0]);                template.push([0,0,0,0,1,1,0,0]);                template.push([0,0,0,0,1,1,0,0]);                template.push([0,0,0,1,1,1,1,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 53:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([1,1,1,1,1,1,1,0]);                template.push([1,1,0,0,0,0,0,0]);                template.push([1,1,0,0,0,0,0,0]);                template.push([1,1,0,0,0,0,0,0]);                template.push([1,1,1,1,1,1,0,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 54:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,1,1,1,1,0,0]);                template.push([0,1,1,0,0,0,0,0]);                template.push([1,1,0,0,0,0,0,0]);                template.push([1,1,0,0,0,0,0,0]);                template.push([1,1,1,1,1,1,0,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 55:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([1,1,1,1,1,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,1,1,0,0]);                template.push([0,0,0,1,1,0,0,0]);                template.push([0,0,1,1,0,0,0,0]);                template.push([0,0,1,1,0,0,0,0]);                template.push([0,0,1,1,0,0,0,0]);                template.push([0,0,1,1,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 56:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            case 57:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,1,1,1,1,1,0,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([1,1,0,0,0,1,1,0]);                template.push([0,1,1,1,1,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,0,1,1,0]);                template.push([0,0,0,0,1,1,0,0]);                template.push([0,1,1,1,1,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;            default:                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                template.push([0,0,0,0,0,0,0,0]);                break;        }        for(var y=0; y<16; y++)        {            for(var x=0; x<8; x++)            {                if (template[y][x] == 1)                    data.ctx.fillRect(location[0] + x, location[1] + y, 1, 1);                          }        }    }})(jQuery);
jQuery to display ANSI graphics
javascript;jquery;plugin;graphics
You could use a bit more concise syntax. For example, when filling the data object in nit()`, you could use literal object notation:data = {  target: $this,  fontheight: 16,  fontwidth: 8,  canvas: $('<canvas width=' + (data.fontwidth * 80) + 'px height=' + (data.fontheight * 25) + 'px>'),   // etc.}Or use jQuery.extend(), to add or overwrite properties.You don't need to reassign the data object ($this.data('ansi', data);) after changing the the properties of data, because it's a reference and all changes have been applied to the object inside jQuery already. Example:var $example = jQuery(body);var data = {}; // Empty object$example.data(ansi, data); // Assign datavar data = $example.data(ansi); // get referencedata.test = hello;alert($example.data(ansi).test); // Shows 'hello'. No need to call $example.data(ansi, data); beforeIn destroy() you call data.tooltip.remove();, but I can't seem to see data.tooltip ever being set.You have some duplicate code, that could be refactored into a separate function, such as parsing the integers from the escape sequences.You should consider moving the actual business code parts into separate functions.The colors should be kept in an array/object instead of assigning them.(More maybe later.)