JAVASCRIPT   22

liquid-canvas.js

Guest on 5th August 2021 05:10:56 PM

  1. /**
  2.  * Liquid Canvas jQuery Plugin
  3.  *
  4.  * Version 0.3
  5.  *
  6.  * Steffen Rusitschka  http://www.ruzee.com  MIT licensed
  7.  */
  8. (function($) {
  9.   var canvasElements = [];
  10.   var pollCounter = 0;
  11.   var plugins = {};
  12.  
  13.   function Area(canvas) {
  14.     var stack = [];
  15.    
  16.     $.extend(this, {
  17.       width: canvas.width, height: canvas.height, ctx: canvas.getContext("2d"),
  18.      
  19.       save: function() {
  20.         this.ctx.save();
  21.         stack.push({ width: this.width, height: this.height });
  22.       },
  23.      
  24.       restore: function() {
  25.         this.ctx.restore();
  26.         $.extend(this, stack.pop());
  27.       }
  28.     });
  29.   }
  30.  
  31.   var Plugin = (function() {
  32.     var shrink = function(area, steps) {
  33.       area.ctx.translate(steps, steps);
  34.       area.width -= 2 * steps;
  35.       area.height -= 2 * steps;
  36.     };
  37.     return {
  38.       action:{ paint:function(){} },  // provide a NOP "plugin"
  39.       shrink: shrink,
  40.       defaultShrink: shrink,
  41.       setAction: function(action) { this.action = action; }
  42.     };
  43.   })();
  44.  
  45.   function newPlugin(hash, opts) {
  46.     return $.extend({}, Plugin, hash, { opts: opts, savedOpts: opts });
  47.   }
  48.  
  49.   function pluginFromPlugins(plugins) {
  50.     return newPlugin({
  51.       paint: function(area) {
  52.         area.save();
  53.         this.action.opts = $.extend(true, this.action.savedOpts);
  54.         $.each(plugins, function() { this.paint(area); });
  55.         area.restore();
  56.       },
  57.      
  58.       setAction: function(action) {
  59.         this.action = action; // should call super if it existed ...
  60.         $.each(plugins, function() { this.action = action; });
  61.       }
  62.     });
  63.   }
  64.   var pluginFromApplications = pluginFromPlugins; // it just does the same ...
  65.  
  66.   function pluginFromName(name, opts) {
  67.     var plugin = plugins[name];
  68.     if (!plugin) throw "Unknown plugin: " + name;
  69.     opts = $.extend({}, plugin.defaultOpts || {}, opts);
  70.     return newPlugin(plugin, opts);
  71.   }
  72.  
  73.   function parse(s) {
  74.     s += " ";
  75.     var index = 0;
  76.    
  77.     function err(m) { msg = m + " at " + index + ": ..." + s.substring(index) + "\nin " + s; alert(msg); throw msg; }
  78.     function cur() { return s.charAt(index); }
  79.     function next() { if (index > s.length) throw("Unexpected end"); return s.charAt(index + 1) }
  80.     function eat() { return s.charAt(index++); }
  81.     function skipWhite() { while (/\s/.exec(cur())) eat(); }
  82.     function check(c) {
  83.       skipWhite();
  84.       for (var i=0; i<c.length; ++i) {
  85.         if (cur() != c.charAt(i)) err("Expected '" + c.charAt(i) + "' found '" + cur() + "'");
  86.         eat();
  87.       }
  88.     }
  89.  
  90.     //var parseApplications; // forward reference
  91.    
  92.     function parseWord() {
  93.       skipWhite();
  94.       for (var word = []; /\w/.exec(cur()); word.push(eat()));
  95.       return word.join("");
  96.     }
  97.    
  98.     function parseNumber() {
  99.       skipWhite();
  100.       for (var n = []; /\d/.exec(cur()); n.push(eat()));
  101.       return parseInt(n.join(""));
  102.     }
  103.    
  104.     function parseString() {
  105.       skipWhite();
  106.       var s = [], start = cur();
  107.       if (/[^\'\"]/.exec(start)) { err("String expected") }
  108.       eat();
  109.       while (cur() != start) { if (cur() == "\\") s.eat(); s.push(eat()); }
  110.       check(start);
  111.       return s.join("");
  112.     }
  113.    
  114.     // Yeah, strange thing - this does the CSS value like parsing
  115.     function parseValue() {
  116.       skipWhite();
  117.       for (var s = []; /[^;}]/.exec(cur()); s.push(eat()));
  118.       return s.join("");
  119.     }
  120.    
  121.     function parseLiteral() {
  122.       skipWhite();
  123.       if (/\d/.exec(cur())) return parseNumber();
  124.       if (/['"]/.exec(cur())) return parseString();
  125.       return parseValue();
  126.     }
  127.    
  128.     function parseOpts() {
  129.       check("{");
  130.       skipWhite();
  131.       var opts = {};
  132.       while (cur() != "}") {
  133.         var key = parseWord();
  134.         check(":");
  135.         opts[key] = parseLiteral();
  136.         skipWhite();
  137.         if (cur() == "}") break;
  138.         check(";");
  139.       }
  140.       check("}");
  141.       return opts;
  142.     }
  143.    
  144.     function parsePlugin() {
  145.       var name = parseWord();
  146.       skipWhite();
  147.       opts = cur() == "{" ? parseOpts() : {};
  148.       return pluginFromName(name, opts);
  149.     }
  150.    
  151.     function parsePlugins() {
  152.       check("[");
  153.       skipWhite();
  154.       var plugins = [];
  155.       while (cur() != "]") {
  156.         plugins.push(parsePlugin());
  157.         skipWhite();
  158.       }
  159.       check("]");
  160.       return pluginFromPlugins(plugins);
  161.     }
  162.  
  163.     function parseActors() {
  164.       skipWhite();
  165.       return cur() == "[" ? parsePlugins() : parsePlugin();
  166.     }
  167.    
  168.     function parseAction() {
  169.       var action;
  170.       skipWhite();
  171.       if (cur() == "(") {
  172.         eat();
  173.         action = parseApplications();
  174.         check(")");
  175.       } else {
  176.         action = parsePlugin();
  177.       }
  178.       return action;
  179.     }
  180.    
  181.     function parseApplication() {
  182.       var actors = parseActors();
  183.       check("=>");
  184.       var action = parseAction();
  185.       actors.setAction(action);
  186.       return actors;
  187.     }
  188.    
  189.     function parseApplications() {
  190.       var applications = [];
  191.       while (true) {
  192.         applications.push(parseApplication());
  193.         skipWhite();
  194.         if (cur() != ",") break;
  195.         check(",");
  196.       }
  197.       return pluginFromApplications(applications);
  198.     }
  199.    
  200.     return parseApplications();
  201.   }
  202.  
  203.   function checkResize(container, force) {
  204.     var $container = $(container);
  205.     var data = $container.data('liquid-canvas');
  206.     if (!data) return;
  207.     var canvas = data.canvas;
  208.     var $canvas = $(canvas);
  209.     var w = $container.outerWidth();
  210.     var h = $container.outerHeight();
  211.    
  212.     if (force ||
  213.         canvas.width != w || canvas.height != h ||
  214.         canvas.offsetTop != container.offsetTop || canvas.offsetLeft != container.offsetLeft) {
  215.       pollCounter = 100;
  216.       $canvas.css({ left: container.offsetLeft + "px", top: container.offsetTop + "px" });
  217.       canvas.width = w;
  218.       canvas.height = h;
  219.       var area = new Area(canvas);
  220.       area.save();
  221.       data.paint(area);
  222.       area.restore();
  223.     }
  224.   }
  225.  
  226.   function checkAllResize(force) {
  227.     $.each(canvasElements, function() { checkResize(this, force); });
  228.   }
  229.  
  230.   function poll(){
  231.     checkAllResize();
  232.     pollCounter--;
  233.     if (pollCounter < 0) {
  234.       pollCounter = 0;
  235.       setTimeout(poll, 1000);
  236.     } else {
  237.       setTimeout(poll, 1000 / 60);
  238.     }
  239.   }
  240.  
  241.   jQuery.fn.extend({
  242.     liquidCanvas: function(func) {
  243.       this.each(function() {
  244.         var canvas;
  245.         if (window.G_vmlCanvasManager) {
  246.           $(this).before('<div width="0" height="0" style="position:absolute; top:0px; left:0px;"></div>');
  247.           canvas = G_vmlCanvasManager.initElement($(this).prev("div").get(0));
  248.         } else {
  249.           $(this).before('<canvas width="0" height="0" style="position:absolute; top:0px; left:0px;"></canvas>');
  250.           canvas = $(this).prev("canvas").get(0);
  251.         }
  252.        
  253.         var paint;
  254.         if ($.isFunction(func)) {
  255.           paint = func;
  256.         } else {
  257.           var plugin = parse(func)
  258.           paint = function(area) { plugin.paint(area); };
  259.         }
  260.        
  261.         $(this).data("liquid-canvas", {
  262.           "canvas": canvas,
  263.           "paint": paint
  264.         });
  265.         $(this).css({ background: "transparent" });
  266.         if ($(this).css("position") != "absolute") $(this).css({ position: "relative" });
  267.        
  268.         canvasElements.push(this);
  269.         checkResize(this, true);
  270.       });
  271.     }
  272.   });
  273.  
  274.   jQuery.extend({
  275.     registerLiquidCanvasPlugin: function(plugin) {
  276.       plugins[plugin.name] = $.extend({}, Plugin, plugin);
  277.     }
  278.   });
  279.  
  280.   $(document).ready(checkAllResize);
  281.   poll();
  282. })(jQuery);

Raw Paste


Login or Register to edit or fork this paste. It's free.