/** * Liquid Canvas jQuery Plugin * * Version 0.1 * * Steffen Rusitschka http://www.ruzee.com MIT licensed */ (function($) { var canvasElements = []; var pollCounter = 0; var plugins = {}; var Area = function(canvas) { var stack = []; $.extend(this, { width: canvas.width, height: canvas.height, ctx: canvas.getContext("2d"), save: function() { this.ctx.save(); stack.push({ width: this.width, height: this.height }); }, restore: function() { this.ctx.restore(); $.extend(this, stack.pop()); } }); }; var Plugin = function() { var shrink = function(area, steps) { area.ctx.translate(steps, steps); area.width -= 2 * steps; area.height -= 2 * steps; }; return { action:{ paint:function(){} }, // provide a NOP "plugin" shrink: shrink, defaultShrink: shrink, setAction: function(action) { this.action = action; } }; }(); var newPlugin = function(hash, opts) { return $.extend({}, Plugin, hash, { opts: opts, savedOpts: opts }); }; var pluginFromPlugins = function(plugins) { return newPlugin({ paint: function(area) { area.save(); this.action.opts = $.extend(true, this.action.savedOpts); $.each(plugins, function() { this.paint(area); }); area.restore(); }, setAction: function(action) { this.action = action; // should call super if it existed ... $.each(plugins, function() { this.action = action; }); } }); }; var pluginFromApplications = pluginFromPlugins; // it just does the same ... var pluginFromName = function(name, opts) { var plugin = plugins[name]; if (!plugin) throw "Unknown plugin: " + name; opts = $.extend({}, plugin.defaultOpts || {}, opts); return newPlugin(plugin, opts); }; var parse = function(s) { s += " "; var index = 0; var err = function(m) { msg = m + " at " + index + ": ..." + s.substring(index) + "\nin " + s; alert(msg); throw msg; } var cur = function() { return s.charAt(index); }; var next = function() { if (index > s.length) throw("Unexpected end"); return s.charAt(index + 1) }; var eat = function() { return s.charAt(index++); }; var skipWhite = function() { while (/\s/.exec(cur())) eat(); }; var check = function(c) { skipWhite(); for (var i=0; i"); var action = parseAction(); actors.setAction(action); return actors; }; var parseApplications = function() { var applications = []; while (true) { applications.push(parseApplication()); skipWhite(); if (cur() != ",") break; check(","); } return pluginFromApplications(applications); } return parseApplications(); }; var checkResize = function(container, force) { var $container = $(container); var data = $container.data('liquid-canvas'); if (!data) return; var canvas = data.canvas; var $canvas = $(canvas); var w = $container.outerWidth(); var h = $container.outerHeight(); var x = $container.offset().left; var y = $container.offset().top; if (force || canvas.width != w || canvas.height != h || $canvas.offset().top != y || $canvas.offset().left != x) { pollCounter = 100; $canvas.css($container.offset()); canvas.width = w; canvas.height = h; var area = new Area(canvas); area.save(); data.paint(area); area.restore(); } }; var checkAllResize = function(force) { $.each(canvasElements, function() { checkResize(this, force); }); }; var poll = function(){ checkAllResize(); pollCounter--; if (pollCounter < 0) { pollCounter = 0; setTimeout(poll, 1000); } else { setTimeout(poll, 1000 / 60); } }; jQuery.fn.extend({ liquidCanvas: function(func) { var args = $.makeArray(arguments); this.each(function() { var $canvas = $(''); var canvas = $canvas.get(0); $(this).before($canvas); if (window.G_vmlCanvasManager) { canvas = G_vmlCanvasManager.initElement(canvas); } var paint; if ($.isFunction(func)) { paint = func; } else { var plugin = parse(func) paint = function(area) { plugin.paint(area); }; } $(this).data("liquid-canvas", { "canvas": canvas, "paint": paint }); $(this).css({ background: "transparent" }); if ($(this).css("position") != "absolute") $(this).css({ position: "relative" }); canvasElements.push(this); checkResize(this, true); }); } }); jQuery.extend({ registerLiquidCanvasPlugin: function(plugin) { plugins[plugin.name] = $.extend({}, Plugin, plugin); } }); $(document).ready(checkAllResize); poll(); })(jQuery);