easy_pie_chart 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +109 -0
- data/LICENSE.txt +20 -0
- data/README.md +173 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/easy_pie_chart.gemspec +72 -0
- data/lib/easy_pie_chart/engine.rb +9 -0
- data/lib/easy_pie_chart/view_helper.rb +17 -0
- data/lib/easy_pie_chart.rb +2 -0
- data/spec/easy_pie_chart/view_helper_spec.rb +27 -0
- data/spec/spec_helper.rb +46 -0
- data/vendor/assets/javascripts/excanvas.js +924 -0
- data/vendor/assets/javascripts/jquery.easy-pie-chart.js +351 -0
- data/vendor/assets/javascripts/jquery.easy-pie-chart.js.coffee +316 -0
- data/vendor/assets/stylesheets/jquery.easy-pie-chart.css +10 -0
- metadata +147 -0
| @@ -0,0 +1,924 @@ | |
| 1 | 
            +
            // Copyright 2006 Google Inc.
         | 
| 2 | 
            +
            //
         | 
| 3 | 
            +
            // Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            // you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            // You may obtain a copy of the License at
         | 
| 6 | 
            +
            //
         | 
| 7 | 
            +
            //   http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
            //
         | 
| 9 | 
            +
            // Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            // distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            // See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            // limitations under the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
             | 
| 16 | 
            +
            // Known Issues:
         | 
| 17 | 
            +
            //
         | 
| 18 | 
            +
            // * Patterns are not implemented.
         | 
| 19 | 
            +
            // * Radial gradient are not implemented. The VML version of these look very
         | 
| 20 | 
            +
            //   different from the canvas one.
         | 
| 21 | 
            +
            // * Clipping paths are not implemented.
         | 
| 22 | 
            +
            // * Coordsize. The width and height attribute have higher priority than the
         | 
| 23 | 
            +
            //   width and height style values which isn't correct.
         | 
| 24 | 
            +
            // * Painting mode isn't implemented.
         | 
| 25 | 
            +
            // * Canvas width/height should is using content-box by default. IE in
         | 
| 26 | 
            +
            //   Quirks mode will draw the canvas using border-box. Either change your
         | 
| 27 | 
            +
            //   doctype to HTML5
         | 
| 28 | 
            +
            //   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
         | 
| 29 | 
            +
            //   or use Box Sizing Behavior from WebFX
         | 
| 30 | 
            +
            //   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
         | 
| 31 | 
            +
            // * Non uniform scaling does not correctly scale strokes.
         | 
| 32 | 
            +
            // * Optimize. There is always room for speed improvements.
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            // Only add this code if we do not already have a canvas implementation
         | 
| 35 | 
            +
            if (!document.createElement('canvas').getContext) {
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            (function() {
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              // alias some functions to make (compiled) code shorter
         | 
| 40 | 
            +
              var m = Math;
         | 
| 41 | 
            +
              var mr = m.round;
         | 
| 42 | 
            +
              var ms = m.sin;
         | 
| 43 | 
            +
              var mc = m.cos;
         | 
| 44 | 
            +
              var abs = m.abs;
         | 
| 45 | 
            +
              var sqrt = m.sqrt;
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              // this is used for sub pixel precision
         | 
| 48 | 
            +
              var Z = 10;
         | 
| 49 | 
            +
              var Z2 = Z / 2;
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              /**
         | 
| 52 | 
            +
               * This funtion is assigned to the <canvas> elements as element.getContext().
         | 
| 53 | 
            +
               * @this {HTMLElement}
         | 
| 54 | 
            +
               * @return {CanvasRenderingContext2D_}
         | 
| 55 | 
            +
               */
         | 
| 56 | 
            +
              function getContext() {
         | 
| 57 | 
            +
                return this.context_ ||
         | 
| 58 | 
            +
                    (this.context_ = new CanvasRenderingContext2D_(this));
         | 
| 59 | 
            +
              }
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              var slice = Array.prototype.slice;
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              /**
         | 
| 64 | 
            +
               * Binds a function to an object. The returned function will always use the
         | 
| 65 | 
            +
               * passed in {@code obj} as {@code this}.
         | 
| 66 | 
            +
               *
         | 
| 67 | 
            +
               * Example:
         | 
| 68 | 
            +
               *
         | 
| 69 | 
            +
               *   g = bind(f, obj, a, b)
         | 
| 70 | 
            +
               *   g(c, d) // will do f.call(obj, a, b, c, d)
         | 
| 71 | 
            +
               *
         | 
| 72 | 
            +
               * @param {Function} f The function to bind the object to
         | 
| 73 | 
            +
               * @param {Object} obj The object that should act as this when the function
         | 
| 74 | 
            +
               *     is called
         | 
| 75 | 
            +
               * @param {*} var_args Rest arguments that will be used as the initial
         | 
| 76 | 
            +
               *     arguments when the function is called
         | 
| 77 | 
            +
               * @return {Function} A new function that has bound this
         | 
| 78 | 
            +
               */
         | 
| 79 | 
            +
              function bind(f, obj, var_args) {
         | 
| 80 | 
            +
                var a = slice.call(arguments, 2);
         | 
| 81 | 
            +
                return function() {
         | 
| 82 | 
            +
                  return f.apply(obj, a.concat(slice.call(arguments)));
         | 
| 83 | 
            +
                };
         | 
| 84 | 
            +
              }
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              var G_vmlCanvasManager_ = {
         | 
| 87 | 
            +
                init: function(opt_doc) {
         | 
| 88 | 
            +
                  if (/MSIE/.test(navigator.userAgent) && !window.opera) {
         | 
| 89 | 
            +
                    var doc = opt_doc || document;
         | 
| 90 | 
            +
                    // Create a dummy element so that IE will allow canvas elements to be
         | 
| 91 | 
            +
                    // recognized.
         | 
| 92 | 
            +
                    doc.createElement('canvas');
         | 
| 93 | 
            +
                    doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
         | 
| 94 | 
            +
                  }
         | 
| 95 | 
            +
                },
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                init_: function(doc) {
         | 
| 98 | 
            +
                  // create xmlns
         | 
| 99 | 
            +
                  if (!doc.namespaces['g_vml_']) {
         | 
| 100 | 
            +
                    doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
         | 
| 101 | 
            +
                                       '#default#VML');
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  }
         | 
| 104 | 
            +
                  if (!doc.namespaces['g_o_']) {
         | 
| 105 | 
            +
                    doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
         | 
| 106 | 
            +
                                       '#default#VML');
         | 
| 107 | 
            +
                  }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  // Setup default CSS.  Only add one style sheet per document
         | 
| 110 | 
            +
                  if (!doc.styleSheets['ex_canvas_']) {
         | 
| 111 | 
            +
                    var ss = doc.createStyleSheet();
         | 
| 112 | 
            +
                    ss.owningElement.id = 'ex_canvas_';
         | 
| 113 | 
            +
                    ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
         | 
| 114 | 
            +
                        // default size is 300x150 in Gecko and Opera
         | 
| 115 | 
            +
                        'text-align:left;width:300px;height:150px}' +
         | 
| 116 | 
            +
                        'g_vml_\\:*{behavior:url(#default#VML)}' +
         | 
| 117 | 
            +
                        'g_o_\\:*{behavior:url(#default#VML)}';
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  }
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  // find all canvas elements
         | 
| 122 | 
            +
                  var els = doc.getElementsByTagName('canvas');
         | 
| 123 | 
            +
                  for (var i = 0; i < els.length; i++) {
         | 
| 124 | 
            +
                    this.initElement(els[i]);
         | 
| 125 | 
            +
                  }
         | 
| 126 | 
            +
                },
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                /**
         | 
| 129 | 
            +
                 * Public initializes a canvas element so that it can be used as canvas
         | 
| 130 | 
            +
                 * element from now on. This is called automatically before the page is
         | 
| 131 | 
            +
                 * loaded but if you are creating elements using createElement you need to
         | 
| 132 | 
            +
                 * make sure this is called on the element.
         | 
| 133 | 
            +
                 * @param {HTMLElement} el The canvas element to initialize.
         | 
| 134 | 
            +
                 * @return {HTMLElement} the element that was created.
         | 
| 135 | 
            +
                 */
         | 
| 136 | 
            +
                initElement: function(el) {
         | 
| 137 | 
            +
                  if (!el.getContext) {
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                    el.getContext = getContext;
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                    // Remove fallback content. There is no way to hide text nodes so we
         | 
| 142 | 
            +
                    // just remove all childNodes. We could hide all elements and remove
         | 
| 143 | 
            +
                    // text nodes but who really cares about the fallback content.
         | 
| 144 | 
            +
                    el.innerHTML = '';
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                    // do not use inline function because that will leak memory
         | 
| 147 | 
            +
                    el.attachEvent('onpropertychange', onPropertyChange);
         | 
| 148 | 
            +
                    el.attachEvent('onresize', onResize);
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                    var attrs = el.attributes;
         | 
| 151 | 
            +
                    if (attrs.width && attrs.width.specified) {
         | 
| 152 | 
            +
                      // TODO: use runtimeStyle and coordsize
         | 
| 153 | 
            +
                      // el.getContext().setWidth_(attrs.width.nodeValue);
         | 
| 154 | 
            +
                      el.style.width = attrs.width.nodeValue + 'px';
         | 
| 155 | 
            +
                    } else {
         | 
| 156 | 
            +
                      el.width = el.clientWidth;
         | 
| 157 | 
            +
                    }
         | 
| 158 | 
            +
                    if (attrs.height && attrs.height.specified) {
         | 
| 159 | 
            +
                      // TODO: use runtimeStyle and coordsize
         | 
| 160 | 
            +
                      // el.getContext().setHeight_(attrs.height.nodeValue);
         | 
| 161 | 
            +
                      el.style.height = attrs.height.nodeValue + 'px';
         | 
| 162 | 
            +
                    } else {
         | 
| 163 | 
            +
                      el.height = el.clientHeight;
         | 
| 164 | 
            +
                    }
         | 
| 165 | 
            +
                    //el.getContext().setCoordsize_()
         | 
| 166 | 
            +
                  }
         | 
| 167 | 
            +
                  return el;
         | 
| 168 | 
            +
                }
         | 
| 169 | 
            +
              };
         | 
| 170 | 
            +
             | 
| 171 | 
            +
              function onPropertyChange(e) {
         | 
| 172 | 
            +
                var el = e.srcElement;
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                switch (e.propertyName) {
         | 
| 175 | 
            +
                  case 'width':
         | 
| 176 | 
            +
                    el.style.width = el.attributes.width.nodeValue + 'px';
         | 
| 177 | 
            +
                    el.getContext().clearRect();
         | 
| 178 | 
            +
                    break;
         | 
| 179 | 
            +
                  case 'height':
         | 
| 180 | 
            +
                    el.style.height = el.attributes.height.nodeValue + 'px';
         | 
| 181 | 
            +
                    el.getContext().clearRect();
         | 
| 182 | 
            +
                    break;
         | 
| 183 | 
            +
                }
         | 
| 184 | 
            +
              }
         | 
| 185 | 
            +
             | 
| 186 | 
            +
              function onResize(e) {
         | 
| 187 | 
            +
                var el = e.srcElement;
         | 
| 188 | 
            +
                if (el.firstChild) {
         | 
| 189 | 
            +
                  el.firstChild.style.width =  el.clientWidth + 'px';
         | 
| 190 | 
            +
                  el.firstChild.style.height = el.clientHeight + 'px';
         | 
| 191 | 
            +
                }
         | 
| 192 | 
            +
              }
         | 
| 193 | 
            +
             | 
| 194 | 
            +
              G_vmlCanvasManager_.init();
         | 
| 195 | 
            +
             | 
| 196 | 
            +
              // precompute "00" to "FF"
         | 
| 197 | 
            +
              var dec2hex = [];
         | 
| 198 | 
            +
              for (var i = 0; i < 16; i++) {
         | 
| 199 | 
            +
                for (var j = 0; j < 16; j++) {
         | 
| 200 | 
            +
                  dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
         | 
| 201 | 
            +
                }
         | 
| 202 | 
            +
              }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
              function createMatrixIdentity() {
         | 
| 205 | 
            +
                return [
         | 
| 206 | 
            +
                  [1, 0, 0],
         | 
| 207 | 
            +
                  [0, 1, 0],
         | 
| 208 | 
            +
                  [0, 0, 1]
         | 
| 209 | 
            +
                ];
         | 
| 210 | 
            +
              }
         | 
| 211 | 
            +
             | 
| 212 | 
            +
              function matrixMultiply(m1, m2) {
         | 
| 213 | 
            +
                var result = createMatrixIdentity();
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                for (var x = 0; x < 3; x++) {
         | 
| 216 | 
            +
                  for (var y = 0; y < 3; y++) {
         | 
| 217 | 
            +
                    var sum = 0;
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                    for (var z = 0; z < 3; z++) {
         | 
| 220 | 
            +
                      sum += m1[x][z] * m2[z][y];
         | 
| 221 | 
            +
                    }
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                    result[x][y] = sum;
         | 
| 224 | 
            +
                  }
         | 
| 225 | 
            +
                }
         | 
| 226 | 
            +
                return result;
         | 
| 227 | 
            +
              }
         | 
| 228 | 
            +
             | 
| 229 | 
            +
              function copyState(o1, o2) {
         | 
| 230 | 
            +
                o2.fillStyle     = o1.fillStyle;
         | 
| 231 | 
            +
                o2.lineCap       = o1.lineCap;
         | 
| 232 | 
            +
                o2.lineJoin      = o1.lineJoin;
         | 
| 233 | 
            +
                o2.lineWidth     = o1.lineWidth;
         | 
| 234 | 
            +
                o2.miterLimit    = o1.miterLimit;
         | 
| 235 | 
            +
                o2.shadowBlur    = o1.shadowBlur;
         | 
| 236 | 
            +
                o2.shadowColor   = o1.shadowColor;
         | 
| 237 | 
            +
                o2.shadowOffsetX = o1.shadowOffsetX;
         | 
| 238 | 
            +
                o2.shadowOffsetY = o1.shadowOffsetY;
         | 
| 239 | 
            +
                o2.strokeStyle   = o1.strokeStyle;
         | 
| 240 | 
            +
                o2.globalAlpha   = o1.globalAlpha;
         | 
| 241 | 
            +
                o2.arcScaleX_    = o1.arcScaleX_;
         | 
| 242 | 
            +
                o2.arcScaleY_    = o1.arcScaleY_;
         | 
| 243 | 
            +
                o2.lineScale_    = o1.lineScale_;
         | 
| 244 | 
            +
              }
         | 
| 245 | 
            +
             | 
| 246 | 
            +
              function processStyle(styleString) {
         | 
| 247 | 
            +
                var str, alpha = 1;
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                styleString = String(styleString);
         | 
| 250 | 
            +
                if (styleString.substring(0, 3) == 'rgb') {
         | 
| 251 | 
            +
                  var start = styleString.indexOf('(', 3);
         | 
| 252 | 
            +
                  var end = styleString.indexOf(')', start + 1);
         | 
| 253 | 
            +
                  var guts = styleString.substring(start + 1, end).split(',');
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                  str = '#';
         | 
| 256 | 
            +
                  for (var i = 0; i < 3; i++) {
         | 
| 257 | 
            +
                    str += dec2hex[Number(guts[i])];
         | 
| 258 | 
            +
                  }
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                  if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
         | 
| 261 | 
            +
                    alpha = guts[3];
         | 
| 262 | 
            +
                  }
         | 
| 263 | 
            +
                } else {
         | 
| 264 | 
            +
                  str = styleString;
         | 
| 265 | 
            +
                }
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                return {color: str, alpha: alpha};
         | 
| 268 | 
            +
              }
         | 
| 269 | 
            +
             | 
| 270 | 
            +
              function processLineCap(lineCap) {
         | 
| 271 | 
            +
                switch (lineCap) {
         | 
| 272 | 
            +
                  case 'butt':
         | 
| 273 | 
            +
                    return 'flat';
         | 
| 274 | 
            +
                  case 'round':
         | 
| 275 | 
            +
                    return 'round';
         | 
| 276 | 
            +
                  case 'square':
         | 
| 277 | 
            +
                  default:
         | 
| 278 | 
            +
                    return 'square';
         | 
| 279 | 
            +
                }
         | 
| 280 | 
            +
              }
         | 
| 281 | 
            +
             | 
| 282 | 
            +
              /**
         | 
| 283 | 
            +
               * This class implements CanvasRenderingContext2D interface as described by
         | 
| 284 | 
            +
               * the WHATWG.
         | 
| 285 | 
            +
               * @param {HTMLElement} surfaceElement The element that the 2D context should
         | 
| 286 | 
            +
               * be associated with
         | 
| 287 | 
            +
               */
         | 
| 288 | 
            +
              function CanvasRenderingContext2D_(surfaceElement) {
         | 
| 289 | 
            +
                this.m_ = createMatrixIdentity();
         | 
| 290 | 
            +
             | 
| 291 | 
            +
                this.mStack_ = [];
         | 
| 292 | 
            +
                this.aStack_ = [];
         | 
| 293 | 
            +
                this.currentPath_ = [];
         | 
| 294 | 
            +
             | 
| 295 | 
            +
                // Canvas context properties
         | 
| 296 | 
            +
                this.strokeStyle = '#000';
         | 
| 297 | 
            +
                this.fillStyle = '#000';
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                this.lineWidth = 1;
         | 
| 300 | 
            +
                this.lineJoin = 'miter';
         | 
| 301 | 
            +
                this.lineCap = 'butt';
         | 
| 302 | 
            +
                this.miterLimit = Z * 1;
         | 
| 303 | 
            +
                this.globalAlpha = 1;
         | 
| 304 | 
            +
                this.canvas = surfaceElement;
         | 
| 305 | 
            +
             | 
| 306 | 
            +
                var el = surfaceElement.ownerDocument.createElement('div');
         | 
| 307 | 
            +
                el.style.width =  surfaceElement.clientWidth + 'px';
         | 
| 308 | 
            +
                el.style.height = surfaceElement.clientHeight + 'px';
         | 
| 309 | 
            +
                el.style.overflow = 'hidden';
         | 
| 310 | 
            +
                el.style.position = 'absolute';
         | 
| 311 | 
            +
                surfaceElement.appendChild(el);
         | 
| 312 | 
            +
             | 
| 313 | 
            +
                this.element_ = el;
         | 
| 314 | 
            +
                this.arcScaleX_ = 1;
         | 
| 315 | 
            +
                this.arcScaleY_ = 1;
         | 
| 316 | 
            +
                this.lineScale_ = 1;
         | 
| 317 | 
            +
              }
         | 
| 318 | 
            +
             | 
| 319 | 
            +
              var contextPrototype = CanvasRenderingContext2D_.prototype;
         | 
| 320 | 
            +
              contextPrototype.clearRect = function() {
         | 
| 321 | 
            +
                this.element_.innerHTML = '';
         | 
| 322 | 
            +
              };
         | 
| 323 | 
            +
             | 
| 324 | 
            +
              contextPrototype.beginPath = function() {
         | 
| 325 | 
            +
                // TODO: Branch current matrix so that save/restore has no effect
         | 
| 326 | 
            +
                //       as per safari docs.
         | 
| 327 | 
            +
                this.currentPath_ = [];
         | 
| 328 | 
            +
              };
         | 
| 329 | 
            +
             | 
| 330 | 
            +
              contextPrototype.moveTo = function(aX, aY) {
         | 
| 331 | 
            +
                var p = this.getCoords_(aX, aY);
         | 
| 332 | 
            +
                this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
         | 
| 333 | 
            +
                this.currentX_ = p.x;
         | 
| 334 | 
            +
                this.currentY_ = p.y;
         | 
| 335 | 
            +
              };
         | 
| 336 | 
            +
             | 
| 337 | 
            +
              contextPrototype.lineTo = function(aX, aY) {
         | 
| 338 | 
            +
                var p = this.getCoords_(aX, aY);
         | 
| 339 | 
            +
                this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                this.currentX_ = p.x;
         | 
| 342 | 
            +
                this.currentY_ = p.y;
         | 
| 343 | 
            +
              };
         | 
| 344 | 
            +
             | 
| 345 | 
            +
              contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
         | 
| 346 | 
            +
                                                        aCP2x, aCP2y,
         | 
| 347 | 
            +
                                                        aX, aY) {
         | 
| 348 | 
            +
                var p = this.getCoords_(aX, aY);
         | 
| 349 | 
            +
                var cp1 = this.getCoords_(aCP1x, aCP1y);
         | 
| 350 | 
            +
                var cp2 = this.getCoords_(aCP2x, aCP2y);
         | 
| 351 | 
            +
                bezierCurveTo(this, cp1, cp2, p);
         | 
| 352 | 
            +
              };
         | 
| 353 | 
            +
             | 
| 354 | 
            +
              // Helper function that takes the already fixed cordinates.
         | 
| 355 | 
            +
              function bezierCurveTo(self, cp1, cp2, p) {
         | 
| 356 | 
            +
                self.currentPath_.push({
         | 
| 357 | 
            +
                  type: 'bezierCurveTo',
         | 
| 358 | 
            +
                  cp1x: cp1.x,
         | 
| 359 | 
            +
                  cp1y: cp1.y,
         | 
| 360 | 
            +
                  cp2x: cp2.x,
         | 
| 361 | 
            +
                  cp2y: cp2.y,
         | 
| 362 | 
            +
                  x: p.x,
         | 
| 363 | 
            +
                  y: p.y
         | 
| 364 | 
            +
                });
         | 
| 365 | 
            +
                self.currentX_ = p.x;
         | 
| 366 | 
            +
                self.currentY_ = p.y;
         | 
| 367 | 
            +
              }
         | 
| 368 | 
            +
             | 
| 369 | 
            +
              contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
         | 
| 370 | 
            +
                // the following is lifted almost directly from
         | 
| 371 | 
            +
                // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                var cp = this.getCoords_(aCPx, aCPy);
         | 
| 374 | 
            +
                var p = this.getCoords_(aX, aY);
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                var cp1 = {
         | 
| 377 | 
            +
                  x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
         | 
| 378 | 
            +
                  y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
         | 
| 379 | 
            +
                };
         | 
| 380 | 
            +
                var cp2 = {
         | 
| 381 | 
            +
                  x: cp1.x + (p.x - this.currentX_) / 3.0,
         | 
| 382 | 
            +
                  y: cp1.y + (p.y - this.currentY_) / 3.0
         | 
| 383 | 
            +
                };
         | 
| 384 | 
            +
             | 
| 385 | 
            +
                bezierCurveTo(this, cp1, cp2, p);
         | 
| 386 | 
            +
              };
         | 
| 387 | 
            +
             | 
| 388 | 
            +
              contextPrototype.arc = function(aX, aY, aRadius,
         | 
| 389 | 
            +
                                              aStartAngle, aEndAngle, aClockwise) {
         | 
| 390 | 
            +
                aRadius *= Z;
         | 
| 391 | 
            +
                var arcType = aClockwise ? 'at' : 'wa';
         | 
| 392 | 
            +
             | 
| 393 | 
            +
                var xStart = aX + mc(aStartAngle) * aRadius - Z2;
         | 
| 394 | 
            +
                var yStart = aY + ms(aStartAngle) * aRadius - Z2;
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
         | 
| 397 | 
            +
                var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
         | 
| 398 | 
            +
             | 
| 399 | 
            +
                // IE won't render arches drawn counter clockwise if xStart == xEnd.
         | 
| 400 | 
            +
                if (xStart == xEnd && !aClockwise) {
         | 
| 401 | 
            +
                  xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
         | 
| 402 | 
            +
                                   // that can be represented in binary
         | 
| 403 | 
            +
                }
         | 
| 404 | 
            +
             | 
| 405 | 
            +
                var p = this.getCoords_(aX, aY);
         | 
| 406 | 
            +
                var pStart = this.getCoords_(xStart, yStart);
         | 
| 407 | 
            +
                var pEnd = this.getCoords_(xEnd, yEnd);
         | 
| 408 | 
            +
             | 
| 409 | 
            +
                this.currentPath_.push({type: arcType,
         | 
| 410 | 
            +
                                       x: p.x,
         | 
| 411 | 
            +
                                       y: p.y,
         | 
| 412 | 
            +
                                       radius: aRadius,
         | 
| 413 | 
            +
                                       xStart: pStart.x,
         | 
| 414 | 
            +
                                       yStart: pStart.y,
         | 
| 415 | 
            +
                                       xEnd: pEnd.x,
         | 
| 416 | 
            +
                                       yEnd: pEnd.y});
         | 
| 417 | 
            +
             | 
| 418 | 
            +
              };
         | 
| 419 | 
            +
             | 
| 420 | 
            +
              contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
         | 
| 421 | 
            +
                this.moveTo(aX, aY);
         | 
| 422 | 
            +
                this.lineTo(aX + aWidth, aY);
         | 
| 423 | 
            +
                this.lineTo(aX + aWidth, aY + aHeight);
         | 
| 424 | 
            +
                this.lineTo(aX, aY + aHeight);
         | 
| 425 | 
            +
                this.closePath();
         | 
| 426 | 
            +
              };
         | 
| 427 | 
            +
             | 
| 428 | 
            +
              contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
         | 
| 429 | 
            +
                var oldPath = this.currentPath_;
         | 
| 430 | 
            +
                this.beginPath();
         | 
| 431 | 
            +
             | 
| 432 | 
            +
                this.moveTo(aX, aY);
         | 
| 433 | 
            +
                this.lineTo(aX + aWidth, aY);
         | 
| 434 | 
            +
                this.lineTo(aX + aWidth, aY + aHeight);
         | 
| 435 | 
            +
                this.lineTo(aX, aY + aHeight);
         | 
| 436 | 
            +
                this.closePath();
         | 
| 437 | 
            +
                this.stroke();
         | 
| 438 | 
            +
             | 
| 439 | 
            +
                this.currentPath_ = oldPath;
         | 
| 440 | 
            +
              };
         | 
| 441 | 
            +
             | 
| 442 | 
            +
              contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
         | 
| 443 | 
            +
                var oldPath = this.currentPath_;
         | 
| 444 | 
            +
                this.beginPath();
         | 
| 445 | 
            +
             | 
| 446 | 
            +
                this.moveTo(aX, aY);
         | 
| 447 | 
            +
                this.lineTo(aX + aWidth, aY);
         | 
| 448 | 
            +
                this.lineTo(aX + aWidth, aY + aHeight);
         | 
| 449 | 
            +
                this.lineTo(aX, aY + aHeight);
         | 
| 450 | 
            +
                this.closePath();
         | 
| 451 | 
            +
                this.fill();
         | 
| 452 | 
            +
             | 
| 453 | 
            +
                this.currentPath_ = oldPath;
         | 
| 454 | 
            +
              };
         | 
| 455 | 
            +
             | 
| 456 | 
            +
              contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
         | 
| 457 | 
            +
                var gradient = new CanvasGradient_('gradient');
         | 
| 458 | 
            +
                gradient.x0_ = aX0;
         | 
| 459 | 
            +
                gradient.y0_ = aY0;
         | 
| 460 | 
            +
                gradient.x1_ = aX1;
         | 
| 461 | 
            +
                gradient.y1_ = aY1;
         | 
| 462 | 
            +
                return gradient;
         | 
| 463 | 
            +
              };
         | 
| 464 | 
            +
             | 
| 465 | 
            +
              contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
         | 
| 466 | 
            +
                                                               aX1, aY1, aR1) {
         | 
| 467 | 
            +
                var gradient = new CanvasGradient_('gradientradial');
         | 
| 468 | 
            +
                gradient.x0_ = aX0;
         | 
| 469 | 
            +
                gradient.y0_ = aY0;
         | 
| 470 | 
            +
                gradient.r0_ = aR0;
         | 
| 471 | 
            +
                gradient.x1_ = aX1;
         | 
| 472 | 
            +
                gradient.y1_ = aY1;
         | 
| 473 | 
            +
                gradient.r1_ = aR1;
         | 
| 474 | 
            +
                return gradient;
         | 
| 475 | 
            +
              };
         | 
| 476 | 
            +
             | 
| 477 | 
            +
              contextPrototype.drawImage = function(image, var_args) {
         | 
| 478 | 
            +
                var dx, dy, dw, dh, sx, sy, sw, sh;
         | 
| 479 | 
            +
             | 
| 480 | 
            +
                // to find the original width we overide the width and height
         | 
| 481 | 
            +
                var oldRuntimeWidth = image.runtimeStyle.width;
         | 
| 482 | 
            +
                var oldRuntimeHeight = image.runtimeStyle.height;
         | 
| 483 | 
            +
                image.runtimeStyle.width = 'auto';
         | 
| 484 | 
            +
                image.runtimeStyle.height = 'auto';
         | 
| 485 | 
            +
             | 
| 486 | 
            +
                // get the original size
         | 
| 487 | 
            +
                var w = image.width;
         | 
| 488 | 
            +
                var h = image.height;
         | 
| 489 | 
            +
             | 
| 490 | 
            +
                // and remove overides
         | 
| 491 | 
            +
                image.runtimeStyle.width = oldRuntimeWidth;
         | 
| 492 | 
            +
                image.runtimeStyle.height = oldRuntimeHeight;
         | 
| 493 | 
            +
             | 
| 494 | 
            +
                if (arguments.length == 3) {
         | 
| 495 | 
            +
                  dx = arguments[1];
         | 
| 496 | 
            +
                  dy = arguments[2];
         | 
| 497 | 
            +
                  sx = sy = 0;
         | 
| 498 | 
            +
                  sw = dw = w;
         | 
| 499 | 
            +
                  sh = dh = h;
         | 
| 500 | 
            +
                } else if (arguments.length == 5) {
         | 
| 501 | 
            +
                  dx = arguments[1];
         | 
| 502 | 
            +
                  dy = arguments[2];
         | 
| 503 | 
            +
                  dw = arguments[3];
         | 
| 504 | 
            +
                  dh = arguments[4];
         | 
| 505 | 
            +
                  sx = sy = 0;
         | 
| 506 | 
            +
                  sw = w;
         | 
| 507 | 
            +
                  sh = h;
         | 
| 508 | 
            +
                } else if (arguments.length == 9) {
         | 
| 509 | 
            +
                  sx = arguments[1];
         | 
| 510 | 
            +
                  sy = arguments[2];
         | 
| 511 | 
            +
                  sw = arguments[3];
         | 
| 512 | 
            +
                  sh = arguments[4];
         | 
| 513 | 
            +
                  dx = arguments[5];
         | 
| 514 | 
            +
                  dy = arguments[6];
         | 
| 515 | 
            +
                  dw = arguments[7];
         | 
| 516 | 
            +
                  dh = arguments[8];
         | 
| 517 | 
            +
                } else {
         | 
| 518 | 
            +
                  throw Error('Invalid number of arguments');
         | 
| 519 | 
            +
                }
         | 
| 520 | 
            +
             | 
| 521 | 
            +
                var d = this.getCoords_(dx, dy);
         | 
| 522 | 
            +
             | 
| 523 | 
            +
                var w2 = sw / 2;
         | 
| 524 | 
            +
                var h2 = sh / 2;
         | 
| 525 | 
            +
             | 
| 526 | 
            +
                var vmlStr = [];
         | 
| 527 | 
            +
             | 
| 528 | 
            +
                var W = 10;
         | 
| 529 | 
            +
                var H = 10;
         | 
| 530 | 
            +
             | 
| 531 | 
            +
                // For some reason that I've now forgotten, using divs didn't work
         | 
| 532 | 
            +
                vmlStr.push(' <g_vml_:group',
         | 
| 533 | 
            +
                            ' coordsize="', Z * W, ',', Z * H, '"',
         | 
| 534 | 
            +
                            ' coordorigin="0,0"' ,
         | 
| 535 | 
            +
                            ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
         | 
| 536 | 
            +
             | 
| 537 | 
            +
                // If filters are necessary (rotation exists), create them
         | 
| 538 | 
            +
                // filters are bog-slow, so only create them if abbsolutely necessary
         | 
| 539 | 
            +
                // The following check doesn't account for skews (which don't exist
         | 
| 540 | 
            +
                // in the canvas spec (yet) anyway.
         | 
| 541 | 
            +
             | 
| 542 | 
            +
                if (this.m_[0][0] != 1 || this.m_[0][1]) {
         | 
| 543 | 
            +
                  var filter = [];
         | 
| 544 | 
            +
             | 
| 545 | 
            +
                  // Note the 12/21 reversal
         | 
| 546 | 
            +
                  filter.push('M11=', this.m_[0][0], ',',
         | 
| 547 | 
            +
                              'M12=', this.m_[1][0], ',',
         | 
| 548 | 
            +
                              'M21=', this.m_[0][1], ',',
         | 
| 549 | 
            +
                              'M22=', this.m_[1][1], ',',
         | 
| 550 | 
            +
                              'Dx=', mr(d.x / Z), ',',
         | 
| 551 | 
            +
                              'Dy=', mr(d.y / Z), '');
         | 
| 552 | 
            +
             | 
| 553 | 
            +
                  // Bounding box calculation (need to minimize displayed area so that
         | 
| 554 | 
            +
                  // filters don't waste time on unused pixels.
         | 
| 555 | 
            +
                  var max = d;
         | 
| 556 | 
            +
                  var c2 = this.getCoords_(dx + dw, dy);
         | 
| 557 | 
            +
                  var c3 = this.getCoords_(dx, dy + dh);
         | 
| 558 | 
            +
                  var c4 = this.getCoords_(dx + dw, dy + dh);
         | 
| 559 | 
            +
             | 
| 560 | 
            +
                  max.x = m.max(max.x, c2.x, c3.x, c4.x);
         | 
| 561 | 
            +
                  max.y = m.max(max.y, c2.y, c3.y, c4.y);
         | 
| 562 | 
            +
             | 
| 563 | 
            +
                  vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
         | 
| 564 | 
            +
                              'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
         | 
| 565 | 
            +
                              filter.join(''), ", sizingmethod='clip');")
         | 
| 566 | 
            +
                } else {
         | 
| 567 | 
            +
                  vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
         | 
| 568 | 
            +
                }
         | 
| 569 | 
            +
             | 
| 570 | 
            +
                vmlStr.push(' ">' ,
         | 
| 571 | 
            +
                            '<g_vml_:image src="', image.src, '"',
         | 
| 572 | 
            +
                            ' style="width:', Z * dw, 'px;',
         | 
| 573 | 
            +
                            ' height:', Z * dh, 'px;"',
         | 
| 574 | 
            +
                            ' cropleft="', sx / w, '"',
         | 
| 575 | 
            +
                            ' croptop="', sy / h, '"',
         | 
| 576 | 
            +
                            ' cropright="', (w - sx - sw) / w, '"',
         | 
| 577 | 
            +
                            ' cropbottom="', (h - sy - sh) / h, '"',
         | 
| 578 | 
            +
                            ' />',
         | 
| 579 | 
            +
                            '</g_vml_:group>');
         | 
| 580 | 
            +
             | 
| 581 | 
            +
                this.element_.insertAdjacentHTML('BeforeEnd',
         | 
| 582 | 
            +
                                                vmlStr.join(''));
         | 
| 583 | 
            +
              };
         | 
| 584 | 
            +
             | 
| 585 | 
            +
              contextPrototype.stroke = function(aFill) {
         | 
| 586 | 
            +
                var lineStr = [];
         | 
| 587 | 
            +
                var lineOpen = false;
         | 
| 588 | 
            +
                var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
         | 
| 589 | 
            +
                var color = a.color;
         | 
| 590 | 
            +
                var opacity = a.alpha * this.globalAlpha;
         | 
| 591 | 
            +
             | 
| 592 | 
            +
                var W = 10;
         | 
| 593 | 
            +
                var H = 10;
         | 
| 594 | 
            +
             | 
| 595 | 
            +
                lineStr.push('<g_vml_:shape',
         | 
| 596 | 
            +
                             ' filled="', !!aFill, '"',
         | 
| 597 | 
            +
                             ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
         | 
| 598 | 
            +
                             ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
         | 
| 599 | 
            +
                             ' stroked="', !aFill, '"',
         | 
| 600 | 
            +
                             ' path="');
         | 
| 601 | 
            +
             | 
| 602 | 
            +
                var newSeq = false;
         | 
| 603 | 
            +
                var min = {x: null, y: null};
         | 
| 604 | 
            +
                var max = {x: null, y: null};
         | 
| 605 | 
            +
             | 
| 606 | 
            +
                for (var i = 0; i < this.currentPath_.length; i++) {
         | 
| 607 | 
            +
                  var p = this.currentPath_[i];
         | 
| 608 | 
            +
                  var c;
         | 
| 609 | 
            +
             | 
| 610 | 
            +
                  switch (p.type) {
         | 
| 611 | 
            +
                    case 'moveTo':
         | 
| 612 | 
            +
                      c = p;
         | 
| 613 | 
            +
                      lineStr.push(' m ', mr(p.x), ',', mr(p.y));
         | 
| 614 | 
            +
                      break;
         | 
| 615 | 
            +
                    case 'lineTo':
         | 
| 616 | 
            +
                      lineStr.push(' l ', mr(p.x), ',', mr(p.y));
         | 
| 617 | 
            +
                      break;
         | 
| 618 | 
            +
                    case 'close':
         | 
| 619 | 
            +
                      lineStr.push(' x ');
         | 
| 620 | 
            +
                      p = null;
         | 
| 621 | 
            +
                      break;
         | 
| 622 | 
            +
                    case 'bezierCurveTo':
         | 
| 623 | 
            +
                      lineStr.push(' c ',
         | 
| 624 | 
            +
                                   mr(p.cp1x), ',', mr(p.cp1y), ',',
         | 
| 625 | 
            +
                                   mr(p.cp2x), ',', mr(p.cp2y), ',',
         | 
| 626 | 
            +
                                   mr(p.x), ',', mr(p.y));
         | 
| 627 | 
            +
                      break;
         | 
| 628 | 
            +
                    case 'at':
         | 
| 629 | 
            +
                    case 'wa':
         | 
| 630 | 
            +
                      lineStr.push(' ', p.type, ' ',
         | 
| 631 | 
            +
                                   mr(p.x - this.arcScaleX_ * p.radius), ',',
         | 
| 632 | 
            +
                                   mr(p.y - this.arcScaleY_ * p.radius), ' ',
         | 
| 633 | 
            +
                                   mr(p.x + this.arcScaleX_ * p.radius), ',',
         | 
| 634 | 
            +
                                   mr(p.y + this.arcScaleY_ * p.radius), ' ',
         | 
| 635 | 
            +
                                   mr(p.xStart), ',', mr(p.yStart), ' ',
         | 
| 636 | 
            +
                                   mr(p.xEnd), ',', mr(p.yEnd));
         | 
| 637 | 
            +
                      break;
         | 
| 638 | 
            +
                  }
         | 
| 639 | 
            +
             | 
| 640 | 
            +
             | 
| 641 | 
            +
                  // TODO: Following is broken for curves due to
         | 
| 642 | 
            +
                  //       move to proper paths.
         | 
| 643 | 
            +
             | 
| 644 | 
            +
                  // Figure out dimensions so we can do gradient fills
         | 
| 645 | 
            +
                  // properly
         | 
| 646 | 
            +
                  if (p) {
         | 
| 647 | 
            +
                    if (min.x == null || p.x < min.x) {
         | 
| 648 | 
            +
                      min.x = p.x;
         | 
| 649 | 
            +
                    }
         | 
| 650 | 
            +
                    if (max.x == null || p.x > max.x) {
         | 
| 651 | 
            +
                      max.x = p.x;
         | 
| 652 | 
            +
                    }
         | 
| 653 | 
            +
                    if (min.y == null || p.y < min.y) {
         | 
| 654 | 
            +
                      min.y = p.y;
         | 
| 655 | 
            +
                    }
         | 
| 656 | 
            +
                    if (max.y == null || p.y > max.y) {
         | 
| 657 | 
            +
                      max.y = p.y;
         | 
| 658 | 
            +
                    }
         | 
| 659 | 
            +
                  }
         | 
| 660 | 
            +
                }
         | 
| 661 | 
            +
                lineStr.push(' ">');
         | 
| 662 | 
            +
             | 
| 663 | 
            +
                if (!aFill) {
         | 
| 664 | 
            +
                  var lineWidth = this.lineScale_ * this.lineWidth;
         | 
| 665 | 
            +
             | 
| 666 | 
            +
                  // VML cannot correctly render a line if the width is less than 1px.
         | 
| 667 | 
            +
                  // In that case, we dilute the color to make the line look thinner.
         | 
| 668 | 
            +
                  if (lineWidth < 1) {
         | 
| 669 | 
            +
                    opacity *= lineWidth;
         | 
| 670 | 
            +
                  }
         | 
| 671 | 
            +
             | 
| 672 | 
            +
                  lineStr.push(
         | 
| 673 | 
            +
                    '<g_vml_:stroke',
         | 
| 674 | 
            +
                    ' opacity="', opacity, '"',
         | 
| 675 | 
            +
                    ' joinstyle="', this.lineJoin, '"',
         | 
| 676 | 
            +
                    ' miterlimit="', this.miterLimit, '"',
         | 
| 677 | 
            +
                    ' endcap="', processLineCap(this.lineCap), '"',
         | 
| 678 | 
            +
                    ' weight="', lineWidth, 'px"',
         | 
| 679 | 
            +
                    ' color="', color, '" />'
         | 
| 680 | 
            +
                  );
         | 
| 681 | 
            +
                } else if (typeof this.fillStyle == 'object') {
         | 
| 682 | 
            +
                  var fillStyle = this.fillStyle;
         | 
| 683 | 
            +
                  var angle = 0;
         | 
| 684 | 
            +
                  var focus = {x: 0, y: 0};
         | 
| 685 | 
            +
             | 
| 686 | 
            +
                  // additional offset
         | 
| 687 | 
            +
                  var shift = 0;
         | 
| 688 | 
            +
                  // scale factor for offset
         | 
| 689 | 
            +
                  var expansion = 1;
         | 
| 690 | 
            +
             | 
| 691 | 
            +
                  if (fillStyle.type_ == 'gradient') {
         | 
| 692 | 
            +
                    var x0 = fillStyle.x0_ / this.arcScaleX_;
         | 
| 693 | 
            +
                    var y0 = fillStyle.y0_ / this.arcScaleY_;
         | 
| 694 | 
            +
                    var x1 = fillStyle.x1_ / this.arcScaleX_;
         | 
| 695 | 
            +
                    var y1 = fillStyle.y1_ / this.arcScaleY_;
         | 
| 696 | 
            +
                    var p0 = this.getCoords_(x0, y0);
         | 
| 697 | 
            +
                    var p1 = this.getCoords_(x1, y1);
         | 
| 698 | 
            +
                    var dx = p1.x - p0.x;
         | 
| 699 | 
            +
                    var dy = p1.y - p0.y;
         | 
| 700 | 
            +
                    angle = Math.atan2(dx, dy) * 180 / Math.PI;
         | 
| 701 | 
            +
             | 
| 702 | 
            +
                    // The angle should be a non-negative number.
         | 
| 703 | 
            +
                    if (angle < 0) {
         | 
| 704 | 
            +
                      angle += 360;
         | 
| 705 | 
            +
                    }
         | 
| 706 | 
            +
             | 
| 707 | 
            +
                    // Very small angles produce an unexpected result because they are
         | 
| 708 | 
            +
                    // converted to a scientific notation string.
         | 
| 709 | 
            +
                    if (angle < 1e-6) {
         | 
| 710 | 
            +
                      angle = 0;
         | 
| 711 | 
            +
                    }
         | 
| 712 | 
            +
                  } else {
         | 
| 713 | 
            +
                    var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
         | 
| 714 | 
            +
                    var width  = max.x - min.x;
         | 
| 715 | 
            +
                    var height = max.y - min.y;
         | 
| 716 | 
            +
                    focus = {
         | 
| 717 | 
            +
                      x: (p0.x - min.x) / width,
         | 
| 718 | 
            +
                      y: (p0.y - min.y) / height
         | 
| 719 | 
            +
                    };
         | 
| 720 | 
            +
             | 
| 721 | 
            +
                    width  /= this.arcScaleX_ * Z;
         | 
| 722 | 
            +
                    height /= this.arcScaleY_ * Z;
         | 
| 723 | 
            +
                    var dimension = m.max(width, height);
         | 
| 724 | 
            +
                    shift = 2 * fillStyle.r0_ / dimension;
         | 
| 725 | 
            +
                    expansion = 2 * fillStyle.r1_ / dimension - shift;
         | 
| 726 | 
            +
                  }
         | 
| 727 | 
            +
             | 
| 728 | 
            +
                  // We need to sort the color stops in ascending order by offset,
         | 
| 729 | 
            +
                  // otherwise IE won't interpret it correctly.
         | 
| 730 | 
            +
                  var stops = fillStyle.colors_;
         | 
| 731 | 
            +
                  stops.sort(function(cs1, cs2) {
         | 
| 732 | 
            +
                    return cs1.offset - cs2.offset;
         | 
| 733 | 
            +
                  });
         | 
| 734 | 
            +
             | 
| 735 | 
            +
                  var length = stops.length;
         | 
| 736 | 
            +
                  var color1 = stops[0].color;
         | 
| 737 | 
            +
                  var color2 = stops[length - 1].color;
         | 
| 738 | 
            +
                  var opacity1 = stops[0].alpha * this.globalAlpha;
         | 
| 739 | 
            +
                  var opacity2 = stops[length - 1].alpha * this.globalAlpha;
         | 
| 740 | 
            +
             | 
| 741 | 
            +
                  var colors = [];
         | 
| 742 | 
            +
                  for (var i = 0; i < length; i++) {
         | 
| 743 | 
            +
                    var stop = stops[i];
         | 
| 744 | 
            +
                    colors.push(stop.offset * expansion + shift + ' ' + stop.color);
         | 
| 745 | 
            +
                  }
         | 
| 746 | 
            +
             | 
| 747 | 
            +
                  // When colors attribute is used, the meanings of opacity and o:opacity2
         | 
| 748 | 
            +
                  // are reversed.
         | 
| 749 | 
            +
                  lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
         | 
| 750 | 
            +
                               ' method="none" focus="100%"',
         | 
| 751 | 
            +
                               ' color="', color1, '"',
         | 
| 752 | 
            +
                               ' color2="', color2, '"',
         | 
| 753 | 
            +
                               ' colors="', colors.join(','), '"',
         | 
| 754 | 
            +
                               ' opacity="', opacity2, '"',
         | 
| 755 | 
            +
                               ' g_o_:opacity2="', opacity1, '"',
         | 
| 756 | 
            +
                               ' angle="', angle, '"',
         | 
| 757 | 
            +
                               ' focusposition="', focus.x, ',', focus.y, '" />');
         | 
| 758 | 
            +
                } else {
         | 
| 759 | 
            +
                  lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
         | 
| 760 | 
            +
                               '" />');
         | 
| 761 | 
            +
                }
         | 
| 762 | 
            +
             | 
| 763 | 
            +
                lineStr.push('</g_vml_:shape>');
         | 
| 764 | 
            +
             | 
| 765 | 
            +
                this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
         | 
| 766 | 
            +
              };
         | 
| 767 | 
            +
             | 
| 768 | 
            +
              contextPrototype.fill = function() {
         | 
| 769 | 
            +
                this.stroke(true);
         | 
| 770 | 
            +
              }
         | 
| 771 | 
            +
             | 
| 772 | 
            +
              contextPrototype.closePath = function() {
         | 
| 773 | 
            +
                this.currentPath_.push({type: 'close'});
         | 
| 774 | 
            +
              };
         | 
| 775 | 
            +
             | 
| 776 | 
            +
              /**
         | 
| 777 | 
            +
               * @private
         | 
| 778 | 
            +
               */
         | 
| 779 | 
            +
              contextPrototype.getCoords_ = function(aX, aY) {
         | 
| 780 | 
            +
                var m = this.m_;
         | 
| 781 | 
            +
                return {
         | 
| 782 | 
            +
                  x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
         | 
| 783 | 
            +
                  y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
         | 
| 784 | 
            +
                }
         | 
| 785 | 
            +
              };
         | 
| 786 | 
            +
             | 
| 787 | 
            +
              contextPrototype.save = function() {
         | 
| 788 | 
            +
                var o = {};
         | 
| 789 | 
            +
                copyState(this, o);
         | 
| 790 | 
            +
                this.aStack_.push(o);
         | 
| 791 | 
            +
                this.mStack_.push(this.m_);
         | 
| 792 | 
            +
                this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
         | 
| 793 | 
            +
              };
         | 
| 794 | 
            +
             | 
| 795 | 
            +
              contextPrototype.restore = function() {
         | 
| 796 | 
            +
                copyState(this.aStack_.pop(), this);
         | 
| 797 | 
            +
                this.m_ = this.mStack_.pop();
         | 
| 798 | 
            +
              };
         | 
| 799 | 
            +
             | 
| 800 | 
            +
              function matrixIsFinite(m) {
         | 
| 801 | 
            +
                for (var j = 0; j < 3; j++) {
         | 
| 802 | 
            +
                  for (var k = 0; k < 2; k++) {
         | 
| 803 | 
            +
                    if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
         | 
| 804 | 
            +
                      return false;
         | 
| 805 | 
            +
                    }
         | 
| 806 | 
            +
                  }
         | 
| 807 | 
            +
                }
         | 
| 808 | 
            +
                return true;
         | 
| 809 | 
            +
              }
         | 
| 810 | 
            +
             | 
| 811 | 
            +
              function setM(ctx, m, updateLineScale) {
         | 
| 812 | 
            +
                if (!matrixIsFinite(m)) {
         | 
| 813 | 
            +
                  return;
         | 
| 814 | 
            +
                }
         | 
| 815 | 
            +
                ctx.m_ = m;
         | 
| 816 | 
            +
             | 
| 817 | 
            +
                if (updateLineScale) {
         | 
| 818 | 
            +
                  // Get the line scale.
         | 
| 819 | 
            +
                  // Determinant of this.m_ means how much the area is enlarged by the
         | 
| 820 | 
            +
                  // transformation. So its square root can be used as a scale factor
         | 
| 821 | 
            +
                  // for width.
         | 
| 822 | 
            +
                  var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
         | 
| 823 | 
            +
                  ctx.lineScale_ = sqrt(abs(det));
         | 
| 824 | 
            +
                }
         | 
| 825 | 
            +
              }
         | 
| 826 | 
            +
             | 
| 827 | 
            +
              contextPrototype.translate = function(aX, aY) {
         | 
| 828 | 
            +
                var m1 = [
         | 
| 829 | 
            +
                  [1,  0,  0],
         | 
| 830 | 
            +
                  [0,  1,  0],
         | 
| 831 | 
            +
                  [aX, aY, 1]
         | 
| 832 | 
            +
                ];
         | 
| 833 | 
            +
             | 
| 834 | 
            +
                setM(this, matrixMultiply(m1, this.m_), false);
         | 
| 835 | 
            +
              };
         | 
| 836 | 
            +
             | 
| 837 | 
            +
              contextPrototype.rotate = function(aRot) {
         | 
| 838 | 
            +
                var c = mc(aRot);
         | 
| 839 | 
            +
                var s = ms(aRot);
         | 
| 840 | 
            +
             | 
| 841 | 
            +
                var m1 = [
         | 
| 842 | 
            +
                  [c,  s, 0],
         | 
| 843 | 
            +
                  [-s, c, 0],
         | 
| 844 | 
            +
                  [0,  0, 1]
         | 
| 845 | 
            +
                ];
         | 
| 846 | 
            +
             | 
| 847 | 
            +
                setM(this, matrixMultiply(m1, this.m_), false);
         | 
| 848 | 
            +
              };
         | 
| 849 | 
            +
             | 
| 850 | 
            +
              contextPrototype.scale = function(aX, aY) {
         | 
| 851 | 
            +
                this.arcScaleX_ *= aX;
         | 
| 852 | 
            +
                this.arcScaleY_ *= aY;
         | 
| 853 | 
            +
                var m1 = [
         | 
| 854 | 
            +
                  [aX, 0,  0],
         | 
| 855 | 
            +
                  [0,  aY, 0],
         | 
| 856 | 
            +
                  [0,  0,  1]
         | 
| 857 | 
            +
                ];
         | 
| 858 | 
            +
             | 
| 859 | 
            +
                setM(this, matrixMultiply(m1, this.m_), true);
         | 
| 860 | 
            +
              };
         | 
| 861 | 
            +
             | 
| 862 | 
            +
              contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
         | 
| 863 | 
            +
                var m1 = [
         | 
| 864 | 
            +
                  [m11, m12, 0],
         | 
| 865 | 
            +
                  [m21, m22, 0],
         | 
| 866 | 
            +
                  [dx,  dy,  1]
         | 
| 867 | 
            +
                ];
         | 
| 868 | 
            +
             | 
| 869 | 
            +
                setM(this, matrixMultiply(m1, this.m_), true);
         | 
| 870 | 
            +
              };
         | 
| 871 | 
            +
             | 
| 872 | 
            +
              contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
         | 
| 873 | 
            +
                var m = [
         | 
| 874 | 
            +
                  [m11, m12, 0],
         | 
| 875 | 
            +
                  [m21, m22, 0],
         | 
| 876 | 
            +
                  [dx,  dy,  1]
         | 
| 877 | 
            +
                ];
         | 
| 878 | 
            +
             | 
| 879 | 
            +
                setM(this, m, true);
         | 
| 880 | 
            +
              };
         | 
| 881 | 
            +
             | 
| 882 | 
            +
              /******** STUBS ********/
         | 
| 883 | 
            +
              contextPrototype.clip = function() {
         | 
| 884 | 
            +
                // TODO: Implement
         | 
| 885 | 
            +
              };
         | 
| 886 | 
            +
             | 
| 887 | 
            +
              contextPrototype.arcTo = function() {
         | 
| 888 | 
            +
                // TODO: Implement
         | 
| 889 | 
            +
              };
         | 
| 890 | 
            +
             | 
| 891 | 
            +
              contextPrototype.createPattern = function() {
         | 
| 892 | 
            +
                return new CanvasPattern_;
         | 
| 893 | 
            +
              };
         | 
| 894 | 
            +
             | 
| 895 | 
            +
              // Gradient / Pattern Stubs
         | 
| 896 | 
            +
              function CanvasGradient_(aType) {
         | 
| 897 | 
            +
                this.type_ = aType;
         | 
| 898 | 
            +
                this.x0_ = 0;
         | 
| 899 | 
            +
                this.y0_ = 0;
         | 
| 900 | 
            +
                this.r0_ = 0;
         | 
| 901 | 
            +
                this.x1_ = 0;
         | 
| 902 | 
            +
                this.y1_ = 0;
         | 
| 903 | 
            +
                this.r1_ = 0;
         | 
| 904 | 
            +
                this.colors_ = [];
         | 
| 905 | 
            +
              }
         | 
| 906 | 
            +
             | 
| 907 | 
            +
              CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
         | 
| 908 | 
            +
                aColor = processStyle(aColor);
         | 
| 909 | 
            +
                this.colors_.push({offset: aOffset,
         | 
| 910 | 
            +
                                   color: aColor.color,
         | 
| 911 | 
            +
                                   alpha: aColor.alpha});
         | 
| 912 | 
            +
              };
         | 
| 913 | 
            +
             | 
| 914 | 
            +
              function CanvasPattern_() {}
         | 
| 915 | 
            +
             | 
| 916 | 
            +
              // set up externs
         | 
| 917 | 
            +
              G_vmlCanvasManager = G_vmlCanvasManager_;
         | 
| 918 | 
            +
              CanvasRenderingContext2D = CanvasRenderingContext2D_;
         | 
| 919 | 
            +
              CanvasGradient = CanvasGradient_;
         | 
| 920 | 
            +
              CanvasPattern = CanvasPattern_;
         | 
| 921 | 
            +
             | 
| 922 | 
            +
            })();
         | 
| 923 | 
            +
             | 
| 924 | 
            +
            } // if
         |