/** * Liquid Canvas jQuery Plugin * * Version 0.3 * * Steffen Rusitschka http://www.ruzee.com MIT licensed */ (function($) { var canvasElements = []; var pollCounter = 0; var plugins = {}; function Area(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; } }; })(); function newPlugin(hash, opts) { return $.extend({}, Plugin, hash, { opts: opts, savedOpts: opts }); } function pluginFromPlugins(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 ... function pluginFromName(name, opts) { var plugin = plugins[name]; if (!plugin) throw "Unknown plugin: " + name; opts = $.extend({}, plugin.defaultOpts || {}, opts); return newPlugin(plugin, opts); } function parse(s) { s += " "; var index = 0; function err(m) { msg = m + " at " + index + ": ..." + s.substring(index) + "\nin " + s; alert(msg); throw msg; } function cur() { return s.charAt(index); } function next() { if (index > s.length) throw("Unexpected end"); return s.charAt(index + 1) } function eat() { return s.charAt(index++); } function skipWhite() { while (/\s/.exec(cur())) eat(); } function check(c) { skipWhite(); for (var i=0; i"); var action = parseAction(); actors.setAction(action); return actors; } function parseApplications() { var applications = []; while (true) { applications.push(parseApplication()); skipWhite(); if (cur() != ",") break; check(","); } return pluginFromApplications(applications); } return parseApplications(); } function checkResize(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(); if (force || canvas.width != w || canvas.height != h || canvas.offsetTop != container.offsetTop || canvas.offsetLeft != container.offsetLeft) { pollCounter = 100; $canvas.css({ left: container.offsetLeft + "px", top: container.offsetTop + "px" }); canvas.width = w; canvas.height = h; var area = new Area(canvas); area.save(); data.paint(area); area.restore(); } } function checkAllResize(force) { $.each(canvasElements, function() { checkResize(this, force); }); } function poll(){ checkAllResize(); pollCounter--; if (pollCounter < 0) { pollCounter = 0; setTimeout(poll, 1000); } else { setTimeout(poll, 1000 / 60); } } jQuery.fn.extend({ liquidCanvas: function(func) { this.each(function() { var canvas; if (window.G_vmlCanvasManager) { $(this).before('
'); canvas = G_vmlCanvasManager.initElement($(this).prev("div").get(0)); } else { $(this).before(''); canvas = $(this).prev("canvas").get(0); } 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);