Blame | Letzte Änderung | Log anzeigen | RSS feed
/*** @license Highstock JS v2.1.8 (2015-08-20)* Exporting module** (c) 2010-2014 Torstein Honsi** License: www.highcharts.com/license*/// JSLint options:/*global Highcharts, HighchartsAdapter, document, window, Math, setTimeout */(function (Highcharts) { // encapsulate// create shortcutsvar Chart = Highcharts.Chart,addEvent = Highcharts.addEvent,removeEvent = Highcharts.removeEvent,fireEvent = HighchartsAdapter.fireEvent,createElement = Highcharts.createElement,discardElement = Highcharts.discardElement,css = Highcharts.css,merge = Highcharts.merge,each = Highcharts.each,extend = Highcharts.extend,splat = Highcharts.splat,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 languageextend(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 hoverstroke: 'none'},verticalAlign: 'top',width: 24}};// Add the export related optionsdefaultOptions.exporting = {//enabled: true,//filename: 'chart',type: 'image/png',url: 'http://export.highcharts.com/',//width: undefined,//scale: 2buttons: {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<').replace(/>/g, '>');doc.body.innerHTML = '<pre>' + svg + '</pre>';}} // */]}}};// Add the Highcharts.post utilityHighcharts.post = function (url, data, formAttributes) {var name,form;// create the formform = createElement('form', merge({method: 'post',action: url,enctype: 'multipart/form-data'}, formAttributes), {display: NONE}, doc.body);// add the datafor (name in data) {createElement('input', {type: HIDDEN,name: name,value: data[name]}, null, form);}// submitform.submit();// clean updiscardElement(form);};extend(Chart.prototype, {/*** A collection of regex fixes on the produces SVG to account for expando properties,* browser bugs, VML problems and other. Returns a cleaned SVG.*/sanitizeSVG: function (svg) {return 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(/ (NS[0-9]+\:)?href=/g, ' xlink:href=') // #3567.replace(/\n/, ' ')// Any HTML added to the container after the SVG (#894).replace(/<\/svg>.*?$/, '</svg>')// Batik doesn't support rgba fills and strokes (#3095).replace(/(fill|stroke)="rgba\(([ 0-9]+,[ 0-9]+,[ 0-9]+),([ 0-9\.]+)\)"/g, '$1="rgb($2)" $1-opacity="$3"')/* This fails in IE < 8.replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weightreturn s2 +'.'+ s3[0];})*/// Replace HTML entities, issue #347.replace(/ /g, '\u00A0') // no-break space.replace(/­/g, '\u00AD') // soft hyphen// IE specific.replace(/<IMG /g, '<image ').replace(/<(\/?)TITLE>/g, '<$1title>').replace(/height=([^" ]+)/g, 'height="$1"').replace(/width=([^" ]+)/g, 'width="$1"').replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>').replace(/ id=([^" >]+)/g, ' id="$1"') // #4003.replace(/class=([^" >]+)/g, 'class="$1"').replace(/ transform /g, ' ').replace(/:(path|rect)/g, '$1').replace(/style="([^"]+)"/g, function (s) {return s.toLowerCase();});},/*** Return innerHTML of chart. Used as hook for plugins.*/getChartHTML: function () {return this.container.innerHTML;},/*** 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,html,options = merge(chart.options, additionalOptions), // copy the options and add extra optionsallowHTML = options.exporting.allowHTML; // docs: experimental, see #2473// IE compatibility hack for generating SVG content that it doesn't really understandif (!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 generatedsandbox = createElement(DIV, null, {position: ABSOLUTE,top: '-9999em',width: chart.chartWidth + PX,height: chart.chartHeight + PX}, doc.body);// get the source sizecssWidth = 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 optionsextend(options.chart, {animation: false,renderTo: sandbox,forExport: !allowHTML,width: sourceWidth,height: sourceHeight});options.exporting.enabled = false; // hide buttons in printdelete options.data; // #3004// prepare for replicating the chartoptions.series = [];each(chart.series, function (serie) {seriesOptions = merge(serie.options, {animation: false, // turn off animationenableMouseTracking: false,showCheckbox: false,visible: serie.visible});if (!seriesOptions.isInternal) { // used for the navigator series that has its own option setoptions.series.push(seriesOptions);}});// Axis options must be merged in one by one, since it may be an array or an object (#2022, #3900)if (additionalOptions) {each(['xAxis', 'yAxis'], function (axisType) {each(splat(additionalOptions[axisType]), function (axisOptions, i) {options[axisType][i] = merge(options[axisType][i], axisOptions);});});}// generate the chart copychartCopy = new Highcharts.Chart(options, chart.callback);// reflect axis extremes in the exporteach(['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 innerHTMLsvg = chartCopy.getChartHTML();// free up memoryoptions = null;chartCopy.destroy();discardElement(sandbox);// Move HTML into a foreignObjectif (allowHTML) {html = svg.match(/<\/svg>(.*?$)/);if (html) {html = '<foreignObject x="0" y="0 width="200" height="200">' +'<body xmlns="http://www.w3.org/1999/xhtml">' +html[1] +'</body>' +'</foreignObject>';svg = svg.replace('</svg>', html + '</svg>');}}// sanitizesvg = this.sanitizeSVG(svg);// IE9 beta bugs with innerHTML. Test again with final IE9.svg = svg.replace(/(url\(#highcharts-[0-9]+)"/g, '$1').replace(/"/g, "'");return svg;},getSVGForExport: function (options, chartOptions) {var chartExportingOptions = this.options.exporting;return this.getSVG(merge({ chart: { borderRadius: 0 } },chartExportingOptions.chartOptions,chartOptions,{exporting: {sourceWidth: (options && options.sourceWidth) || chartExportingOptions.sourceWidth,sourceHeight: (options && options.sourceHeight) || chartExportingOptions.sourceHeight}}));},/*** Submit the SVG representation of the chart to the server* @param {Object} options Exporting options. Possible members are url, type, width and formAttributes.* @param {Object} chartOptions Additional chart options for the SVG representation of the chart*/exportChart: function (options, chartOptions) {var svg = this.getSVGForExport(options, chartOptions);// merge the optionsoptions = merge(this.options.exporting, options);// do the postHighcharts.post(options.url, {filename: options.filename || 'chart',type: options.type,width: options.width || 0, // IE8 fails to post undefined correctly, so use 0scale: options.scale || 2,svg: svg}, options.formAttributes);},/*** 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 modereturn;}chart.isPrinting = true;fireEvent(chart, 'beforePrint');// hide all body contenteach(childNodes, function (node, i) {if (node.nodeType === 1) {origDisplay[i] = node.style.display;node.style.display = NONE;}});// pull out the chartbody.appendChild(container);win.focus(); // #1510win.print();// allow the browser to prepare before revertingsetTimeout(function () {// put the chart back inorigParent.appendChild(container);// restore all body contenteach(childNodes, function (node, i) {if (node.nodeType === 1) {node.style.display = origDisplay[i];}});chart.isPrinting = false;fireEvent(chart, 'afterPrint');}, 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 detectionboxShadow = '3px 3px 10px #888',innerMenu,hide,hideTimer,menuStyle,docMouseUpHandler = function (e) {if (!chart.pointer.inClass(e.target, className)) {hide();}};// create the menu only the first timeif (!menu) {// create a HTML element above the SVGchart[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 outhide = 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, #2335, #2407)addEvent(document, 'mouseup', docMouseUpHandler);addEvent(chart, 'destroy', function () {removeEvent(document, 'mouseup', docMouseUpHandler);});// create the itemseach(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 (e) {e.stopPropagation();hide();if (item.onclick) {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 themchart.exportDivElements.push(element);}});// Keep references to menu and innerMenu div to be able to destroy themchart.exportDivElements.push(innerMenu, menu);chart.exportMenuWidth = menu.offsetWidth;chart.exportMenuHeight = menu.offsetHeight;}menuStyle = { display: 'block' };// if outside right, right align itif (x + chart.exportMenuWidth > chartWidth) {menuStyle.right = (chartWidth - x - width - menuPadding) + PX;} else {menuStyle.left = (x - menuPadding) + PX;}// if outside bottom, bottom align itif (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 elementsif (!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 (e) {e.stopPropagation();onclick.call(chart, e);};} 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 addedfor (i = 0; i < chart.exportSVGElements.length; i++) {elem = chart.exportSVGElements[i];// Destroy and null the svg/vml elementsif (elem) { // #1822elem.onclick = elem.ontouchstart = null;chart.exportSVGElements[i] = elem.destroy();}}// Destroy the divs for the menufor (i = 0; i < chart.exportDivElements.length; i++) {elem = chart.exportDivElements[i];// Remove the event handlerremoveEvent(elem, 'mouseleave');// Remove inline eventschart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;// Destroy the div by moving to garbage bindiscardElement(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 loadChart.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 destroyaddEvent(chart, 'destroy', chart.destroyExport);}});}(Highcharts));