Вход Регистрация
Файл: public_html/admin/vendors/flot/excanvas.js
Строк: 1295
<?php
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


// Known Issues:
//
// * Patterns only support repeat.
// * Radial gradient are not implemented. The VML version of these look very
//   different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
//   width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
//   Quirks mode will draw the canvas using border-box. Either change your
//   doctype to HTML5
//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
//   or use Box Sizing Behavior from WebFX
//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Filling very large shapes (above 5000 points) is buggy.
// * Optimize. There is always room for speed improvements.

// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {

(function() {

  
// alias some functions to make (compiled) code shorter
  
var Math;
  var 
mr m.round;
  var 
ms m.sin;
  var 
mc m.cos;
  var 
abs m.abs;
  var 
sqrt m.sqrt;

  
// this is used for sub pixel precision
  
var 10;
  var 
Z2 2;

  var 
IE_VERSION = +navigator.userAgent.match(/MSIE ([d.]+)?/)[1];

  
/**
   * This funtion is assigned to the <canvas> elements as element.getContext().
   * @this {HTMLElement}
   * @return {CanvasRenderingContext2D_}
   */
  
function getContext() {
    return 
this.context_ ||
        (
this.context_ = new CanvasRenderingContext2D_(this));
  }

  var 
slice = Array.prototype.slice;

  
/**
   * Binds a function to an object. The returned function will always use the
   * passed in {@code obj} as {@code this}.
   *
   * Example:
   *
   *   g = bind(f, obj, a, b)
   *   g(c, d) // will do f.call(obj, a, b, c, d)
   *
   * @param {Function} f The function to bind the object to
   * @param {Object} obj The object that should act as this when the function
   *     is called
   * @param {*} var_args Rest arguments that will be used as the initial
   *     arguments when the function is called
   * @return {Function} A new function that has bound this
   */
  
function bind(fobjvar_args) {
    var 
slice.call(arguments2);
    return function() {
      return 
f.apply(obja.concat(slice.call(arguments)));
    };
  }

  function 
encodeHtmlAttribute(s) {
    return 
String(s).replace(/&/g'&amp;').replace(/"/g, '&quot;');
  }

  function addNamespace(doc, prefix, urn) {
    if (!doc.namespaces[prefix]) {
      doc.namespaces.add(prefix, urn, '#default#VML');
    }
  }

  function addNamespacesAndStylesheet(doc) {
    addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
    addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');

    // Setup default CSS.  Only add one style sheet per document
    if (!doc.styleSheets['ex_canvas_']) {
      var ss = doc.createStyleSheet();
      ss.owningElement.id = 'ex_canvas_';
      ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
          // default size is 300x150 in Gecko and Opera
          'text-align:left;width:300px;height:150px}';
    }
  }

  // Add namespaces and stylesheet at startup.
  addNamespacesAndStylesheet(document);

  var G_vmlCanvasManager_ = {
    init: function(opt_doc) {
      var doc = opt_doc || document;
      // Create a dummy element so that IE will allow canvas elements to be
      // recognized.
      doc.createElement('canvas');
      doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
    },

    init_: function(doc) {
      // find all canvas elements
      var els = doc.getElementsByTagName('canvas');
      for (var i = 0; i < els.length; i++) {
        this.initElement(els[i]);
      }
    },

    /**
     * Public initializes a canvas element so that it can be used as canvas
     * element from now on. This is called automatically before the page is
     * loaded but if you are creating elements using createElement you need to
     * make sure this is called on the element.
     * @param {HTMLElement} el The canvas element to initialize.
     * @return {HTMLElement} the element that was created.
     */
    initElement: function(el) {
      if (!el.getContext) {
        el.getContext = getContext;

        // Add namespaces and stylesheet to document of the element.
        addNamespacesAndStylesheet(el.ownerDocument);

        // Remove fallback content. There is no way to hide text nodes so we
        // just remove all childNodes. We could hide all elements and remove
        // text nodes but who really cares about the fallback content.
        el.innerHTML = '';

        // do not use inline function because that will leak memory
        el.attachEvent('onpropertychange', onPropertyChange);
        el.attachEvent('onresize', onResize);

        var attrs = el.attributes;
        if (attrs.width && attrs.width.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setWidth_(attrs.width.nodeValue);
          el.style.width = attrs.width.nodeValue + 'px';
        } else {
          el.width = el.clientWidth;
        }
        if (attrs.height && attrs.height.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setHeight_(attrs.height.nodeValue);
          el.style.height = attrs.height.nodeValue + 'px';
        } else {
          el.height = el.clientHeight;
        }
        //el.getContext().setCoordsize_()
      }
      return el;
    }
  };

  function onPropertyChange(e) {
    var el = e.srcElement;

    switch (e.propertyName) {
      case 'width':
        el.getContext().clearRect();
        el.style.width = el.attributes.width.nodeValue + 'px';
        // In IE8 this does not trigger onresize.
        el.firstChild.style.width =  el.clientWidth + 'px';
        break;
      case 'height':
        el.getContext().clearRect();
        el.style.height = el.attributes.height.nodeValue + 'px';
        el.firstChild.style.height = el.clientHeight + 'px';
        break;
    }
  }

  function onResize(e) {
    var el = e.srcElement;
    if (el.firstChild) {
      el.firstChild.style.width =  el.clientWidth + 'px';
      el.firstChild.style.height = el.clientHeight + 'px';
    }
  }

  G_vmlCanvasManager_.init();

  // precompute "
00" to "FF"
  var decToHex = [];
  for (var i = 0; i < 16; i++) {
    for (var j = 0; j < 16; j++) {
      decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
    }
  }

  function createMatrixIdentity() {
    return [
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ];
  }

  function matrixMultiply(m1, m2) {
    var result = createMatrixIdentity();

    for (var x = 0; x < 3; x++) {
      for (var y = 0; y < 3; y++) {
        var sum = 0;

        for (var z = 0; z < 3; z++) {
          sum += m1[x][z] * m2[z][y];
        }

        result[x][y] = sum;
      }
    }
    return result;
  }

  function copyState(o1, o2) {
    o2.fillStyle     = o1.fillStyle;
    o2.lineCap       = o1.lineCap;
    o2.lineJoin      = o1.lineJoin;
    o2.lineWidth     = o1.lineWidth;
    o2.miterLimit    = o1.miterLimit;
    o2.shadowBlur    = o1.shadowBlur;
    o2.shadowColor   = o1.shadowColor;
    o2.shadowOffsetX = o1.shadowOffsetX;
    o2.shadowOffsetY = o1.shadowOffsetY;
    o2.strokeStyle   = o1.strokeStyle;
    o2.globalAlpha   = o1.globalAlpha;
    o2.font          = o1.font;
    o2.textAlign     = o1.textAlign;
    o2.textBaseline  = o1.textBaseline;
    o2.arcScaleX_    = o1.arcScaleX_;
    o2.arcScaleY_    = o1.arcScaleY_;
    o2.lineScale_    = o1.lineScale_;
  }

  var colorData = {
    aliceblue: '#F0F8FF',
    antiquewhite: '#FAEBD7',
    aquamarine: '#7FFFD4',
    azure: '#F0FFFF',
    beige: '#F5F5DC',
    bisque: '#FFE4C4',
    black: '#000000',
    blanchedalmond: '#FFEBCD',
    blueviolet: '#8A2BE2',
    brown: '#A52A2A',
    burlywood: '#DEB887',
    cadetblue: '#5F9EA0',
    chartreuse: '#7FFF00',
    chocolate: '#D2691E',
    coral: '#FF7F50',
    cornflowerblue: '#6495ED',
    cornsilk: '#FFF8DC',
    crimson: '#DC143C',
    cyan: '#00FFFF',
    darkblue: '#00008B',
    darkcyan: '#008B8B',
    darkgoldenrod: '#B8860B',
    darkgray: '#A9A9A9',
    darkgreen: '#006400',
    darkgrey: '#A9A9A9',
    darkkhaki: '#BDB76B',
    darkmagenta: '#8B008B',
    darkolivegreen: '#556B2F',
    darkorange: '#FF8C00',
    darkorchid: '#9932CC',
    darkred: '#8B0000',
    darksalmon: '#E9967A',
    darkseagreen: '#8FBC8F',
    darkslateblue: '#483D8B',
    darkslategray: '#2F4F4F',
    darkslategrey: '#2F4F4F',
    darkturquoise: '#00CED1',
    darkviolet: '#9400D3',
    deeppink: '#FF1493',
    deepskyblue: '#00BFFF',
    dimgray: '#696969',
    dimgrey: '#696969',
    dodgerblue: '#1E90FF',
    firebrick: '#B22222',
    floralwhite: '#FFFAF0',
    forestgreen: '#228B22',
    gainsboro: '#DCDCDC',
    ghostwhite: '#F8F8FF',
    gold: '#FFD700',
    goldenrod: '#DAA520',
    grey: '#808080',
    greenyellow: '#ADFF2F',
    honeydew: '#F0FFF0',
    hotpink: '#FF69B4',
    indianred: '#CD5C5C',
    indigo: '#4B0082',
    ivory: '#FFFFF0',
    khaki: '#F0E68C',
    lavender: '#E6E6FA',
    lavenderblush: '#FFF0F5',
    lawngreen: '#7CFC00',
    lemonchiffon: '#FFFACD',
    lightblue: '#ADD8E6',
    lightcoral: '#F08080',
    lightcyan: '#E0FFFF',
    lightgoldenrodyellow: '#FAFAD2',
    lightgreen: '#90EE90',
    lightgrey: '#D3D3D3',
    lightpink: '#FFB6C1',
    lightsalmon: '#FFA07A',
    lightseagreen: '#20B2AA',
    lightskyblue: '#87CEFA',
    lightslategray: '#778899',
    lightslategrey: '#778899',
    lightsteelblue: '#B0C4DE',
    lightyellow: '#FFFFE0',
    limegreen: '#32CD32',
    linen: '#FAF0E6',
    magenta: '#FF00FF',
    mediumaquamarine: '#66CDAA',
    mediumblue: '#0000CD',
    mediumorchid: '#BA55D3',
    mediumpurple: '#9370DB',
    mediumseagreen: '#3CB371',
    mediumslateblue: '#7B68EE',
    mediumspringgreen: '#00FA9A',
    mediumturquoise: '#48D1CC',
    mediumvioletred: '#C71585',
    midnightblue: '#191970',
    mintcream: '#F5FFFA',
    mistyrose: '#FFE4E1',
    moccasin: '#FFE4B5',
    navajowhite: '#FFDEAD',
    oldlace: '#FDF5E6',
    olivedrab: '#6B8E23',
    orange: '#FFA500',
    orangered: '#FF4500',
    orchid: '#DA70D6',
    palegoldenrod: '#EEE8AA',
    palegreen: '#98FB98',
    paleturquoise: '#AFEEEE',
    palevioletred: '#DB7093',
    papayawhip: '#FFEFD5',
    peachpuff: '#FFDAB9',
    peru: '#CD853F',
    pink: '#FFC0CB',
    plum: '#DDA0DD',
    powderblue: '#B0E0E6',
    rosybrown: '#BC8F8F',
    royalblue: '#4169E1',
    saddlebrown: '#8B4513',
    salmon: '#FA8072',
    sandybrown: '#F4A460',
    seagreen: '#2E8B57',
    seashell: '#FFF5EE',
    sienna: '#A0522D',
    skyblue: '#87CEEB',
    slateblue: '#6A5ACD',
    slategray: '#708090',
    slategrey: '#708090',
    snow: '#FFFAFA',
    springgreen: '#00FF7F',
    steelblue: '#4682B4',
    tan: '#D2B48C',
    thistle: '#D8BFD8',
    tomato: '#FF6347',
    turquoise: '#40E0D0',
    violet: '#EE82EE',
    wheat: '#F5DEB3',
    whitesmoke: '#F5F5F5',
    yellowgreen: '#9ACD32'
  };


  function getRgbHslContent(styleString) {
    var start = styleString.indexOf('(', 3);
    var end = styleString.indexOf(')', start + 1);
    var parts = styleString.substring(start + 1, end).split(',');
    // add alpha if needed
    if (parts.length != 4 || styleString.charAt(3) != 'a') {
      parts[3] = 1;
    }
    return parts;
  }

  function percent(s) {
    return parseFloat(s) / 100;
  }

  function clamp(v, min, max) {
    return Math.min(max, Math.max(min, v));
  }

  function hslToRgb(parts){
    var r, g, b, h, s, l;
    h = parseFloat(parts[0]) / 360 % 360;
    if (h < 0)
      h++;
    s = clamp(percent(parts[1]), 0, 1);
    l = clamp(percent(parts[2]), 0, 1);
    if (s == 0) {
      r = g = b = l; // achromatic
    } else {
      var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
      var p = 2 * l - q;
      r = hueToRgb(p, q, h + 1 / 3);
      g = hueToRgb(p, q, h);
      b = hueToRgb(p, q, h - 1 / 3);
    }

    return '#' + decToHex[Math.floor(r * 255)] +
        decToHex[Math.floor(g * 255)] +
        decToHex[Math.floor(b * 255)];
  }

  function hueToRgb(m1, m2, h) {
    if (h < 0)
      h++;
    if (h > 1)
      h--;

    if (6 * h < 1)
      return m1 + (m2 - m1) * 6 * h;
    else if (2 * h < 1)
      return m2;
    else if (3 * h < 2)
      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
    else
      return m1;
  }

  var processStyleCache = {};

  function processStyle(styleString) {
    if (styleString in processStyleCache) {
      return processStyleCache[styleString];
    }

    var str, alpha = 1;

    styleString = String(styleString);
    if (styleString.charAt(0) == '#') {
      str = styleString;
    } else if (/^rgb/.test(styleString)) {
      var parts = getRgbHslContent(styleString);
      var str = '#', n;
      for (var i = 0; i < 3; i++) {
        if (parts[i].indexOf('%') != -1) {
          n = Math.floor(percent(parts[i]) * 255);
        } else {
          n = +parts[i];
        }
        str += decToHex[clamp(n, 0, 255)];
      }
      alpha = +parts[3];
    } else if (/^hsl/.test(styleString)) {
      var parts = getRgbHslContent(styleString);
      str = hslToRgb(parts);
      alpha = parts[3];
    } else {
      str = colorData[styleString] || styleString;
    }
    return processStyleCache[styleString] = {color: str, alpha: alpha};
  }

  var DEFAULT_STYLE = {
    style: 'normal',
    variant: 'normal',
    weight: 'normal',
    size: 10,
    family: 'sans-serif'
  };

  // Internal text style cache
  var fontStyleCache = {};

  function processFontStyle(styleString) {
    if (fontStyleCache[styleString]) {
      return fontStyleCache[styleString];
    }

    var el = document.createElement('div');
    var style = el.style;
    try {
      style.font = styleString;
    } catch (ex) {
      // Ignore failures to set to invalid font.
    }

    return fontStyleCache[styleString] = {
      style: style.fontStyle || DEFAULT_STYLE.style,
      variant: style.fontVariant || DEFAULT_STYLE.variant,
      weight: style.fontWeight || DEFAULT_STYLE.weight,
      size: style.fontSize || DEFAULT_STYLE.size,
      family: style.fontFamily || DEFAULT_STYLE.family
    };
  }

  function getComputedStyle(style, element) {
    var computedStyle = {};

    for (var p in style) {
      computedStyle[p] = style[p];
    }

    // Compute the size
    var canvasFontSize = parseFloat(element.currentStyle.fontSize),
        fontSize = parseFloat(style.size);

    if (typeof style.size == 'number') {
      computedStyle.size = style.size;
    } else if (style.size.indexOf('px') != -1) {
      computedStyle.size = fontSize;
    } else if (style.size.indexOf('em') != -1) {
      computedStyle.size = canvasFontSize * fontSize;
    } else if(style.size.indexOf('%') != -1) {
      computedStyle.size = (canvasFontSize / 100) * fontSize;
    } else if (style.size.indexOf('pt') != -1) {
      computedStyle.size = fontSize / .75;
    } else {
      computedStyle.size = canvasFontSize;
    }

    // Different scaling between normal text and VML text. This was found using
    // trial and error to get the same size as non VML text.
    computedStyle.size *= 0.981;

    return computedStyle;
  }

  function buildStyle(style) {
    return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
        style.size + 'px ' + style.family;
  }

  var lineCapMap = {
    'butt': 'flat',
    'round': 'round'
  };

  function processLineCap(lineCap) {
    return lineCapMap[lineCap] || 'square';
  }

  /**
   * This class implements CanvasRenderingContext2D interface as described by
   * the WHATWG.
   * @param {HTMLElement} canvasElement The element that the 2D context should
   * be associated with
   */
  function CanvasRenderingContext2D_(canvasElement) {
    this.m_ = createMatrixIdentity();

    this.mStack_ = [];
    this.aStack_ = [];
    this.currentPath_ = [];

    // Canvas context properties
    this.strokeStyle = '#000';
    this.fillStyle = '#000';

    this.lineWidth = 1;
    this.lineJoin = 'miter';
    this.lineCap = 'butt';
    this.miterLimit = Z * 1;
    this.globalAlpha = 1;
    this.font = '10px sans-serif';
    this.textAlign = 'left';
    this.textBaseline = 'alphabetic';
    this.canvas = canvasElement;

    var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
        canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
    var el = canvasElement.ownerDocument.createElement('div');
    el.style.cssText = cssText;
    canvasElement.appendChild(el);

    var overlayEl = el.cloneNode(false);
    // Use a non transparent background.
    overlayEl.style.backgroundColor = 'red';
    overlayEl.style.filter = 'alpha(opacity=0)';
    canvasElement.appendChild(overlayEl);

    this.element_ = el;
    this.arcScaleX_ = 1;
    this.arcScaleY_ = 1;
    this.lineScale_ = 1;
  }

  var contextPrototype = CanvasRenderingContext2D_.prototype;
  contextPrototype.clearRect = function() {
    if (this.textMeasureEl_) {
      this.textMeasureEl_.removeNode(true);
      this.textMeasureEl_ = null;
    }
    this.element_.innerHTML = '';
  };

  contextPrototype.beginPath = function() {
    // TODO: Branch current matrix so that save/restore has no effect
    //       as per safari docs.
    this.currentPath_ = [];
  };

  contextPrototype.moveTo = function(aX, aY) {
    var p = getCoords(this, aX, aY);
    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.lineTo = function(aX, aY) {
    var p = getCoords(this, aX, aY);
    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});

    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
                                            aCP2x, aCP2y,
                                            aX, aY) {
    var p = getCoords(this, aX, aY);
    var cp1 = getCoords(this, aCP1x, aCP1y);
    var cp2 = getCoords(this, aCP2x, aCP2y);
    bezierCurveTo(this, cp1, cp2, p);
  };

  // Helper function that takes the already fixed cordinates.
  function bezierCurveTo(self, cp1, cp2, p) {
    self.currentPath_.push({
      type: 'bezierCurveTo',
      cp1x: cp1.x,
      cp1y: cp1.y,
      cp2x: cp2.x,
      cp2y: cp2.y,
      x: p.x,
      y: p.y
    });
    self.currentX_ = p.x;
    self.currentY_ = p.y;
  }

  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
    // the following is lifted almost directly from
    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes

    var cp = getCoords(this, aCPx, aCPy);
    var p = getCoords(this, aX, aY);

    var cp1 = {
      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
    };
    var cp2 = {
      x: cp1.x + (p.x - this.currentX_) / 3.0,
      y: cp1.y + (p.y - this.currentY_) / 3.0
    };

    bezierCurveTo(this, cp1, cp2, p);
  };

  contextPrototype.arc = function(aX, aY, aRadius,
                                  aStartAngle, aEndAngle, aClockwise) {
    aRadius *= Z;
    var arcType = aClockwise ? 'at' : 'wa';

    var xStart = aX + mc(aStartAngle) * aRadius - Z2;
    var yStart = aY + ms(aStartAngle) * aRadius - Z2;

    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;

    // IE won't render arches drawn counter clockwise if xStart == xEnd.
    if (xStart == xEnd && !aClockwise) {
      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
                       // that can be represented in binary
    }

    var p = getCoords(this, aX, aY);
    var pStart = getCoords(this, xStart, yStart);
    var pEnd = getCoords(this, xEnd, yEnd);

    this.currentPath_.push({type: arcType,
                           x: p.x,
                           y: p.y,
                           radius: aRadius,
                           xStart: pStart.x,
                           yStart: pStart.y,
                           xEnd: pEnd.x,
                           yEnd: pEnd.y});

  };

  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
  };

  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
    var oldPath = this.currentPath_;
    this.beginPath();

    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.stroke();

    this.currentPath_ = oldPath;
  };

  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
    var oldPath = this.currentPath_;
    this.beginPath();

    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.fill();

    this.currentPath_ = oldPath;
  };

  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
    var gradient = new CanvasGradient_('gradient');
    gradient.x0_ = aX0;
    gradient.y0_ = aY0;
    gradient.x1_ = aX1;
    gradient.y1_ = aY1;
    return gradient;
  };

  contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
                                                   aX1, aY1, aR1) {
    var gradient = new CanvasGradient_('gradientradial');
    gradient.x0_ = aX0;
    gradient.y0_ = aY0;
    gradient.r0_ = aR0;
    gradient.x1_ = aX1;
    gradient.y1_ = aY1;
    gradient.r1_ = aR1;
    return gradient;
  };

  contextPrototype.drawImage = function(image, var_args) {
    var dx, dy, dw, dh, sx, sy, sw, sh;

    // to find the original width we overide the width and height
    var oldRuntimeWidth = image.runtimeStyle.width;
    var oldRuntimeHeight = image.runtimeStyle.height;
    image.runtimeStyle.width = 'auto';
    image.runtimeStyle.height = 'auto';

    // get the original size
    var w = image.width;
    var h = image.height;

    // and remove overides
    image.runtimeStyle.width = oldRuntimeWidth;
    image.runtimeStyle.height = oldRuntimeHeight;

    if (arguments.length == 3) {
      dx = arguments[1];
      dy = arguments[2];
      sx = sy = 0;
      sw = dw = w;
      sh = dh = h;
    } else if (arguments.length == 5) {
      dx = arguments[1];
      dy = arguments[2];
      dw = arguments[3];
      dh = arguments[4];
      sx = sy = 0;
      sw = w;
      sh = h;
    } else if (arguments.length == 9) {
      sx = arguments[1];
      sy = arguments[2];
      sw = arguments[3];
      sh = arguments[4];
      dx = arguments[5];
      dy = arguments[6];
      dw = arguments[7];
      dh = arguments[8];
    } else {
      throw Error('Invalid number of arguments');
    }

    var d = getCoords(this, dx, dy);

    var w2 = sw / 2;
    var h2 = sh / 2;

    var vmlStr = [];

    var W = 10;
    var H = 10;

    // For some reason that I've now forgotten, using divs didn't work
    vmlStr.push(' <g_vml_:group',
                ' coordsize="', Z * W, '
,', Z * H, '"',
                ' coordorigin="
0,0"' ,
                ' style="
width:', W, 'px;height:', H, 'px;position:absolute;');

    // If filters are necessary (rotation exists), create them
    // filters are bog-slow, so only create them if abbsolutely necessary
    // The following check doesn'
t account for skews (which don't exist
    // in the canvas spec (yet) anyway.

    if (this.m_[0][0] != 1 || this.m_[0][1] ||
        this.m_[1][1] != 1 || this.m_[1][0]) {
      var filter = [];

      // Note the 12/21 reversal
      filter.push('
M11=', this.m_[0][0], ',',
                  '
M12=', this.m_[1][0], ',',
                  '
M21=', this.m_[0][1], ',',
                  '
M22=', this.m_[1][1], ',',
                  '
Dx=', mr(d.x / Z), ',',
                  '
Dy=', mr(d.y / Z), '');

      // Bounding box calculation (need to minimize displayed area so that
      // filters don'
t waste time on unused pixels.
      var 
max d;
      var 
c2 getCoords(thisdx dwdy);
      var 
c3 getCoords(thisdxdy dh);
      var 
c4 getCoords(thisdx dwdy dh);

      
max.m.max(max.xc2.xc3.xc4.x);
      
max.m.max(max.yc2.yc3.yc4.y);

      
vmlStr.push('padding:0 'mr(max.Z), 'px 'mr(max.Z),
                  
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
                  
filter.join(''), ", sizingmethod='clip');");

    } else {
      
vmlStr.push('top:'mr(d.Z), 'px;left:'mr(d.Z), 'px;');
    }

    
vmlStr.push(' ">' ,
                
'<g_vml_:image src="'image.src'"',
                
' style="width:'dw'px;',
                
' height:'dh'px"',
                
' cropleft="'sx w'"',
                
' croptop="'sy h'"',
                
' cropright="', (sx sw) / w'"',
                
' cropbottom="', (sy sh) / h'"',
                
' />',
                
'</g_vml_:group>');

    
this.element_.insertAdjacentHTML('BeforeEnd'vmlStr.join(''));
  };

  
contextPrototype.stroke = function(aFill) {
    var 
10;
    var 
10;
    
// Divide the shape into chunks if it's too long because IE has a limit
    // somewhere for how long a VML shape can be. This simple division does
    // not work with fills, only strokes, unfortunately.
    
var chunkSize 5000;

    var 
min = {xnullynull};
    var 
max = {xnullynull};

    for (var 
0this.currentPath_.length+= chunkSize) {
      var 
lineStr = [];
      var 
lineOpen false;

      
lineStr.push('<g_vml_:shape',
                   
' filled="', !!aFill'"',
                   
' style="position:absolute;width:'W'px;height:'H'px;"',
                   
' coordorigin="0,0"',
                   
' coordsize="'W','H'"',
                   
' stroked="', !aFill'"',
                   
' path="');

      var 
newSeq false;

      for (var 
jMath.min(chunkSizethis.currentPath_.length); i++) {
        if (
chunkSize == && 0) { // move into position for next chunk
          
lineStr.push(' m 'mr(this.currentPath_[i-1].x), ','mr(this.currentPath_[i-1].y));
        }

        var 
this.currentPath_[i];
        var 
c;

        switch (
p.type) {
          case 
'moveTo':
            
p;
            
lineStr.push(' m 'mr(p.x), ','mr(p.y));
            break;
          case 
'lineTo':
            
lineStr.push(' l 'mr(p.x), ','mr(p.y));
            break;
          case 
'close':
            
lineStr.push(' x ');
            
null;
            break;
          case 
'bezierCurveTo':
            
lineStr.push(' c ',
                         
mr(p.cp1x), ','mr(p.cp1y), ',',
                         
mr(p.cp2x), ','mr(p.cp2y), ',',
                         
mr(p.x), ','mr(p.y));
            break;
          case 
'at':
          case 
'wa':
            
lineStr.push(' 'p.type' ',
                         
mr(p.this.arcScaleX_ p.radius), ',',
                         
mr(p.this.arcScaleY_ p.radius), ' ',
                         
mr(p.this.arcScaleX_ p.radius), ',',
                         
mr(p.this.arcScaleY_ p.radius), ' ',
                         
mr(p.xStart), ','mr(p.yStart), ' ',
                         
mr(p.xEnd), ','mr(p.yEnd));
            break;
        }
  
  
        
// TODO: Following is broken for curves due to
        //       move to proper paths.
  
        // Figure out dimensions so we can do gradient fills
        // properly
        
if (p) {
          if (
min.== null || p.min.x) {
            
min.p.x;
          }
          if (
max.== null || p.max.x) {
            
max.p.x;
          }
          if (
min.== null || p.min.y) {
            
min.p.y;
          }
          if (
max.== null || p.max.y) {
            
max.p.y;
          }
        }
      }
      
lineStr.push(' ">');
  
      if (!
aFill) {
        
appendStroke(thislineStr);
      } else {
        
appendFill(thislineStrminmax);
      }
  
      
lineStr.push('</g_vml_:shape>');
  
      
this.element_.insertAdjacentHTML('beforeEnd'lineStr.join(''));
    }
  };

  function 
appendStroke(ctxlineStr) {
    var 
processStyle(ctx.strokeStyle);
    var 
color a.color;
    var 
opacity a.alpha ctx.globalAlpha;
    var 
lineWidth ctx.lineScale_ ctx.lineWidth;

    
// VML cannot correctly render a line if the width is less than 1px.
    // In that case, we dilute the color to make the line look thinner.
    
if (lineWidth 1) {
      
opacity *= lineWidth;
    }

    
lineStr.push(
      
'<g_vml_:stroke',
      
' opacity="'opacity'"',
      
' joinstyle="'ctx.lineJoin'"',
      
' miterlimit="'ctx.miterLimit'"',
      
' endcap="'processLineCap(ctx.lineCap), '"',
      
' weight="'lineWidth'px"',
      
' color="'color'" />'
    
);
  }

  function 
appendFill(ctxlineStrminmax) {
    var 
fillStyle ctx.fillStyle;
    var 
arcScaleX ctx.arcScaleX_;
    var 
arcScaleY ctx.arcScaleY_;
    var 
width max.min.x;
    var 
height max.min.y;
    if (
fillStyle instanceof CanvasGradient_) {
      
// TODO: Gradients transformed with the transformation matrix.
      
var angle 0;
      var 
focus = {x0y0};

      
// additional offset
      
var shift 0;
      
// scale factor for offset
      
var expansion 1;

      if (
fillStyle.type_ == 'gradient') {
        var 
x0 fillStyle.x0_ arcScaleX;
        var 
y0 fillStyle.y0_ arcScaleY;
        var 
x1 fillStyle.x1_ arcScaleX;
        var 
y1 fillStyle.y1_ arcScaleY;
        var 
p0 getCoords(ctxx0y0);
        var 
p1 getCoords(ctxx1y1);
        var 
dx p1.p0.x;
        var 
dy p1.p0.y;
        
angle Math.atan2(dxdy) * 180 Math.PI;

        
// The angle should be a non-negative number.
        
if (angle 0) {
          
angle += 360;
        }

        
// Very small angles produce an unexpected result because they are
        // converted to a scientific notation string.
        
if (angle 1e-6) {
          
angle 0;
        }
      } else {
        var 
p0 getCoords(ctxfillStyle.x0_fillStyle.y0_);
        
focus = {
          
x: (p0.min.x) / width,
          
y: (p0.min.y) / height
        
};

        
width  /= arcScaleX Z;
        
height /= arcScaleY Z;
        var 
dimension m.max(widthheight);
        
shift fillStyle.r0_ dimension;
        
expansion fillStyle.r1_ dimension shift;
      }

      
// We need to sort the color stops in ascending order by offset,
      // otherwise IE won't interpret it correctly.
      
var stops fillStyle.colors_;
      
stops.sort(function(cs1cs2) {
        return 
cs1.offset cs2.offset;
      });

      var 
length stops.length;
      var 
color1 stops[0].color;
      var 
color2 stops[length 1].color;
      var 
opacity1 stops[0].alpha ctx.globalAlpha;
      var 
opacity2 stops[length 1].alpha ctx.globalAlpha;

      var 
colors = [];
      for (var 
0lengthi++) {
        var 
stop stops[i];
        
colors.push(stop.offset expansion shift ' ' stop.color);
      }

      
// When colors attribute is used, the meanings of opacity and o:opacity2
      // are reversed.
      
lineStr.push('<g_vml_:fill type="'fillStyle.type_'"',
                   
' method="none" focus="100%"',
                   
' color="'color1'"',
                   
' color2="'color2'"',
                   
' colors="'colors.join(','), '"',
                   
' opacity="'opacity2'"',
                   
' g_o_:opacity2="'opacity1'"',
                   
' angle="'angle'"',
                   
' focusposition="'focus.x','focus.y'" />');
    } else if (
fillStyle instanceof CanvasPattern_) {
      if (
width && height) {
        var 
deltaLeft = -min.x;
        var 
deltaTop = -min.y;
        
lineStr.push('<g_vml_:fill',
                     
' position="',
                     
deltaLeft width arcScaleX arcScaleX',',
                     
deltaTop height arcScaleY arcScaleY'"',
                     
' type="tile"',
                     
// TODO: Figure out the correct size to fit the scale.
                     //' size="', w, 'px ', h, 'px"',
                     
' src="'fillStyle.src_'" />');
       }
    } else {
      var 
processStyle(ctx.fillStyle);
      var 
color a.color;
      var 
opacity a.alpha ctx.globalAlpha;
      
lineStr.push('<g_vml_:fill color="'color'" opacity="'opacity,
                   
'" />');
    }
  }

  
contextPrototype.fill = function() {
    
this.stroke(true);
  };

  
contextPrototype.closePath = function() {
    
this.currentPath_.push({type'close'});
  };

  function 
getCoords(ctxaXaY) {
    var 
ctx.m_;
    return {
      
x* (aX m[0][0] + aY m[1][0] + m[2][0]) - Z2,
      
y* (aX m[0][1] + aY m[1][1] + m[2][1]) - Z2
    
};
  };

  
contextPrototype.save = function() {
    var 
= {};
    
copyState(thiso);
    
this.aStack_.push(o);
    
this.mStack_.push(this.m_);
    
this.m_ matrixMultiply(createMatrixIdentity(), this.m_);
  };

  
contextPrototype.restore = function() {
    if (
this.aStack_.length) {
      
copyState(this.aStack_.pop(), this);
      
this.m_ this.mStack_.pop();
    }
  };

  function 
matrixIsFinite(m) {
    return 
isFinite(m[0][0]) && isFinite(m[0][1]) &&
        
isFinite(m[1][0]) && isFinite(m[1][1]) &&
        
isFinite(m[2][0]) && isFinite(m[2][1]);
  }

  function 
setM(ctxmupdateLineScale) {
    if (!
matrixIsFinite(m)) {
      return;
    }
    
ctx.m_ m;

    if (
updateLineScale) {
      
// Get the line scale.
      // Determinant of this.m_ means how much the area is enlarged by the
      // transformation. So its square root can be used as a scale factor
      // for width.
      
var det m[0][0] * m[1][1] - m[0][1] * m[1][0];
      
ctx.lineScale_ sqrt(abs(det));
    }
  }

  
contextPrototype.translate = function(aXaY) {
    var 
m1 = [
      [
1,  0,  0],
      [
0,  1,  0],
      [
aXaY1]
    ];

    
setM(thismatrixMultiply(m1this.m_), false);
  };

  
contextPrototype.rotate = function(aRot) {
    var 
mc(aRot);
    var 
ms(aRot);

    var 
m1 = [
      [
c,  s0],
      [-
sc0],
      [
0,  01]
    ];

    
setM(thismatrixMultiply(m1this.m_), false);
  };

  
contextPrototype.scale = function(aXaY) {
    
this.arcScaleX_ *= aX;
    
this.arcScaleY_ *= aY;
    var 
m1 = [
      [
aX0,  0],
      [
0,  aY0],
      [
0,  0,  1]
    ];

    
setM(thismatrixMultiply(m1this.m_), true);
  };

  
contextPrototype.transform = function(m11m12m21m22dxdy) {
    var 
m1 = [
      [
m11m120],
      [
m21m220],
      [
dx,  dy,  1]
    ];

    
setM(thismatrixMultiply(m1this.m_), true);
  };

  
contextPrototype.setTransform = function(m11m12m21m22dxdy) {
    var 
= [
      [
m11m120],
      [
m21m220],
      [
dx,  dy,  1]
    ];

    
setM(thismtrue);
  };

  
/**
   * The text drawing function.
   * The maxWidth argument isn't taken in account, since no browser supports
   * it yet.
   */
  
contextPrototype.drawText_ = function(textxymaxWidthstroke) {
    var 
this.m_,
        
delta 1000,
        
left 0,
        
right delta,
        
offset = {x0y0},
        
lineStr = [];

    var 
fontStyle getComputedStyle(processFontStyle(this.font),
                                     
this.element_);

    var 
fontStyleString buildStyle(fontStyle);

    var 
elementStyle this.element_.currentStyle;
    var 
textAlign this.textAlign.toLowerCase();
    switch (
textAlign) {
      case 
'left':
      case 
'center':
      case 
'right':
        break;
      case 
'end':
        
textAlign elementStyle.direction == 'ltr' 'right' 'left';
        break;
      case 
'start':
        
textAlign elementStyle.direction == 'rtl' 'right' 'left';
        break;
      default:
        
textAlign 'left';
    }

    
// 1.75 is an arbitrary number, as there is no info about the text baseline
    
switch (this.textBaseline) {
      case 
'hanging':
      case 
'top':
        
offset.fontStyle.size 1.75;
        break;
      case 
'middle':
        break;
      default:
      case 
null:
      case 
'alphabetic':
      case 
'ideographic':
      case 
'bottom':
        
offset.= -fontStyle.size 2.25;
        break;
    }

    switch(
textAlign) {
      case 
'right':
        
left delta;
        
right 0.05;
        break;
      case 
'center':
        
left right delta 2;
        break;
    }

    var 
getCoords(thisoffset.xoffset.y);

    
lineStr.push('<g_vml_:line from="', -left ,' 0" to="'right ,' 0.05" ',
                 
' coordsize="100 100" coordorigin="0 0"',
                 
' filled="', !stroke'" stroked="', !!stroke,
                 
'" style="position:absolute;width:1px;height:1px;">');

    if (
stroke) {
      
appendStroke(thislineStr);
    } else {
      
// TODO: Fix the min and max params.
      
appendFill(thislineStr, {x: -lefty0},
                 {
xrightyfontStyle.size});
    }

    var 
skewM m[0][0].toFixed(3) + ',' m[1][0].toFixed(3) + ',' +
                
m[0][1].toFixed(3) + ',' m[1][1].toFixed(3) + ',0,0';

    var 
skewOffset mr(d.Z) + ',' mr(d.Z);

    
lineStr.push('<g_vml_:skew on="t" matrix="'skewM ,'" ',
                 
' offset="'skewOffset'" origin="'left ,' 0" />',
                 
'<g_vml_:path textpathok="true" />',
                 
'<g_vml_:textpath on="true" string="',
                 
encodeHtmlAttribute(text),
                 
'" style="v-text-align:'textAlign,
                 
';font:'encodeHtmlAttribute(fontStyleString),
                 
'" /></g_vml_:line>');

    
this.element_.insertAdjacentHTML('beforeEnd'lineStr.join(''));
  };

  
contextPrototype.fillText = function(textxymaxWidth) {
    
this.drawText_(textxymaxWidthfalse);
  };

  
contextPrototype.strokeText = function(textxymaxWidth) {
    
this.drawText_(textxymaxWidthtrue);
  };

  
contextPrototype.measureText = function(text) {
    if (!
this.textMeasureEl_) {
      var 
'<span style="position:absolute;' +
          
'top:-20000px;left:0;padding:0;margin:0;border:none;' +
          
'white-space:pre;"></span>';
      
this.element_.insertAdjacentHTML('beforeEnd's);
      
this.textMeasureEl_ this.element_.lastChild;
    }
    var 
doc this.element_.ownerDocument;
    
this.textMeasureEl_.innerHTML '';
    
this.textMeasureEl_.style.font this.font;
    
// Don't use innerHTML or innerText because they allow markup/whitespace.
    
this.textMeasureEl_.appendChild(doc.createTextNode(text));
    return {
widththis.textMeasureEl_.offsetWidth};
  };

  
/******** STUBS ********/
  
contextPrototype.clip = function() {
    
// TODO: Implement
  
};

  
contextPrototype.arcTo = function() {
    
// TODO: Implement
  
};

  
contextPrototype.createPattern = function(imagerepetition) {
    return new 
CanvasPattern_(imagerepetition);
  };

  
// Gradient / Pattern Stubs
  
function CanvasGradient_(aType) {
    
this.type_ aType;
    
this.x0_ 0;
    
this.y0_ 0;
    
this.r0_ 0;
    
this.x1_ 0;
    
this.y1_ 0;
    
this.r1_ 0;
    
this.colors_ = [];
  }

  
CanvasGradient_.prototype.addColorStop = function(aOffsetaColor) {
    
aColor processStyle(aColor);
    
this.colors_.push({offsetaOffset,
                       
coloraColor.color,
                       
alphaaColor.alpha});
  };

  function 
CanvasPattern_(imagerepetition) {
    
assertImageIsValid(image);
    switch (
repetition) {
      case 
'repeat':
      case 
null:
      case 
'':
        
this.repetition_ 'repeat';
        break
      case 
'repeat-x':
      case 
'repeat-y':
      case 
'no-repeat':
        
this.repetition_ repetition;
        break;
      default:
        
throwException('SYNTAX_ERR');
    }

    
this.src_ image.src;
    
this.width_ image.width;
    
this.height_ image.height;
  }

  function 
throwException(s) {
    throw new 
DOMException_(s);
  }

  function 
assertImageIsValid(img) {
    if (!
img || img.nodeType != || img.tagName != 'IMG') {
      
throwException('TYPE_MISMATCH_ERR');
    }
    if (
img.readyState != 'complete') {
      
throwException('INVALID_STATE_ERR');
    }
  }

  function 
DOMException_(s) {
    
this.code this[s];
    
this.message +': DOM Exception ' this.code;
  }
  var 
DOMException_.prototype = new Error;
  
p.INDEX_SIZE_ERR 1;
  
p.DOMSTRING_SIZE_ERR 2;
  
p.HIERARCHY_REQUEST_ERR 3;
  
p.WRONG_DOCUMENT_ERR 4;
  
p.INVALID_CHARACTER_ERR 5;
  
p.NO_DATA_ALLOWED_ERR 6;
  
p.NO_MODIFICATION_ALLOWED_ERR 7;
  
p.NOT_FOUND_ERR 8;
  
p.NOT_SUPPORTED_ERR 9;
  
p.INUSE_ATTRIBUTE_ERR 10;
  
p.INVALID_STATE_ERR 11;
  
p.SYNTAX_ERR 12;
  
p.INVALID_MODIFICATION_ERR 13;
  
p.NAMESPACE_ERR 14;
  
p.INVALID_ACCESS_ERR 15;
  
p.VALIDATION_ERR 16;
  
p.TYPE_MISMATCH_ERR 17;

  
// set up externs
  
G_vmlCanvasManager G_vmlCanvasManager_;
  
CanvasRenderingContext2D CanvasRenderingContext2D_;
  
CanvasGradient CanvasGradient_;
  
CanvasPattern CanvasPattern_;
  
DOMException DOMException_;
})();

// if
?>
Онлайн: 1
Реклама