yujian
2020-06-09 554de444b87aab5f93cb1593a8095612cf9479a7
fanli/src/main/webapp/admin/new/js/third-party/highcharts/modules/exporting.src.js
@@ -1,709 +1,709 @@
/**
 * @license Highcharts JS v3.0.6 (2013-10-04)
 * Exporting module
 *
 * (c) 2010-2013 Torstein Hønsi
 *
 * License: www.highcharts.com/license
 */
// JSLint options:
/*global Highcharts, document, window, Math, setTimeout */
(function (Highcharts) { // encapsulate
// create shortcuts
var Chart = Highcharts.Chart,
   addEvent = Highcharts.addEvent,
   removeEvent = Highcharts.removeEvent,
   createElement = Highcharts.createElement,
   discardElement = Highcharts.discardElement,
   css = Highcharts.css,
   merge = Highcharts.merge,
   each = Highcharts.each,
   extend = Highcharts.extend,
   math = Math,
   mathMax = math.max,
   doc = document,
   win = window,
   isTouchDevice = Highcharts.isTouchDevice,
   M = 'M',
   L = 'L',
   DIV = 'div',
   HIDDEN = 'hidden',
   NONE = 'none',
   PREFIX = 'highcharts-',
   ABSOLUTE = 'absolute',
   PX = 'px',
   UNDEFINED,
   symbols = Highcharts.Renderer.prototype.symbols,
   defaultOptions = Highcharts.getOptions(),
   buttonOffset;
   // Add language
   extend(defaultOptions.lang, {
      printChart: 'Print chart',
      downloadPNG: 'Download PNG image',
      downloadJPEG: 'Download JPEG image',
      downloadPDF: 'Download PDF document',
      downloadSVG: 'Download SVG vector image',
      contextButtonTitle: 'Chart context menu'
   });
// Buttons and menus are collected in a separate config option set called 'navigation'.
// This can be extended later to add control buttons like zoom and pan right click menus.
defaultOptions.navigation = {
   menuStyle: {
      border: '1px solid #A0A0A0',
      background: '#FFFFFF',
      padding: '5px 0'
   },
   menuItemStyle: {
      padding: '0 10px',
      background: NONE,
      color: '#303030',
      fontSize: isTouchDevice ? '14px' : '11px'
   },
   menuItemHoverStyle: {
      background: '#4572A5',
      color: '#FFFFFF'
   },
   buttonOptions: {
      symbolFill: '#E0E0E0',
      symbolSize: 14,
      symbolStroke: '#666',
      symbolStrokeWidth: 3,
      symbolX: 12.5,
      symbolY: 10.5,
      align: 'right',
      buttonSpacing: 3,
      height: 22,
      // text: null,
      theme: {
         fill: 'white', // capture hover
         stroke: 'none'
      },
      verticalAlign: 'top',
      width: 24
   }
};
// Add the export related options
defaultOptions.exporting = {
   //enabled: true,
   //filename: 'chart',
   type: 'image/png',
   url: 'http://export.highcharts.com/',
   //width: undefined,
   //scale: 2
   buttons: {
      contextButton: {
         menuClassName: PREFIX + 'contextmenu',
         //x: -10,
         symbol: 'menu',
         _titleKey: 'contextButtonTitle',
         menuItems: [{
            textKey: 'printChart',
            onclick: function () {
               this.print();
            }
         }, {
            separator: true
         }, {
            textKey: 'downloadPNG',
            onclick: function () {
               this.exportChart();
            }
         }, {
            textKey: 'downloadJPEG',
            onclick: function () {
               this.exportChart({
                  type: 'image/jpeg'
               });
            }
         }, {
            textKey: 'downloadPDF',
            onclick: function () {
               this.exportChart({
                  type: 'application/pdf'
               });
            }
         }, {
            textKey: 'downloadSVG',
            onclick: function () {
               this.exportChart({
                  type: 'image/svg+xml'
               });
            }
         }
         // Enable this block to add "View SVG" to the dropdown menu
         /*
         ,{
            text: 'View SVG',
            onclick: function () {
               var svg = this.getSVG()
                  .replace(/</g, '\n&lt;')
                  .replace(/>/g, '&gt;');
               doc.body.innerHTML = '<pre>' + svg + '</pre>';
            }
         } // */
         ]
      }
   }
};
// Add the Highcharts.post utility
Highcharts.post = function (url, data) {
   var name,
      form;
   // create the form
   form = createElement('form', {
      method: 'post',
      action: url,
      enctype: 'multipart/form-data'
   }, {
      display: NONE
   }, doc.body);
   // add the data
   for (name in data) {
      createElement('input', {
         type: HIDDEN,
         name: name,
         value: data[name]
      }, null, form);
   }
   // submit
   form.submit();
   // clean up
   discardElement(form);
};
extend(Chart.prototype, {
   /**
    * Return an SVG representation of the chart
    *
    * @param additionalOptions {Object} Additional chart options for the generated SVG representation
    */
   getSVG: function (additionalOptions) {
      var chart = this,
         chartCopy,
         sandbox,
         svg,
         seriesOptions,
         sourceWidth,
         sourceHeight,
         cssWidth,
         cssHeight,
         options = merge(chart.options, additionalOptions); // copy the options and add extra options
      // IE compatibility hack for generating SVG content that it doesn't really understand
      if (!doc.createElementNS) {
         /*jslint unparam: true*//* allow unused parameter ns in function below */
         doc.createElementNS = function (ns, tagName) {
            return doc.createElement(tagName);
         };
         /*jslint unparam: false*/
      }
      // create a sandbox where a new chart will be generated
      sandbox = createElement(DIV, null, {
         position: ABSOLUTE,
         top: '-9999em',
         width: chart.chartWidth + PX,
         height: chart.chartHeight + PX
      }, doc.body);
      // get the source size
      cssWidth = chart.renderTo.style.width;
      cssHeight = chart.renderTo.style.height;
      sourceWidth = options.exporting.sourceWidth ||
         options.chart.width ||
         (/px$/.test(cssWidth) && parseInt(cssWidth, 10)) ||
         600;
      sourceHeight = options.exporting.sourceHeight ||
         options.chart.height ||
         (/px$/.test(cssHeight) && parseInt(cssHeight, 10)) ||
         400;
      // override some options
      extend(options.chart, {
         animation: false,
         renderTo: sandbox,
         forExport: true,
         width: sourceWidth,
         height: sourceHeight
      });
      options.exporting.enabled = false; // hide buttons in print
      // prepare for replicating the chart
      options.series = [];
      each(chart.series, function (serie) {
         seriesOptions = merge(serie.options, {
            animation: false, // turn off animation
            showCheckbox: false,
            visible: serie.visible
         });
         if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
            options.series.push(seriesOptions);
         }
      });
      // generate the chart copy
      chartCopy = new Highcharts.Chart(options, chart.callback);
      // reflect axis extremes in the export
      each(['xAxis', 'yAxis'], function (axisType) {
         each(chart[axisType], function (axis, i) {
            var axisCopy = chartCopy[axisType][i],
               extremes = axis.getExtremes(),
               userMin = extremes.userMin,
               userMax = extremes.userMax;
            if (axisCopy && (userMin !== UNDEFINED || userMax !== UNDEFINED)) {
               axisCopy.setExtremes(userMin, userMax, true, false);
            }
         });
      });
      // get the SVG from the container's innerHTML
      svg = chartCopy.container.innerHTML;
      // free up memory
      options = null;
      chartCopy.destroy();
      discardElement(sandbox);
      // sanitize
      svg = svg
         .replace(/zIndex="[^"]+"/g, '')
         .replace(/isShadow="[^"]+"/g, '')
         .replace(/symbolName="[^"]+"/g, '')
         .replace(/jQuery[0-9]+="[^"]+"/g, '')
         .replace(/url\([^#]+#/g, 'url(#')
         .replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
         .replace(/ href=/g, ' xlink:href=')
         .replace(/\n/, ' ')
         .replace(/<\/svg>.*?$/, '</svg>') // any HTML added to the container after the SVG (#894)
         /* This fails in IE < 8
         .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
            return s2 +'.'+ s3[0];
         })*/
         // Replace HTML entities, issue #347
         .replace(/&nbsp;/g, '\u00A0') // no-break space
         .replace(/&shy;/g,  '\u00AD') // soft hyphen
         // IE specific
         .replace(/<IMG /g, '<image ')
         .replace(/height=([^" ]+)/g, 'height="$1"')
         .replace(/width=([^" ]+)/g, 'width="$1"')
         .replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
         .replace(/id=([^" >]+)/g, 'id="$1"')
         .replace(/class=([^" >]+)/g, 'class="$1"')
         .replace(/ transform /g, ' ')
         .replace(/:(path|rect)/g, '$1')
         .replace(/style="([^"]+)"/g, function (s) {
            return s.toLowerCase();
         });
      // IE9 beta bugs with innerHTML. Test again with final IE9.
      svg = svg.replace(/(url\(#highcharts-[0-9]+)&quot;/g, '$1')
         .replace(/&quot;/g, "'");
      return svg;
   },
   /**
    * Submit the SVG representation of the chart to the server
    * @param {Object} options Exporting options. Possible members are url, type and width.
    * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
    */
   exportChart: function (options, chartOptions) {
      options = options || {};
      var chart = this,
         chartExportingOptions = chart.options.exporting,
         svg = chart.getSVG(merge(
            { chart: { borderRadius: 0 } },
            chartExportingOptions.chartOptions,
            chartOptions,
            {
               exporting: {
                  sourceWidth: options.sourceWidth || chartExportingOptions.sourceWidth,
                  sourceHeight: options.sourceHeight || chartExportingOptions.sourceHeight
               }
            }
         ));
      // merge the options
      options = merge(chart.options.exporting, options);
      // do the post
      Highcharts.post(options.url, {
         filename: options.filename || 'chart',
         type: options.type,
         width: options.width || 0, // IE8 fails to post undefined correctly, so use 0
         scale: options.scale || 2,
         svg: svg
      });
   },
   /**
    * Print the chart
    */
   print: function () {
      var chart = this,
         container = chart.container,
         origDisplay = [],
         origParent = container.parentNode,
         body = doc.body,
         childNodes = body.childNodes;
      if (chart.isPrinting) { // block the button while in printing mode
         return;
      }
      chart.isPrinting = true;
      // hide all body content
      each(childNodes, function (node, i) {
         if (node.nodeType === 1) {
            origDisplay[i] = node.style.display;
            node.style.display = NONE;
         }
      });
      // pull out the chart
      body.appendChild(container);
      // print
      win.focus(); // #1510
      win.print();
      // allow the browser to prepare before reverting
      setTimeout(function () {
         // put the chart back in
         origParent.appendChild(container);
         // restore all body content
         each(childNodes, function (node, i) {
            if (node.nodeType === 1) {
               node.style.display = origDisplay[i];
            }
         });
         chart.isPrinting = false;
      }, 1000);
   },
   /**
    * Display a popup menu for choosing the export type
    *
    * @param {String} className An identifier for the menu
    * @param {Array} items A collection with text and onclicks for the items
    * @param {Number} x The x position of the opener button
    * @param {Number} y The y position of the opener button
    * @param {Number} width The width of the opener button
    * @param {Number} height The height of the opener button
    */
   contextMenu: function (className, items, x, y, width, height, button) {
      var chart = this,
         navOptions = chart.options.navigation,
         menuItemStyle = navOptions.menuItemStyle,
         chartWidth = chart.chartWidth,
         chartHeight = chart.chartHeight,
         cacheName = 'cache-' + className,
         menu = chart[cacheName],
         menuPadding = mathMax(width, height), // for mouse leave detection
         boxShadow = '3px 3px 10px #888',
         innerMenu,
         hide,
         hideTimer,
         menuStyle;
      // create the menu only the first time
      if (!menu) {
         // create a HTML element above the SVG
         chart[cacheName] = menu = createElement(DIV, {
            className: className
         }, {
            position: ABSOLUTE,
            zIndex: 1000,
            padding: menuPadding + PX
         }, chart.container);
         innerMenu = createElement(DIV, null,
            extend({
               MozBoxShadow: boxShadow,
               WebkitBoxShadow: boxShadow,
               boxShadow: boxShadow
            }, navOptions.menuStyle), menu);
         // hide on mouse out
         hide = function () {
            css(menu, { display: NONE });
            if (button) {
               button.setState(0);
            }
            chart.openMenu = false;
         };
         // Hide the menu some time after mouse leave (#1357)
         addEvent(menu, 'mouseleave', function () {
            hideTimer = setTimeout(hide, 500);
         });
         addEvent(menu, 'mouseenter', function () {
            clearTimeout(hideTimer);
         });
         // Hide it on clicking or touching outside the menu (#2258)
         addEvent(document, 'mousedown', function (e) {
            if (!chart.pointer.inClass(e.target, className)) {
               hide();
            }
         });
         // create the items
         each(items, function (item) {
            if (item) {
               var element = item.separator ?
                  createElement('hr', null, null, innerMenu) :
                  createElement(DIV, {
                     onmouseover: function () {
                        css(this, navOptions.menuItemHoverStyle);
                     },
                     onmouseout: function () {
                        css(this, menuItemStyle);
                     },
                     onclick: function () {
                        hide();
                        item.onclick.apply(chart, arguments);
                     },
                     innerHTML: item.text || chart.options.lang[item.textKey]
                  }, extend({
                     cursor: 'pointer'
                  }, menuItemStyle), innerMenu);
               // Keep references to menu divs to be able to destroy them
               chart.exportDivElements.push(element);
            }
         });
         // Keep references to menu and innerMenu div to be able to destroy them
         chart.exportDivElements.push(innerMenu, menu);
         chart.exportMenuWidth = menu.offsetWidth;
         chart.exportMenuHeight = menu.offsetHeight;
      }
      menuStyle = { display: 'block' };
      // if outside right, right align it
      if (x + chart.exportMenuWidth > chartWidth) {
         menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
      } else {
         menuStyle.left = (x - menuPadding) + PX;
      }
      // if outside bottom, bottom align it
      if (y + height + chart.exportMenuHeight > chartHeight && button.alignOptions.verticalAlign !== 'top') {
         menuStyle.bottom = (chartHeight - y - menuPadding)  + PX;
      } else {
         menuStyle.top = (y + height - menuPadding) + PX;
      }
      css(menu, menuStyle);
      chart.openMenu = true;
   },
   /**
    * Add the export button to the chart
    */
   addButton: function (options) {
      var chart = this,
         renderer = chart.renderer,
         btnOptions = merge(chart.options.navigation.buttonOptions, options),
         onclick = btnOptions.onclick,
         menuItems = btnOptions.menuItems,
         symbol,
         button,
         symbolAttr = {
            stroke: btnOptions.symbolStroke,
            fill: btnOptions.symbolFill
         },
         symbolSize = btnOptions.symbolSize || 12;
      if (!chart.btnCount) {
         chart.btnCount = 0;
      }
      // Keeps references to the button elements
      if (!chart.exportDivElements) {
         chart.exportDivElements = [];
         chart.exportSVGElements = [];
      }
      if (btnOptions.enabled === false) {
         return;
      }
      var attr = btnOptions.theme,
         states = attr.states,
         hover = states && states.hover,
         select = states && states.select,
         callback;
      delete attr.states;
      if (onclick) {
         callback = function () {
            onclick.apply(chart, arguments);
         };
      } else if (menuItems) {
         callback = function () {
            chart.contextMenu(
               button.menuClassName,
               menuItems,
               button.translateX,
               button.translateY,
               button.width,
               button.height,
               button
            );
            button.setState(2);
         };
      }
      if (btnOptions.text && btnOptions.symbol) {
         attr.paddingLeft = Highcharts.pick(attr.paddingLeft, 25);
      } else if (!btnOptions.text) {
         extend(attr, {
            width: btnOptions.width,
            height: btnOptions.height,
            padding: 0
         });
      }
      button = renderer.button(btnOptions.text, 0, 0, callback, attr, hover, select)
         .attr({
            title: chart.options.lang[btnOptions._titleKey],
            'stroke-linecap': 'round'
         });
      button.menuClassName = options.menuClassName || PREFIX + 'menu-' + chart.btnCount++;
      if (btnOptions.symbol) {
         symbol = renderer.symbol(
               btnOptions.symbol,
               btnOptions.symbolX - (symbolSize / 2),
               btnOptions.symbolY - (symbolSize / 2),
               symbolSize,
               symbolSize
            )
            .attr(extend(symbolAttr, {
               'stroke-width': btnOptions.symbolStrokeWidth || 1,
               zIndex: 1
            })).add(button);
      }
      button.add()
         .align(extend(btnOptions, {
            width: button.width,
            x: Highcharts.pick(btnOptions.x, buttonOffset) // #1654
         }), true, 'spacingBox');
      buttonOffset += (button.width + btnOptions.buttonSpacing) * (btnOptions.align === 'right' ? -1 : 1);
      chart.exportSVGElements.push(button, symbol);
   },
   /**
    * Destroy the buttons.
    */
   destroyExport: function (e) {
      var chart = e.target,
         i,
         elem;
      // Destroy the extra buttons added
      for (i = 0; i < chart.exportSVGElements.length; i++) {
         elem = chart.exportSVGElements[i];
         // Destroy and null the svg/vml elements
         if (elem) { // #1822
            elem.onclick = elem.ontouchstart = null;
            chart.exportSVGElements[i] = elem.destroy();
         }
      }
      // Destroy the divs for the menu
      for (i = 0; i < chart.exportDivElements.length; i++) {
         elem = chart.exportDivElements[i];
         // Remove the event handler
         removeEvent(elem, 'mouseleave');
         // Remove inline events
         chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
         // Destroy the div by moving to garbage bin
         discardElement(elem);
      }
   }
});
symbols.menu = function (x, y, width, height) {
   var arr = [
      M, x, y + 2.5,
      L, x + width, y + 2.5,
      M, x, y + height / 2 + 0.5,
      L, x + width, y + height / 2 + 0.5,
      M, x, y + height - 1.5,
      L, x + width, y + height - 1.5
   ];
   return arr;
};
// Add the buttons on chart load
Chart.prototype.callbacks.push(function (chart) {
   var n,
      exportingOptions = chart.options.exporting,
      buttons = exportingOptions.buttons;
   buttonOffset = 0;
   if (exportingOptions.enabled !== false) {
      for (n in buttons) {
         chart.addButton(buttons[n]);
      }
      // Destroy the export elements at chart destroy
      addEvent(chart, 'destroy', chart.destroyExport);
   }
});
}(Highcharts));
/**
 * @license Highcharts JS v3.0.6 (2013-10-04)
 * Exporting module
 *
 * (c) 2010-2013 Torstein Hønsi
 *
 * License: www.highcharts.com/license
 */
// JSLint options:
/*global Highcharts, document, window, Math, setTimeout */
(function (Highcharts) { // encapsulate
// create shortcuts
var Chart = Highcharts.Chart,
   addEvent = Highcharts.addEvent,
   removeEvent = Highcharts.removeEvent,
   createElement = Highcharts.createElement,
   discardElement = Highcharts.discardElement,
   css = Highcharts.css,
   merge = Highcharts.merge,
   each = Highcharts.each,
   extend = Highcharts.extend,
   math = Math,
   mathMax = math.max,
   doc = document,
   win = window,
   isTouchDevice = Highcharts.isTouchDevice,
   M = 'M',
   L = 'L',
   DIV = 'div',
   HIDDEN = 'hidden',
   NONE = 'none',
   PREFIX = 'highcharts-',
   ABSOLUTE = 'absolute',
   PX = 'px',
   UNDEFINED,
   symbols = Highcharts.Renderer.prototype.symbols,
   defaultOptions = Highcharts.getOptions(),
   buttonOffset;
   // Add language
   extend(defaultOptions.lang, {
      printChart: 'Print chart',
      downloadPNG: 'Download PNG image',
      downloadJPEG: 'Download JPEG image',
      downloadPDF: 'Download PDF document',
      downloadSVG: 'Download SVG vector image',
      contextButtonTitle: 'Chart context menu'
   });
// Buttons and menus are collected in a separate config option set called 'navigation'.
// This can be extended later to add control buttons like zoom and pan right click menus.
defaultOptions.navigation = {
   menuStyle: {
      border: '1px solid #A0A0A0',
      background: '#FFFFFF',
      padding: '5px 0'
   },
   menuItemStyle: {
      padding: '0 10px',
      background: NONE,
      color: '#303030',
      fontSize: isTouchDevice ? '14px' : '11px'
   },
   menuItemHoverStyle: {
      background: '#4572A5',
      color: '#FFFFFF'
   },
   buttonOptions: {
      symbolFill: '#E0E0E0',
      symbolSize: 14,
      symbolStroke: '#666',
      symbolStrokeWidth: 3,
      symbolX: 12.5,
      symbolY: 10.5,
      align: 'right',
      buttonSpacing: 3,
      height: 22,
      // text: null,
      theme: {
         fill: 'white', // capture hover
         stroke: 'none'
      },
      verticalAlign: 'top',
      width: 24
   }
};
// Add the export related options
defaultOptions.exporting = {
   //enabled: true,
   //filename: 'chart',
   type: 'image/png',
   url: 'http://export.highcharts.com/',
   //width: undefined,
   //scale: 2
   buttons: {
      contextButton: {
         menuClassName: PREFIX + 'contextmenu',
         //x: -10,
         symbol: 'menu',
         _titleKey: 'contextButtonTitle',
         menuItems: [{
            textKey: 'printChart',
            onclick: function () {
               this.print();
            }
         }, {
            separator: true
         }, {
            textKey: 'downloadPNG',
            onclick: function () {
               this.exportChart();
            }
         }, {
            textKey: 'downloadJPEG',
            onclick: function () {
               this.exportChart({
                  type: 'image/jpeg'
               });
            }
         }, {
            textKey: 'downloadPDF',
            onclick: function () {
               this.exportChart({
                  type: 'application/pdf'
               });
            }
         }, {
            textKey: 'downloadSVG',
            onclick: function () {
               this.exportChart({
                  type: 'image/svg+xml'
               });
            }
         }
         // Enable this block to add "View SVG" to the dropdown menu
         /*
         ,{
            text: 'View SVG',
            onclick: function () {
               var svg = this.getSVG()
                  .replace(/</g, '\n&lt;')
                  .replace(/>/g, '&gt;');
               doc.body.innerHTML = '<pre>' + svg + '</pre>';
            }
         } // */
         ]
      }
   }
};
// Add the Highcharts.post utility
Highcharts.post = function (url, data) {
   var name,
      form;
   // create the form
   form = createElement('form', {
      method: 'post',
      action: url,
      enctype: 'multipart/form-data'
   }, {
      display: NONE
   }, doc.body);
   // add the data
   for (name in data) {
      createElement('input', {
         type: HIDDEN,
         name: name,
         value: data[name]
      }, null, form);
   }
   // submit
   form.submit();
   // clean up
   discardElement(form);
};
extend(Chart.prototype, {
   /**
    * Return an SVG representation of the chart
    *
    * @param additionalOptions {Object} Additional chart options for the generated SVG representation
    */
   getSVG: function (additionalOptions) {
      var chart = this,
         chartCopy,
         sandbox,
         svg,
         seriesOptions,
         sourceWidth,
         sourceHeight,
         cssWidth,
         cssHeight,
         options = merge(chart.options, additionalOptions); // copy the options and add extra options
      // IE compatibility hack for generating SVG content that it doesn't really understand
      if (!doc.createElementNS) {
         /*jslint unparam: true*//* allow unused parameter ns in function below */
         doc.createElementNS = function (ns, tagName) {
            return doc.createElement(tagName);
         };
         /*jslint unparam: false*/
      }
      // create a sandbox where a new chart will be generated
      sandbox = createElement(DIV, null, {
         position: ABSOLUTE,
         top: '-9999em',
         width: chart.chartWidth + PX,
         height: chart.chartHeight + PX
      }, doc.body);
      // get the source size
      cssWidth = chart.renderTo.style.width;
      cssHeight = chart.renderTo.style.height;
      sourceWidth = options.exporting.sourceWidth ||
         options.chart.width ||
         (/px$/.test(cssWidth) && parseInt(cssWidth, 10)) ||
         600;
      sourceHeight = options.exporting.sourceHeight ||
         options.chart.height ||
         (/px$/.test(cssHeight) && parseInt(cssHeight, 10)) ||
         400;
      // override some options
      extend(options.chart, {
         animation: false,
         renderTo: sandbox,
         forExport: true,
         width: sourceWidth,
         height: sourceHeight
      });
      options.exporting.enabled = false; // hide buttons in print
      // prepare for replicating the chart
      options.series = [];
      each(chart.series, function (serie) {
         seriesOptions = merge(serie.options, {
            animation: false, // turn off animation
            showCheckbox: false,
            visible: serie.visible
         });
         if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
            options.series.push(seriesOptions);
         }
      });
      // generate the chart copy
      chartCopy = new Highcharts.Chart(options, chart.callback);
      // reflect axis extremes in the export
      each(['xAxis', 'yAxis'], function (axisType) {
         each(chart[axisType], function (axis, i) {
            var axisCopy = chartCopy[axisType][i],
               extremes = axis.getExtremes(),
               userMin = extremes.userMin,
               userMax = extremes.userMax;
            if (axisCopy && (userMin !== UNDEFINED || userMax !== UNDEFINED)) {
               axisCopy.setExtremes(userMin, userMax, true, false);
            }
         });
      });
      // get the SVG from the container's innerHTML
      svg = chartCopy.container.innerHTML;
      // free up memory
      options = null;
      chartCopy.destroy();
      discardElement(sandbox);
      // sanitize
      svg = svg
         .replace(/zIndex="[^"]+"/g, '')
         .replace(/isShadow="[^"]+"/g, '')
         .replace(/symbolName="[^"]+"/g, '')
         .replace(/jQuery[0-9]+="[^"]+"/g, '')
         .replace(/url\([^#]+#/g, 'url(#')
         .replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
         .replace(/ href=/g, ' xlink:href=')
         .replace(/\n/, ' ')
         .replace(/<\/svg>.*?$/, '</svg>') // any HTML added to the container after the SVG (#894)
         /* This fails in IE < 8
         .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
            return s2 +'.'+ s3[0];
         })*/
         // Replace HTML entities, issue #347
         .replace(/&nbsp;/g, '\u00A0') // no-break space
         .replace(/&shy;/g,  '\u00AD') // soft hyphen
         // IE specific
         .replace(/<IMG /g, '<image ')
         .replace(/height=([^" ]+)/g, 'height="$1"')
         .replace(/width=([^" ]+)/g, 'width="$1"')
         .replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
         .replace(/id=([^" >]+)/g, 'id="$1"')
         .replace(/class=([^" >]+)/g, 'class="$1"')
         .replace(/ transform /g, ' ')
         .replace(/:(path|rect)/g, '$1')
         .replace(/style="([^"]+)"/g, function (s) {
            return s.toLowerCase();
         });
      // IE9 beta bugs with innerHTML. Test again with final IE9.
      svg = svg.replace(/(url\(#highcharts-[0-9]+)&quot;/g, '$1')
         .replace(/&quot;/g, "'");
      return svg;
   },
   /**
    * Submit the SVG representation of the chart to the server
    * @param {Object} options Exporting options. Possible members are url, type and width.
    * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
    */
   exportChart: function (options, chartOptions) {
      options = options || {};
      var chart = this,
         chartExportingOptions = chart.options.exporting,
         svg = chart.getSVG(merge(
            { chart: { borderRadius: 0 } },
            chartExportingOptions.chartOptions,
            chartOptions,
            {
               exporting: {
                  sourceWidth: options.sourceWidth || chartExportingOptions.sourceWidth,
                  sourceHeight: options.sourceHeight || chartExportingOptions.sourceHeight
               }
            }
         ));
      // merge the options
      options = merge(chart.options.exporting, options);
      // do the post
      Highcharts.post(options.url, {
         filename: options.filename || 'chart',
         type: options.type,
         width: options.width || 0, // IE8 fails to post undefined correctly, so use 0
         scale: options.scale || 2,
         svg: svg
      });
   },
   /**
    * Print the chart
    */
   print: function () {
      var chart = this,
         container = chart.container,
         origDisplay = [],
         origParent = container.parentNode,
         body = doc.body,
         childNodes = body.childNodes;
      if (chart.isPrinting) { // block the button while in printing mode
         return;
      }
      chart.isPrinting = true;
      // hide all body content
      each(childNodes, function (node, i) {
         if (node.nodeType === 1) {
            origDisplay[i] = node.style.display;
            node.style.display = NONE;
         }
      });
      // pull out the chart
      body.appendChild(container);
      // print
      win.focus(); // #1510
      win.print();
      // allow the browser to prepare before reverting
      setTimeout(function () {
         // put the chart back in
         origParent.appendChild(container);
         // restore all body content
         each(childNodes, function (node, i) {
            if (node.nodeType === 1) {
               node.style.display = origDisplay[i];
            }
         });
         chart.isPrinting = false;
      }, 1000);
   },
   /**
    * Display a popup menu for choosing the export type
    *
    * @param {String} className An identifier for the menu
    * @param {Array} items A collection with text and onclicks for the items
    * @param {Number} x The x position of the opener button
    * @param {Number} y The y position of the opener button
    * @param {Number} width The width of the opener button
    * @param {Number} height The height of the opener button
    */
   contextMenu: function (className, items, x, y, width, height, button) {
      var chart = this,
         navOptions = chart.options.navigation,
         menuItemStyle = navOptions.menuItemStyle,
         chartWidth = chart.chartWidth,
         chartHeight = chart.chartHeight,
         cacheName = 'cache-' + className,
         menu = chart[cacheName],
         menuPadding = mathMax(width, height), // for mouse leave detection
         boxShadow = '3px 3px 10px #888',
         innerMenu,
         hide,
         hideTimer,
         menuStyle;
      // create the menu only the first time
      if (!menu) {
         // create a HTML element above the SVG
         chart[cacheName] = menu = createElement(DIV, {
            className: className
         }, {
            position: ABSOLUTE,
            zIndex: 1000,
            padding: menuPadding + PX
         }, chart.container);
         innerMenu = createElement(DIV, null,
            extend({
               MozBoxShadow: boxShadow,
               WebkitBoxShadow: boxShadow,
               boxShadow: boxShadow
            }, navOptions.menuStyle), menu);
         // hide on mouse out
         hide = function () {
            css(menu, { display: NONE });
            if (button) {
               button.setState(0);
            }
            chart.openMenu = false;
         };
         // Hide the menu some time after mouse leave (#1357)
         addEvent(menu, 'mouseleave', function () {
            hideTimer = setTimeout(hide, 500);
         });
         addEvent(menu, 'mouseenter', function () {
            clearTimeout(hideTimer);
         });
         // Hide it on clicking or touching outside the menu (#2258)
         addEvent(document, 'mousedown', function (e) {
            if (!chart.pointer.inClass(e.target, className)) {
               hide();
            }
         });
         // create the items
         each(items, function (item) {
            if (item) {
               var element = item.separator ?
                  createElement('hr', null, null, innerMenu) :
                  createElement(DIV, {
                     onmouseover: function () {
                        css(this, navOptions.menuItemHoverStyle);
                     },
                     onmouseout: function () {
                        css(this, menuItemStyle);
                     },
                     onclick: function () {
                        hide();
                        item.onclick.apply(chart, arguments);
                     },
                     innerHTML: item.text || chart.options.lang[item.textKey]
                  }, extend({
                     cursor: 'pointer'
                  }, menuItemStyle), innerMenu);
               // Keep references to menu divs to be able to destroy them
               chart.exportDivElements.push(element);
            }
         });
         // Keep references to menu and innerMenu div to be able to destroy them
         chart.exportDivElements.push(innerMenu, menu);
         chart.exportMenuWidth = menu.offsetWidth;
         chart.exportMenuHeight = menu.offsetHeight;
      }
      menuStyle = { display: 'block' };
      // if outside right, right align it
      if (x + chart.exportMenuWidth > chartWidth) {
         menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
      } else {
         menuStyle.left = (x - menuPadding) + PX;
      }
      // if outside bottom, bottom align it
      if (y + height + chart.exportMenuHeight > chartHeight && button.alignOptions.verticalAlign !== 'top') {
         menuStyle.bottom = (chartHeight - y - menuPadding)  + PX;
      } else {
         menuStyle.top = (y + height - menuPadding) + PX;
      }
      css(menu, menuStyle);
      chart.openMenu = true;
   },
   /**
    * Add the export button to the chart
    */
   addButton: function (options) {
      var chart = this,
         renderer = chart.renderer,
         btnOptions = merge(chart.options.navigation.buttonOptions, options),
         onclick = btnOptions.onclick,
         menuItems = btnOptions.menuItems,
         symbol,
         button,
         symbolAttr = {
            stroke: btnOptions.symbolStroke,
            fill: btnOptions.symbolFill
         },
         symbolSize = btnOptions.symbolSize || 12;
      if (!chart.btnCount) {
         chart.btnCount = 0;
      }
      // Keeps references to the button elements
      if (!chart.exportDivElements) {
         chart.exportDivElements = [];
         chart.exportSVGElements = [];
      }
      if (btnOptions.enabled === false) {
         return;
      }
      var attr = btnOptions.theme,
         states = attr.states,
         hover = states && states.hover,
         select = states && states.select,
         callback;
      delete attr.states;
      if (onclick) {
         callback = function () {
            onclick.apply(chart, arguments);
         };
      } else if (menuItems) {
         callback = function () {
            chart.contextMenu(
               button.menuClassName,
               menuItems,
               button.translateX,
               button.translateY,
               button.width,
               button.height,
               button
            );
            button.setState(2);
         };
      }
      if (btnOptions.text && btnOptions.symbol) {
         attr.paddingLeft = Highcharts.pick(attr.paddingLeft, 25);
      } else if (!btnOptions.text) {
         extend(attr, {
            width: btnOptions.width,
            height: btnOptions.height,
            padding: 0
         });
      }
      button = renderer.button(btnOptions.text, 0, 0, callback, attr, hover, select)
         .attr({
            title: chart.options.lang[btnOptions._titleKey],
            'stroke-linecap': 'round'
         });
      button.menuClassName = options.menuClassName || PREFIX + 'menu-' + chart.btnCount++;
      if (btnOptions.symbol) {
         symbol = renderer.symbol(
               btnOptions.symbol,
               btnOptions.symbolX - (symbolSize / 2),
               btnOptions.symbolY - (symbolSize / 2),
               symbolSize,
               symbolSize
            )
            .attr(extend(symbolAttr, {
               'stroke-width': btnOptions.symbolStrokeWidth || 1,
               zIndex: 1
            })).add(button);
      }
      button.add()
         .align(extend(btnOptions, {
            width: button.width,
            x: Highcharts.pick(btnOptions.x, buttonOffset) // #1654
         }), true, 'spacingBox');
      buttonOffset += (button.width + btnOptions.buttonSpacing) * (btnOptions.align === 'right' ? -1 : 1);
      chart.exportSVGElements.push(button, symbol);
   },
   /**
    * Destroy the buttons.
    */
   destroyExport: function (e) {
      var chart = e.target,
         i,
         elem;
      // Destroy the extra buttons added
      for (i = 0; i < chart.exportSVGElements.length; i++) {
         elem = chart.exportSVGElements[i];
         // Destroy and null the svg/vml elements
         if (elem) { // #1822
            elem.onclick = elem.ontouchstart = null;
            chart.exportSVGElements[i] = elem.destroy();
         }
      }
      // Destroy the divs for the menu
      for (i = 0; i < chart.exportDivElements.length; i++) {
         elem = chart.exportDivElements[i];
         // Remove the event handler
         removeEvent(elem, 'mouseleave');
         // Remove inline events
         chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
         // Destroy the div by moving to garbage bin
         discardElement(elem);
      }
   }
});
symbols.menu = function (x, y, width, height) {
   var arr = [
      M, x, y + 2.5,
      L, x + width, y + 2.5,
      M, x, y + height / 2 + 0.5,
      L, x + width, y + height / 2 + 0.5,
      M, x, y + height - 1.5,
      L, x + width, y + height - 1.5
   ];
   return arr;
};
// Add the buttons on chart load
Chart.prototype.callbacks.push(function (chart) {
   var n,
      exportingOptions = chart.options.exporting,
      buttons = exportingOptions.buttons;
   buttonOffset = 0;
   if (exportingOptions.enabled !== false) {
      for (n in buttons) {
         chart.addButton(buttons[n]);
      }
      // Destroy the export elements at chart destroy
      addEvent(chart, 'destroy', chart.destroyExport);
   }
});
}(Highcharts));