topical media & game development

talk show tell print

graphic-canvas-util-liquid-liquid-canvas.js / js



  
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<c.length; ++i) {
          if (cur() != c.charAt(i)) err("Expected '" + c.charAt(i) + "' found '" + cur() + "'"); 
          eat();
        }
      }
  
      //var parseApplications; // forward reference
      
      function parseWord() {
        skipWhite();
        for (var word = []; /\w/.exec(cur()); word.push(eat()));
        return word.join("");
      }
      
      function parseNumber() {
        skipWhite();
        for (var n = []; /\d/.exec(cur()); n.push(eat()));
        return parseInt(n.join(""));
      }
      
      function parseString() {
        skipWhite();
        var s = [], start = cur();
        if (/[^\'\"]/.exec(start)) { err("String expected") }
        eat();
        while (cur() != start) { if (cur() == "\\") s.eat(); s.push(eat()); }
        check(start);
        return s.join("");
      }
      
      // Yeah, strange thing - this does the CSS value like parsing
      function parseValue() {
        skipWhite();
        for (var s = []; /[^;}]/.exec(cur()); s.push(eat()));
        return s.join("");
      }
      
      function parseLiteral() {
        skipWhite();
        if (/\d/.exec(cur())) return parseNumber();
        if (/['"]/.exec(cur())) return parseString();
        return parseValue();
      }
      
      function parseOpts() {
        check("{");
        skipWhite();
        var opts = {};
        while (cur() != "}") {
          var key = parseWord();
          check(":");
          opts[key] = parseLiteral();
          skipWhite();
          if (cur() == "}") break;
          check(";");
        }
        check("}");
        return opts;
      }
      
      function parsePlugin() {
        var name = parseWord();
        skipWhite();
        opts = cur() == "{" ? parseOpts() : {};
        return pluginFromName(name, opts);
      }
      
      function parsePlugins() {
        check("[");
        skipWhite();
        var plugins = [];
        while (cur() != "]") {
          plugins.push(parsePlugin());
          skipWhite();
        }
        check("]");
        return pluginFromPlugins(plugins);
      }
  
      function parseActors() {
        skipWhite();
        return cur() == "[" ? parsePlugins() : parsePlugin();
      }
      
      function parseAction() {
        var action;
        skipWhite();
        if (cur() == "(") {
          eat();
          action = parseApplications();
          check(")");
        } else {
          action = parsePlugin();
        }
        return action;
      }
      
      function parseApplication() {
        var actors = parseActors();
        check("=>");
        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('<div width="0" height="0" style="position:absolute; top:0px; left:0px;"></div>');
            canvas = G_vmlCanvasManager.initElement(this.prev("div").get(0));
          } else {
            this.before('<canvas width="0" height="0" style="position:absolute; top:0px; left:0px;"></canvas>');
            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);
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.