corrade-nucleus-nucleons – Blame information for rev 20

Subversion Repositories:
Rev:
Rev Author Line No. Line
20 office 1 /**
2 * @license Highcharts JS v5.0.12 (2017-05-24)
3 * Exporting module
4 *
5 * (c) 2010-2017 Torstein Honsi
6 *
7 * License: www.highcharts.com/license
8 */
9 'use strict';
10 (function(factory) {
11 if (typeof module === 'object' && module.exports) {
12 module.exports = factory;
13 } else {
14 factory(Highcharts);
15 }
16 }(function(Highcharts) {
17 (function(H) {
18 /**
19 * Exporting module
20 *
21 * (c) 2010-2017 Torstein Honsi
22 *
23 * License: www.highcharts.com/license
24 */
25  
26 /* eslint indent:0 */
27  
28 // create shortcuts
29 var defaultOptions = H.defaultOptions,
30 doc = H.doc,
31 Chart = H.Chart,
32 addEvent = H.addEvent,
33 removeEvent = H.removeEvent,
34 fireEvent = H.fireEvent,
35 createElement = H.createElement,
36 discardElement = H.discardElement,
37 css = H.css,
38 merge = H.merge,
39 pick = H.pick,
40 each = H.each,
41 objectEach = H.objectEach,
42 extend = H.extend,
43 isTouchDevice = H.isTouchDevice,
44 win = H.win,
45 userAgent = win.navigator.userAgent,
46 SVGRenderer = H.SVGRenderer,
47 symbols = H.Renderer.prototype.symbols,
48 isMSBrowser = /Edge\/|Trident\/|MSIE /.test(userAgent),
49 isFirefoxBrowser = /firefox/i.test(userAgent);
50  
51 // Add language
52 extend(defaultOptions.lang, {
53 printChart: 'Print chart',
54 downloadPNG: 'Download PNG image',
55 downloadJPEG: 'Download JPEG image',
56 downloadPDF: 'Download PDF document',
57 downloadSVG: 'Download SVG vector image',
58 contextButtonTitle: 'Chart context menu'
59 });
60  
61 // Buttons and menus are collected in a separate config option set called 'navigation'.
62 // This can be extended later to add control buttons like zoom and pan right click menus.
63 defaultOptions.navigation = {
64 buttonOptions: {
65 theme: {},
66 symbolSize: 14,
67 symbolX: 12.5,
68 symbolY: 10.5,
69 align: 'right',
70 buttonSpacing: 3,
71 height: 22,
72 // text: null,
73 verticalAlign: 'top',
74 width: 24
75 }
76 };
77  
78  
79  
80  
81 // Add the export related options
82 defaultOptions.exporting = {
83 //enabled: true,
84 //filename: 'chart',
85 type: 'image/png',
86 url: 'https://export.highcharts.com/',
87 //width: undefined,
88 printMaxWidth: 780,
89 scale: 2,
90 buttons: {
91 contextButton: {
92 className: 'highcharts-contextbutton',
93 menuClassName: 'highcharts-contextmenu',
94 //x: -10,
95 symbol: 'menu',
96 _titleKey: 'contextButtonTitle',
97 menuItems: [{
98 textKey: 'printChart',
99 onclick: function() {
100 this.print();
101 }
102 }, {
103 separator: true
104 }, {
105 textKey: 'downloadPNG',
106 onclick: function() {
107 this.exportChart();
108 }
109 }, {
110 textKey: 'downloadJPEG',
111 onclick: function() {
112 this.exportChart({
113 type: 'image/jpeg'
114 });
115 }
116 }, {
117 textKey: 'downloadPDF',
118 onclick: function() {
119 this.exportChart({
120 type: 'application/pdf'
121 });
122 }
123 }, {
124 textKey: 'downloadSVG',
125 onclick: function() {
126 this.exportChart({
127 type: 'image/svg+xml'
128 });
129 }
130 }]
131 }
132 }
133 };
134  
135 // Add the H.post utility
136 H.post = function(url, data, formAttributes) {
137 // create the form
138 var form = createElement('form', merge({
139 method: 'post',
140 action: url,
141 enctype: 'multipart/form-data'
142 }, formAttributes), {
143 display: 'none'
144 }, doc.body);
145  
146 // add the data
147 objectEach(data, function(val, name) {
148 createElement('input', {
149 type: 'hidden',
150 name: name,
151 value: val
152 }, null, form);
153 });
154  
155 // submit
156 form.submit();
157  
158 // clean up
159 discardElement(form);
160 };
161  
162 extend(Chart.prototype, /** @lends Highcharts.Chart.prototype */ {
163  
164 /**
165 * A collection of fixes on the produced SVG to account for expando properties,
166 * browser bugs, VML problems and other. Returns a cleaned SVG.
167 */
168 sanitizeSVG: function(svg, options) {
169 // Move HTML into a foreignObject
170 if (options && options.exporting && options.exporting.allowHTML) {
171 var html = svg.match(/<\/svg>(.*?$)/);
172 <\/svg> if (html && html[1]) {
173 <\/svg> html = '<foreignObject x="0" y="0" ' +
174 <\/svg> 'width="' + options.chart.width + '" ' +
175 <\/svg> 'height="' + options.chart.height + '">' +
176 <\/svg> '<body xmlns="http://www.w3.org/1999/xhtml">' +
177 <\/svg> html[1] +
178 <\/svg> '</body>' +
179 <\/svg> '</foreignObject>';
180 <\/svg> svg = svg.replace('</svg>', html + '</svg>');
181 <\/svg> }
182 <\/svg> }
183  
184 <\/svg> svg = svg
185 <\/svg> .replace(/zIndex="[^"]+"/g, '')
186 <\/svg> .replace(/isShadow="[^"]+"/g, '')
187 <\/svg> .replace(/symbolName="[^"]+"/g, '')
188 <\/svg> .replace(/jQuery[0-9]+="[^"]+"/g, '')
189 <\/svg> .replace(/url\(("|")(\S+)("|")\)/g, 'url($2)')
190 <\/svg> .replace(/url\([^#]+#/g, 'url(#')
191 <\/svg> .replace(/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
192 <\/svg> .replace(/ (NS[0-9]+\:)?href=/g, ' xlink:href=') // #3567
193 <\/svg> .replace(/\n/, ' ')
194 <\/svg> // Any HTML added to the container after the SVG (#894)
195 <\/svg> .replace(/<\/svg>.*?$/, '</svg>')
196 <\/svg><\/svg> // Batik doesn't support rgba fills and strokes (#3095)
197 <\/svg><\/svg> .replace(/(fill|stroke)="rgba\(([ 0-9]+,[ 0-9]+,[ 0-9]+),([ 0-9\.]+)\)"/g, '$1="rgb($2)" $1-opacity="$3"')
198 <\/svg><\/svg> /* This fails in IE < 8
199 <\/svg><\/svg> .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
200 <\/svg><\/svg> return s2 +'.'+ s3[0];
201 <\/svg><\/svg> })*/
202  
203 <\/svg><\/svg> // Replace HTML entities, issue #347
204 <\/svg><\/svg> .replace(/ /g, '\u00A0') // no-break space
205 <\/svg><\/svg> .replace(/­/g, '\u00AD'); // soft hyphen
206  
207  
208  
209 <\/svg><\/svg> return svg;
210 <\/svg><\/svg> },
211  
212 <\/svg><\/svg> /**
213 <\/svg><\/svg> * Return innerHTML of chart. Used as hook for plugins.
214 <\/svg><\/svg> */
215 <\/svg><\/svg> getChartHTML: function() {
216  
217 <\/svg><\/svg> this.inlineStyles();
218  
219 <\/svg><\/svg> return this.container.innerHTML;
220 <\/svg><\/svg> },
221  
222 <\/svg><\/svg> /**
223 <\/svg><\/svg> * Return an SVG representation of the chart.
224 <\/svg><\/svg> *
225 <\/svg><\/svg> * @param chartOptions {Options}
226 <\/svg><\/svg> * Additional chart options for the generated SVG representation.
227 <\/svg><\/svg> * For collections like `xAxis`, `yAxis` or `series`, the additional
228 <\/svg><\/svg> * options is either merged in to the orininal item of the same
229 <\/svg><\/svg> * `id`, or to the first item if a common id is not found.
230 <\/svg><\/svg> * @return {String}
231 <\/svg><\/svg> * The SVG representation of the rendered chart.
232 <\/svg><\/svg> * @sample highcharts/members/chart-getsvg/
233 <\/svg><\/svg> * View the SVG from a button
234 <\/svg><\/svg> */
235 <\/svg><\/svg> getSVG: function(chartOptions) {
236 <\/svg><\/svg> var chart = this,
237 <\/svg><\/svg> chartCopy,
238 <\/svg><\/svg> sandbox,
239 <\/svg><\/svg> svg,
240 <\/svg><\/svg> seriesOptions,
241 <\/svg><\/svg> sourceWidth,
242 <\/svg><\/svg> sourceHeight,
243 <\/svg><\/svg> cssWidth,
244 <\/svg><\/svg> cssHeight,
245 <\/svg><\/svg> options = merge(chart.options, chartOptions); // copy the options and add extra options
246  
247  
248 <\/svg><\/svg> // IE compatibility hack for generating SVG content that it doesn't really understand
249 <\/svg><\/svg> if (!doc.createElementNS) {
250 <\/svg><\/svg> doc.createElementNS = function(ns, tagName) {
251 <\/svg><\/svg> return doc.createElement(tagName);
252 <\/svg><\/svg> };
253 <\/svg><\/svg> }
254  
255 <\/svg><\/svg> // create a sandbox where a new chart will be generated
256 <\/svg><\/svg> sandbox = createElement('div', null, {
257 <\/svg><\/svg> position: 'absolute',
258 <\/svg><\/svg> top: '-9999em',
259 <\/svg><\/svg> width: chart.chartWidth + 'px',
260 <\/svg><\/svg> height: chart.chartHeight + 'px'
261 <\/svg><\/svg> }, doc.body);
262  
263 <\/svg><\/svg> // get the source size
264 <\/svg><\/svg> cssWidth = chart.renderTo.style.width;
265 <\/svg><\/svg> cssHeight = chart.renderTo.style.height;
266 <\/svg><\/svg> sourceWidth = options.exporting.sourceWidth ||
267 <\/svg><\/svg> options.chart.width ||
268 <\/svg><\/svg> (/px$/.test(cssWidth) && parseInt(cssWidth, 10)) ||
269 <\/svg><\/svg> 600;
270 <\/svg><\/svg> sourceHeight = options.exporting.sourceHeight ||
271 <\/svg><\/svg> options.chart.height ||
272 <\/svg><\/svg> (/px$/.test(cssHeight) && parseInt(cssHeight, 10)) ||
273 <\/svg><\/svg> 400;
274  
275 <\/svg><\/svg> // override some options
276 <\/svg><\/svg> extend(options.chart, {
277 <\/svg><\/svg> animation: false,
278 <\/svg><\/svg> renderTo: sandbox,
279 <\/svg><\/svg> forExport: true,
280 <\/svg><\/svg> renderer: 'SVGRenderer',
281 <\/svg><\/svg> width: sourceWidth,
282 <\/svg><\/svg> height: sourceHeight
283 <\/svg><\/svg> });
284 <\/svg><\/svg> options.exporting.enabled = false; // hide buttons in print
285 <\/svg><\/svg> delete options.data; // #3004
286  
287 <\/svg><\/svg> // prepare for replicating the chart
288 <\/svg><\/svg> options.series = [];
289 <\/svg><\/svg> each(chart.series, function(serie) {
290 <\/svg><\/svg> seriesOptions = merge(serie.userOptions, { // #4912
291 <\/svg><\/svg> animation: false, // turn off animation
292 <\/svg><\/svg> enableMouseTracking: false,
293 <\/svg><\/svg> showCheckbox: false,
294 <\/svg><\/svg> visible: serie.visible
295 <\/svg><\/svg> });
296  
297 <\/svg><\/svg> if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
298 <\/svg><\/svg> options.series.push(seriesOptions);
299 <\/svg><\/svg> }
300 <\/svg><\/svg> });
301  
302 <\/svg><\/svg> // Assign an internal key to ensure a one-to-one mapping (#5924)
303 <\/svg><\/svg> each(chart.axes, function(axis) {
304 <\/svg><\/svg> if (!axis.userOptions.internalKey) { // #6444
305 <\/svg><\/svg> axis.userOptions.internalKey = H.uniqueKey();
306 <\/svg><\/svg> }
307 <\/svg><\/svg> });
308  
309 <\/svg><\/svg> // generate the chart copy
310 <\/svg><\/svg> chartCopy = new H.Chart(options, chart.callback);
311  
312 <\/svg><\/svg> // Axis options and series options (#2022, #3900, #5982)
313 <\/svg><\/svg> if (chartOptions) {
314 <\/svg><\/svg> each(['xAxis', 'yAxis', 'series'], function(coll) {
315 <\/svg><\/svg> var collOptions = {};
316 <\/svg><\/svg> if (chartOptions[coll]) {
317 <\/svg><\/svg> collOptions[coll] = chartOptions[coll];
318 <\/svg><\/svg> chartCopy.update(collOptions);
319 <\/svg><\/svg> }
320 <\/svg><\/svg> });
321 <\/svg><\/svg> }
322  
323 <\/svg><\/svg> // Reflect axis extremes in the export (#5924)
324 <\/svg><\/svg> each(chart.axes, function(axis) {
325 <\/svg><\/svg> var axisCopy = H.find(chartCopy.axes, function(copy) {
326 <\/svg><\/svg> return copy.options.internalKey ===
327 <\/svg><\/svg> axis.userOptions.internalKey;
328 <\/svg><\/svg> }),
329 <\/svg><\/svg> extremes = axis.getExtremes(),
330 <\/svg><\/svg> userMin = extremes.userMin,
331 <\/svg><\/svg> userMax = extremes.userMax;
332  
333 <\/svg><\/svg> if (axisCopy && (userMin !== undefined || userMax !== undefined)) {
334 <\/svg><\/svg> axisCopy.setExtremes(userMin, userMax, true, false);
335 <\/svg><\/svg> }
336 <\/svg><\/svg> });
337  
338 <\/svg><\/svg> // Get the SVG from the container's innerHTML
339 <\/svg><\/svg> svg = chartCopy.getChartHTML();
340  
341 <\/svg><\/svg> svg = chart.sanitizeSVG(svg, options);
342  
343 <\/svg><\/svg> // free up memory
344 <\/svg><\/svg> options = null;
345 <\/svg><\/svg> chartCopy.destroy();
346 <\/svg><\/svg> discardElement(sandbox);
347  
348 <\/svg><\/svg> return svg;
349 <\/svg><\/svg> },
350  
351 <\/svg><\/svg> getSVGForExport: function(options, chartOptions) {
352 <\/svg><\/svg> var chartExportingOptions = this.options.exporting;
353  
354 <\/svg><\/svg> return this.getSVG(merge({
355 <\/svg><\/svg> chart: {
356 <\/svg><\/svg> borderRadius: 0
357 <\/svg><\/svg> }
358 <\/svg><\/svg> },
359 <\/svg><\/svg> chartExportingOptions.chartOptions,
360 <\/svg><\/svg> chartOptions, {
361 <\/svg><\/svg> exporting: {
362 <\/svg><\/svg> sourceWidth: (options && options.sourceWidth) || chartExportingOptions.sourceWidth,
363 <\/svg><\/svg> sourceHeight: (options && options.sourceHeight) || chartExportingOptions.sourceHeight
364 <\/svg><\/svg> }
365 <\/svg><\/svg> }
366 <\/svg><\/svg> ));
367 <\/svg><\/svg> },
368  
369 <\/svg><\/svg> /**
370 <\/svg><\/svg> * Exporting module required. Submit an SVG version of the chart to a server
371 <\/svg><\/svg> * along with some parameters for conversion.
372 <\/svg><\/svg> * @param {Object} exportingOptions
373 <\/svg><\/svg> * Exporting options in addition to those defined in {@link
374 <\/svg><\/svg> * https://api.highcharts.com/highcharts/exporting|exporting}.
375 <\/svg><\/svg> * @param {String} exportingOptions.filename
376 <\/svg><\/svg> * The file name for the export without extension.
377 <\/svg><\/svg> * @param {String} exportingOptions.url
378 <\/svg><\/svg> * The URL for the server module to do the conversion.
379 <\/svg><\/svg> * @param {Number} exportingOptions.width
380 <\/svg><\/svg> * The width of the PNG or JPG image generated on the server.
381 <\/svg><\/svg> * @param {String} exportingOptions.type
382 <\/svg><\/svg> * The MIME type of the converted image.
383 <\/svg><\/svg> * @param {Number} exportingOptions.sourceWidth
384 <\/svg><\/svg> * The pixel width of the source (in-page) chart.
385 <\/svg><\/svg> * @param {Number} exportingOptions.sourceHeight
386 <\/svg><\/svg> * The pixel height of the source (in-page) chart.
387 <\/svg><\/svg> * @param {Options} chartOptions
388 <\/svg><\/svg> * Additional chart options for the exported chart. For example a
389 <\/svg><\/svg> * different background color can be added here, or `dataLabels`
390 <\/svg><\/svg> * for export only.
391 <\/svg><\/svg> *
392 <\/svg><\/svg> * @sample highcharts/members/chart-exportchart/
393 <\/svg><\/svg> * Export with no options
394 <\/svg><\/svg> * @sample highcharts/members/chart-exportchart-filename/
395 <\/svg><\/svg> * PDF type and custom filename
396 <\/svg><\/svg> * @sample highcharts/members/chart-exportchart-custom-background/
397 <\/svg><\/svg> * Different chart background in export
398 <\/svg><\/svg> * @sample stock/members/chart-exportchart/
399 <\/svg><\/svg> * Export with Highstock
400 <\/svg><\/svg> */
401 <\/svg><\/svg> exportChart: function(exportingOptions, chartOptions) {
402  
403 <\/svg><\/svg> var svg = this.getSVGForExport(exportingOptions, chartOptions);
404  
405 <\/svg><\/svg> // merge the options
406 <\/svg><\/svg> exportingOptions = merge(this.options.exporting, exportingOptions);
407  
408 <\/svg><\/svg> // do the post
409 <\/svg><\/svg> H.post(exportingOptions.url, {
410 <\/svg><\/svg> filename: exportingOptions.filename || 'chart',
411 <\/svg><\/svg> type: exportingOptions.type,
412 <\/svg><\/svg> width: exportingOptions.width || 0, // IE8 fails to post undefined correctly, so use 0
413 <\/svg><\/svg> scale: exportingOptions.scale,
414 <\/svg><\/svg> svg: svg
415 <\/svg><\/svg> }, exportingOptions.formAttributes);
416  
417 <\/svg><\/svg> },
418  
419 <\/svg><\/svg> /**
420 <\/svg><\/svg> * Exporting module required. Clears away other elements in the page and
421 <\/svg><\/svg> * prints the chart as it is displayed. By default, when the exporting
422 <\/svg><\/svg> * module is enabled, a context button with a drop down menu in the upper
423 <\/svg><\/svg> * right corner accesses this function.
424 <\/svg><\/svg> *
425 <\/svg><\/svg> * @sample highcharts/members/chart-print/
426 <\/svg><\/svg> * Print from a HTML button
427 <\/svg><\/svg> */
428 <\/svg><\/svg> print: function() {
429  
430 <\/svg><\/svg> var chart = this,
431 <\/svg><\/svg> container = chart.container,
432 <\/svg><\/svg> origDisplay = [],
433 <\/svg><\/svg> origParent = container.parentNode,
434 <\/svg><\/svg> body = doc.body,
435 <\/svg><\/svg> childNodes = body.childNodes,
436 <\/svg><\/svg> printMaxWidth = chart.options.exporting.printMaxWidth,
437 <\/svg><\/svg> resetParams,
438 <\/svg><\/svg> handleMaxWidth;
439  
440 <\/svg><\/svg> if (chart.isPrinting) { // block the button while in printing mode
441 <\/svg><\/svg> return;
442 <\/svg><\/svg> }
443  
444 <\/svg><\/svg> chart.isPrinting = true;
445 <\/svg><\/svg> chart.pointer.reset(null, 0);
446  
447 <\/svg><\/svg> fireEvent(chart, 'beforePrint');
448  
449 <\/svg><\/svg> // Handle printMaxWidth
450 <\/svg><\/svg> handleMaxWidth = printMaxWidth && chart.chartWidth > printMaxWidth;
451 <\/svg><\/svg> if (handleMaxWidth) {
452 <\/svg><\/svg> resetParams = [chart.options.chart.width, undefined, false];
453 <\/svg><\/svg> chart.setSize(printMaxWidth, undefined, false);
454 <\/svg><\/svg> }
455  
456 <\/svg><\/svg> // hide all body content
457 <\/svg><\/svg> each(childNodes, function(node, i) {
458 <\/svg><\/svg> if (node.nodeType === 1) {
459 <\/svg><\/svg> origDisplay[i] = node.style.display;
460 <\/svg><\/svg> node.style.display = 'none';
461 <\/svg><\/svg> }
462 <\/svg><\/svg> });
463  
464 <\/svg><\/svg> // pull out the chart
465 <\/svg><\/svg> body.appendChild(container);
466  
467 <\/svg><\/svg> // print
468 <\/svg><\/svg> win.focus(); // #1510
469 <\/svg><\/svg> win.print();
470  
471 <\/svg><\/svg> // allow the browser to prepare before reverting
472 <\/svg><\/svg> setTimeout(function() {
473  
474 <\/svg><\/svg> // put the chart back in
475 <\/svg><\/svg> origParent.appendChild(container);
476  
477 <\/svg><\/svg> // restore all body content
478 <\/svg><\/svg> each(childNodes, function(node, i) {
479 <\/svg><\/svg> if (node.nodeType === 1) {
480 <\/svg><\/svg> node.style.display = origDisplay[i];
481 <\/svg><\/svg> }
482 <\/svg><\/svg> });
483  
484 <\/svg><\/svg> chart.isPrinting = false;
485  
486 <\/svg><\/svg> // Reset printMaxWidth
487 <\/svg><\/svg> if (handleMaxWidth) {
488 <\/svg><\/svg> chart.setSize.apply(chart, resetParams);
489 <\/svg><\/svg> }
490  
491 <\/svg><\/svg> fireEvent(chart, 'afterPrint');
492  
493 <\/svg><\/svg> }, 1000);
494  
495 <\/svg><\/svg> },
496  
497 <\/svg><\/svg> /**
498 <\/svg><\/svg> * Display a popup menu for choosing the export type
499 <\/svg><\/svg> *
500 <\/svg><\/svg> * @param {String} className An identifier for the menu
501 <\/svg><\/svg> * @param {Array} items A collection with text and onclicks for the items
502 <\/svg><\/svg> * @param {Number} x The x position of the opener button
503 <\/svg><\/svg> * @param {Number} y The y position of the opener button
504 <\/svg><\/svg> * @param {Number} width The width of the opener button
505 <\/svg><\/svg> * @param {Number} height The height of the opener button
506 <\/svg><\/svg> */
507 <\/svg><\/svg> contextMenu: function(className, items, x, y, width, height, button) {
508 <\/svg><\/svg> var chart = this,
509 <\/svg><\/svg> navOptions = chart.options.navigation,
510 <\/svg><\/svg> chartWidth = chart.chartWidth,
511 <\/svg><\/svg> chartHeight = chart.chartHeight,
512 <\/svg><\/svg> cacheName = 'cache-' + className,
513 <\/svg><\/svg> menu = chart[cacheName],
514 <\/svg><\/svg> menuPadding = Math.max(width, height), // for mouse leave detection
515 <\/svg><\/svg> innerMenu,
516 <\/svg><\/svg> hide,
517 <\/svg><\/svg> menuStyle;
518  
519 <\/svg><\/svg> // create the menu only the first time
520 <\/svg><\/svg> if (!menu) {
521  
522 <\/svg><\/svg> // create a HTML element above the SVG
523 <\/svg><\/svg> chart[cacheName] = menu = createElement('div', {
524 <\/svg><\/svg> className: className
525 <\/svg><\/svg> }, {
526 <\/svg><\/svg> position: 'absolute',
527 <\/svg><\/svg> zIndex: 1000,
528 <\/svg><\/svg> padding: menuPadding + 'px'
529 <\/svg><\/svg> }, chart.container);
530  
531 <\/svg><\/svg> innerMenu = createElement('div', {
532 <\/svg><\/svg> className: 'highcharts-menu'
533 <\/svg><\/svg> }, null, menu);
534  
535  
536  
537 <\/svg><\/svg> // hide on mouse out
538 <\/svg><\/svg> hide = function() {
539 <\/svg><\/svg> css(menu, {
540 <\/svg><\/svg> display: 'none'
541 <\/svg><\/svg> });
542 <\/svg><\/svg> if (button) {
543 <\/svg><\/svg> button.setState(0);
544 <\/svg><\/svg> }
545 <\/svg><\/svg> chart.openMenu = false;
546 <\/svg><\/svg> };
547  
548 <\/svg><\/svg> // Hide the menu some time after mouse leave (#1357)
549 <\/svg><\/svg> chart.exportEvents.push(
550 <\/svg><\/svg> addEvent(menu, 'mouseleave', function() {
551 <\/svg><\/svg> menu.hideTimer = setTimeout(hide, 500);
552 <\/svg><\/svg> }),
553 <\/svg><\/svg> addEvent(menu, 'mouseenter', function() {
554 <\/svg><\/svg> clearTimeout(menu.hideTimer);
555 <\/svg><\/svg> }),
556  
557 <\/svg><\/svg> // Hide it on clicking or touching outside the menu (#2258, #2335,
558 <\/svg><\/svg> // #2407)
559 <\/svg><\/svg> addEvent(doc, 'mouseup', function(e) {
560 <\/svg><\/svg> if (!chart.pointer.inClass(e.target, className)) {
561 <\/svg><\/svg> hide();
562 <\/svg><\/svg> }
563 <\/svg><\/svg> })
564 <\/svg><\/svg> );
565  
566 <\/svg><\/svg> // create the items
567 <\/svg><\/svg> each(items, function(item) {
568 <\/svg><\/svg> if (item) {
569 <\/svg><\/svg> var element;
570  
571 <\/svg><\/svg> if (item.separator) {
572 <\/svg><\/svg> element = createElement('hr', null, null, innerMenu);
573  
574 <\/svg><\/svg> } else {
575 <\/svg><\/svg> element = createElement('div', {
576 <\/svg><\/svg> className: 'highcharts-menu-item',
577 <\/svg><\/svg> onclick: function(e) {
578 <\/svg><\/svg> if (e) { // IE7
579 <\/svg><\/svg> e.stopPropagation();
580 <\/svg><\/svg> }
581 <\/svg><\/svg> hide();
582 <\/svg><\/svg> if (item.onclick) {
583 <\/svg><\/svg> item.onclick.apply(chart, arguments);
584 <\/svg><\/svg> }
585 <\/svg><\/svg> },
586 <\/svg><\/svg> innerHTML: item.text || chart.options.lang[item.textKey]
587 <\/svg><\/svg> }, null, innerMenu);
588  
589  
590 <\/svg><\/svg> }
591  
592 <\/svg><\/svg> // Keep references to menu divs to be able to destroy them
593 <\/svg><\/svg> chart.exportDivElements.push(element);
594 <\/svg><\/svg> }
595 <\/svg><\/svg> });
596  
597 <\/svg><\/svg> // Keep references to menu and innerMenu div to be able to destroy them
598 <\/svg><\/svg> chart.exportDivElements.push(innerMenu, menu);
599  
600 <\/svg><\/svg> chart.exportMenuWidth = menu.offsetWidth;
601 <\/svg><\/svg> chart.exportMenuHeight = menu.offsetHeight;
602 <\/svg><\/svg> }
603  
604 <\/svg><\/svg> menuStyle = {
605 <\/svg><\/svg> display: 'block'
606 <\/svg><\/svg> };
607  
608 <\/svg><\/svg> // if outside right, right align it
609 <\/svg><\/svg> if (x + chart.exportMenuWidth > chartWidth) {
610 <\/svg><\/svg> menuStyle.right = (chartWidth - x - width - menuPadding) + 'px';
611 <\/svg><\/svg> } else {
612 <\/svg><\/svg> menuStyle.left = (x - menuPadding) + 'px';
613 <\/svg><\/svg> }
614 <\/svg><\/svg> // if outside bottom, bottom align it
615 <\/svg><\/svg> if (y + height + chart.exportMenuHeight > chartHeight && button.alignOptions.verticalAlign !== 'top') {
616 <\/svg><\/svg> menuStyle.bottom = (chartHeight - y - menuPadding) + 'px';
617 <\/svg><\/svg> } else {
618 <\/svg><\/svg> menuStyle.top = (y + height - menuPadding) + 'px';
619 <\/svg><\/svg> }
620  
621 <\/svg><\/svg> css(menu, menuStyle);
622 <\/svg><\/svg> chart.openMenu = true;
623 <\/svg><\/svg> },
624  
625 <\/svg><\/svg> /**
626 <\/svg><\/svg> * Add the export button to the chart
627 <\/svg><\/svg> */
628 <\/svg><\/svg> addButton: function(options) {
629 <\/svg><\/svg> var chart = this,
630 <\/svg><\/svg> renderer = chart.renderer,
631 <\/svg><\/svg> btnOptions = merge(chart.options.navigation.buttonOptions, options),
632 <\/svg><\/svg> onclick = btnOptions.onclick,
633 <\/svg><\/svg> menuItems = btnOptions.menuItems,
634 <\/svg><\/svg> symbol,
635 <\/svg><\/svg> button,
636 <\/svg><\/svg> symbolSize = btnOptions.symbolSize || 12;
637 <\/svg><\/svg> if (!chart.btnCount) {
638 <\/svg><\/svg> chart.btnCount = 0;
639 <\/svg><\/svg> }
640  
641 <\/svg><\/svg> // Keeps references to the button elements
642 <\/svg><\/svg> if (!chart.exportDivElements) {
643 <\/svg><\/svg> chart.exportDivElements = [];
644 <\/svg><\/svg> chart.exportSVGElements = [];
645 <\/svg><\/svg> }
646  
647 <\/svg><\/svg> if (btnOptions.enabled === false) {
648 <\/svg><\/svg> return;
649 <\/svg><\/svg> }
650  
651  
652 <\/svg><\/svg> var attr = btnOptions.theme,
653 <\/svg><\/svg> states = attr.states,
654 <\/svg><\/svg> hover = states && states.hover,
655 <\/svg><\/svg> select = states && states.select,
656 <\/svg><\/svg> callback;
657  
658 <\/svg><\/svg> delete attr.states;
659  
660 <\/svg><\/svg> if (onclick) {
661 <\/svg><\/svg> callback = function(e) {
662 <\/svg><\/svg> e.stopPropagation();
663 <\/svg><\/svg> onclick.call(chart, e);
664 <\/svg><\/svg> };
665  
666 <\/svg><\/svg> } else if (menuItems) {
667 <\/svg><\/svg> callback = function() {
668 <\/svg><\/svg> chart.contextMenu(
669 <\/svg><\/svg> button.menuClassName,
670 <\/svg><\/svg> menuItems,
671 <\/svg><\/svg> button.translateX,
672 <\/svg><\/svg> button.translateY,
673 <\/svg><\/svg> button.width,
674 <\/svg><\/svg> button.height,
675 <\/svg><\/svg> button
676 <\/svg><\/svg> );
677 <\/svg><\/svg> button.setState(2);
678 <\/svg><\/svg> };
679 <\/svg><\/svg> }
680  
681  
682 <\/svg><\/svg> if (btnOptions.text && btnOptions.symbol) {
683 <\/svg><\/svg> attr.paddingLeft = pick(attr.paddingLeft, 25);
684  
685 <\/svg><\/svg> } else if (!btnOptions.text) {
686 <\/svg><\/svg> extend(attr, {
687 <\/svg><\/svg> width: btnOptions.width,
688 <\/svg><\/svg> height: btnOptions.height,
689 <\/svg><\/svg> padding: 0
690 <\/svg><\/svg> });
691 <\/svg><\/svg> }
692  
693 <\/svg><\/svg> button = renderer.button(btnOptions.text, 0, 0, callback, attr, hover, select)
694 <\/svg><\/svg> .addClass(options.className)
695 <\/svg><\/svg> .attr({
696  
697 <\/svg><\/svg> title: chart.options.lang[btnOptions._titleKey],
698 <\/svg><\/svg> zIndex: 3 // #4955
699 <\/svg><\/svg> });
700 <\/svg><\/svg> button.menuClassName = options.menuClassName || 'highcharts-menu-' + chart.btnCount++;
701  
702 <\/svg><\/svg> if (btnOptions.symbol) {
703 <\/svg><\/svg> symbol = renderer.symbol(
704 <\/svg><\/svg> btnOptions.symbol,
705 <\/svg><\/svg> btnOptions.symbolX - (symbolSize / 2),
706 <\/svg><\/svg> btnOptions.symbolY - (symbolSize / 2),
707 <\/svg><\/svg> symbolSize,
708 <\/svg><\/svg> symbolSize
709 <\/svg><\/svg> )
710 <\/svg><\/svg> .addClass('highcharts-button-symbol')
711 <\/svg><\/svg> .attr({
712 <\/svg><\/svg> zIndex: 1
713 <\/svg><\/svg> }).add(button);
714  
715  
716 <\/svg><\/svg> }
717  
718 <\/svg><\/svg> button.add()
719 <\/svg><\/svg> .align(extend(btnOptions, {
720 <\/svg><\/svg> width: button.width,
721 <\/svg><\/svg> x: pick(btnOptions.x, chart.buttonOffset) // #1654
722 <\/svg><\/svg> }), true, 'spacingBox');
723  
724 <\/svg><\/svg> chart.buttonOffset += (button.width + btnOptions.buttonSpacing) * (btnOptions.align === 'right' ? -1 : 1);
725  
726 <\/svg><\/svg> chart.exportSVGElements.push(button, symbol);
727  
728 <\/svg><\/svg> },
729  
730 <\/svg><\/svg> /**
731 <\/svg><\/svg> * Destroy the buttons.
732 <\/svg><\/svg> */
733 <\/svg><\/svg> destroyExport: function(e) {
734 <\/svg><\/svg> var chart = e ? e.target : this,
735 <\/svg><\/svg> exportSVGElements = chart.exportSVGElements,
736 <\/svg><\/svg> exportDivElements = chart.exportDivElements,
737 <\/svg><\/svg> exportEvents = chart.exportEvents,
738 <\/svg><\/svg> cacheName;
739  
740 <\/svg><\/svg> // Destroy the extra buttons added
741 <\/svg><\/svg> if (exportSVGElements) {
742 <\/svg><\/svg> each(exportSVGElements, function(elem, i) {
743  
744 <\/svg><\/svg> // Destroy and null the svg/vml elements
745 <\/svg><\/svg> if (elem) { // #1822
746 <\/svg><\/svg> elem.onclick = elem.ontouchstart = null;
747 <\/svg><\/svg> cacheName = 'cache-' + elem.menuClassName;
748  
749 <\/svg><\/svg> if (chart[cacheName]) {
750 <\/svg><\/svg> delete chart[cacheName];
751 <\/svg><\/svg> }
752  
753 <\/svg><\/svg> chart.exportSVGElements[i] = elem.destroy();
754 <\/svg><\/svg> }
755 <\/svg><\/svg> });
756 <\/svg><\/svg> exportSVGElements.length = 0;
757 <\/svg><\/svg> }
758  
759 <\/svg><\/svg> // Destroy the divs for the menu
760 <\/svg><\/svg> if (exportDivElements) {
761 <\/svg><\/svg> each(exportDivElements, function(elem, i) {
762  
763 <\/svg><\/svg> // Remove the event handler
764 <\/svg><\/svg> clearTimeout(elem.hideTimer); // #5427
765 <\/svg><\/svg> removeEvent(elem, 'mouseleave');
766  
767 <\/svg><\/svg> // Remove inline events
768 <\/svg><\/svg> chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
769  
770 <\/svg><\/svg> // Destroy the div by moving to garbage bin
771 <\/svg><\/svg> discardElement(elem);
772 <\/svg><\/svg> });
773 <\/svg><\/svg> exportDivElements.length = 0;
774 <\/svg><\/svg> }
775  
776 <\/svg><\/svg> if (exportEvents) {
777 <\/svg><\/svg> each(exportEvents, function(unbind) {
778 <\/svg><\/svg> unbind();
779 <\/svg><\/svg> });
780 <\/svg><\/svg> exportEvents.length = 0;
781 <\/svg><\/svg> }
782 <\/svg><\/svg> }
783 <\/svg><\/svg> });
784  
785  
786 <\/svg><\/svg> // These ones are translated to attributes rather than styles
787 <\/svg><\/svg> SVGRenderer.prototype.inlineToAttributes = [
788 <\/svg><\/svg> 'fill',
789 <\/svg><\/svg> 'stroke',
790 <\/svg><\/svg> 'strokeLinecap',
791 <\/svg><\/svg> 'strokeLinejoin',
792 <\/svg><\/svg> 'strokeWidth',
793 <\/svg><\/svg> 'textAnchor',
794 <\/svg><\/svg> 'x',
795 <\/svg><\/svg> 'y'
796 <\/svg><\/svg> ];
797 <\/svg><\/svg> // These CSS properties are not inlined. Remember camelCase.
798 <\/svg><\/svg> SVGRenderer.prototype.inlineBlacklist = [
799 <\/svg><\/svg> /-/, // In Firefox, both hyphened and camelCased names are listed
800 <\/svg><\/svg> /^(clipPath|cssText|d|height|width)$/, // Full words
801 <\/svg><\/svg> /^font$/, // more specific props are set
802 <\/svg><\/svg> /[lL]ogical(Width|Height)$/,
803 <\/svg><\/svg> /perspective/,
804 <\/svg><\/svg> /TapHighlightColor/,
805 <\/svg><\/svg> /^transition/
806 <\/svg><\/svg> // /^text (border|color|cursor|height|webkitBorder)/
807 <\/svg><\/svg> ];
808 <\/svg><\/svg> SVGRenderer.prototype.unstyledElements = [
809 <\/svg><\/svg> 'clipPath',
810 <\/svg><\/svg> 'defs',
811 <\/svg><\/svg> 'desc'
812 <\/svg><\/svg> ];
813  
814 <\/svg><\/svg> /**
815 <\/svg><\/svg> * Analyze inherited styles from stylesheets and add them inline
816 <\/svg><\/svg> *
817 <\/svg><\/svg> * @todo: What are the border styles for text about? In general, text has a lot of properties.
818 <\/svg><\/svg> * @todo: Make it work with IE9 and IE10.
819 <\/svg><\/svg> */
820 <\/svg><\/svg> Chart.prototype.inlineStyles = function() {
821 <\/svg><\/svg> var renderer = this.renderer,
822 <\/svg><\/svg> inlineToAttributes = renderer.inlineToAttributes,
823 <\/svg><\/svg> blacklist = renderer.inlineBlacklist,
824 <\/svg><\/svg> whitelist = renderer.inlineWhitelist, // For IE
825 <\/svg><\/svg> unstyledElements = renderer.unstyledElements,
826 <\/svg><\/svg> defaultStyles = {},
827 <\/svg><\/svg> dummySVG;
828  
829 <\/svg><\/svg> /**
830 <\/svg><\/svg> * Make hyphenated property names out of camelCase
831 <\/svg><\/svg> */
832 <\/svg><\/svg> function hyphenate(prop) {
833 <\/svg><\/svg> return prop.replace(
834 <\/svg><\/svg> /([A-Z])/g,
835 <\/svg><\/svg> function(a, b) {
836 <\/svg><\/svg> return '-' + b.toLowerCase();
837 <\/svg><\/svg> }
838 <\/svg><\/svg> );
839 <\/svg><\/svg> }
840  
841 <\/svg><\/svg> /**
842 <\/svg><\/svg> * Call this on all elements and recurse to children
843 <\/svg><\/svg> */
844 <\/svg><\/svg> function recurse(node) {
845 <\/svg><\/svg> var styles,
846 <\/svg><\/svg> parentStyles,
847 <\/svg><\/svg> cssText = '',
848 <\/svg><\/svg> dummy,
849 <\/svg><\/svg> styleAttr,
850 <\/svg><\/svg> blacklisted,
851 <\/svg><\/svg> whitelisted,
852 <\/svg><\/svg> i;
853  
854 <\/svg><\/svg> // Check computed styles and whether they are in the white/blacklist for
855 <\/svg><\/svg> // styles or atttributes
856 <\/svg><\/svg> function filterStyles(val, prop) {
857  
858 <\/svg><\/svg> // Check against whitelist & blacklist
859 <\/svg><\/svg> blacklisted = whitelisted = false;
860 <\/svg><\/svg> if (whitelist) {
861 <\/svg><\/svg> // Styled mode in IE has a whitelist instead.
862 <\/svg><\/svg> // Exclude all props not in this list.
863 <\/svg><\/svg> i = whitelist.length;
864 <\/svg><\/svg> while (i-- && !whitelisted) {
865 <\/svg><\/svg> whitelisted = whitelist[i].test(prop);
866 <\/svg><\/svg> }
867 <\/svg><\/svg> blacklisted = !whitelisted;
868 <\/svg><\/svg> }
869  
870 <\/svg><\/svg> // Explicitly remove empty transforms
871 <\/svg><\/svg> if (prop === 'transform' && val === 'none') {
872 <\/svg><\/svg> blacklisted = true;
873 <\/svg><\/svg> }
874  
875 <\/svg><\/svg> i = blacklist.length;
876 <\/svg><\/svg> while (i-- && !blacklisted) {
877 <\/svg><\/svg> blacklisted = blacklist[i].test(prop) || typeof val === 'function';
878 <\/svg><\/svg> }
879  
880 <\/svg><\/svg> if (!blacklisted) {
881 <\/svg><\/svg> // If parent node has the same style, it gets inherited, no need to inline it
882 <\/svg><\/svg> if (parentStyles[prop] !== val && defaultStyles[node.nodeName][prop] !== val) {
883 <\/svg><\/svg> // Attributes
884 <\/svg><\/svg> if (inlineToAttributes.indexOf(prop) !== -1) {
885 <\/svg><\/svg> node.setAttribute(hyphenate(prop), val);
886 <\/svg><\/svg> // Styles
887 <\/svg><\/svg> } else {
888 <\/svg><\/svg> cssText += hyphenate(prop) + ':' + val + ';';
889 <\/svg><\/svg> }
890 <\/svg><\/svg> }
891 <\/svg><\/svg> }
892 <\/svg><\/svg> }
893  
894 <\/svg><\/svg> if (node.nodeType === 1 && unstyledElements.indexOf(node.nodeName) === -1) {
895 <\/svg><\/svg> styles = win.getComputedStyle(node, null);
896 <\/svg><\/svg> parentStyles = node.nodeName === 'svg' ? {} : win.getComputedStyle(node.parentNode, null);
897  
898 <\/svg><\/svg> // Get default styles from the browser so that we don't have to add these
899 <\/svg><\/svg> if (!defaultStyles[node.nodeName]) {
900 <\/svg><\/svg> if (!dummySVG) {
901 <\/svg><\/svg> dummySVG = doc.createElementNS(H.SVG_NS, 'svg');
902 <\/svg><\/svg> dummySVG.setAttribute('version', '1.1');
903 <\/svg><\/svg> doc.body.appendChild(dummySVG);
904 <\/svg><\/svg> }
905 <\/svg><\/svg> dummy = doc.createElementNS(node.namespaceURI, node.nodeName);
906 <\/svg><\/svg> dummySVG.appendChild(dummy);
907 <\/svg><\/svg> defaultStyles[node.nodeName] = merge(win.getComputedStyle(dummy, null)); // Copy, so we can remove the node
908 <\/svg><\/svg> dummySVG.removeChild(dummy);
909 <\/svg><\/svg> }
910  
911 <\/svg><\/svg> // Loop through all styles and add them inline if they are ok
912 <\/svg><\/svg> if (isFirefoxBrowser || isMSBrowser) {
913 <\/svg><\/svg> // Some browsers put lots of styles on the prototype
914 <\/svg><\/svg> for (var p in styles) {
915 <\/svg><\/svg> filterStyles(styles[p], p);
916 <\/svg><\/svg> }
917 <\/svg><\/svg> } else {
918 <\/svg><\/svg> objectEach(styles, filterStyles);
919 <\/svg><\/svg> }
920  
921 <\/svg><\/svg> // Apply styles
922 <\/svg><\/svg> if (cssText) {
923 <\/svg><\/svg> styleAttr = node.getAttribute('style');
924 <\/svg><\/svg> node.setAttribute('style', (styleAttr ? styleAttr + ';' : '') + cssText);
925 <\/svg><\/svg> }
926  
927 <\/svg><\/svg> // Set default stroke width (needed at least for IE)
928 <\/svg><\/svg> if (node.nodeName === 'svg') {
929 <\/svg><\/svg> node.setAttribute('stroke-width', '1px');
930 <\/svg><\/svg> }
931  
932 <\/svg><\/svg> if (node.nodeName === 'text') {
933 <\/svg><\/svg> return;
934 <\/svg><\/svg> }
935  
936 <\/svg><\/svg> // Recurse
937 <\/svg><\/svg> each(node.children || node.childNodes, recurse);
938 <\/svg><\/svg> }
939 <\/svg><\/svg> }
940  
941 <\/svg><\/svg> /**
942 <\/svg><\/svg> * Remove the dummy objects used to get defaults
943 <\/svg><\/svg> */
944 <\/svg><\/svg> function tearDown() {
945 <\/svg><\/svg> dummySVG.parentNode.removeChild(dummySVG);
946 <\/svg><\/svg> }
947  
948 <\/svg><\/svg> recurse(this.container.querySelector('svg'));
949 <\/svg><\/svg> tearDown();
950  
951 <\/svg><\/svg> };
952  
953  
954  
955 <\/svg><\/svg> symbols.menu = function(x, y, width, height) {
956 <\/svg><\/svg> var arr = [
957 <\/svg><\/svg> 'M', x, y + 2.5,
958 <\/svg><\/svg> 'L', x + width, y + 2.5,
959 <\/svg><\/svg> 'M', x, y + height / 2 + 0.5,
960 <\/svg><\/svg> 'L', x + width, y + height / 2 + 0.5,
961 <\/svg><\/svg> 'M', x, y + height - 1.5,
962 <\/svg><\/svg> 'L', x + width, y + height - 1.5
963 <\/svg><\/svg> ];
964 <\/svg><\/svg> return arr;
965 <\/svg><\/svg> };
966  
967 <\/svg><\/svg> // Add the buttons on chart load
968 <\/svg><\/svg> Chart.prototype.renderExporting = function() {
969 <\/svg><\/svg> var chart = this,
970 <\/svg><\/svg> exportingOptions = chart.options.exporting,
971 <\/svg><\/svg> buttons = exportingOptions.buttons,
972 <\/svg><\/svg> isDirty = chart.isDirtyExporting || !chart.exportSVGElements;
973  
974 <\/svg><\/svg> chart.buttonOffset = 0;
975 <\/svg><\/svg> if (chart.isDirtyExporting) {
976 <\/svg><\/svg> chart.destroyExport();
977 <\/svg><\/svg> }
978  
979 <\/svg><\/svg> if (isDirty && exportingOptions.enabled !== false) {
980 <\/svg><\/svg> chart.exportEvents = [];
981  
982 <\/svg><\/svg> objectEach(buttons, function(button) {
983 <\/svg><\/svg> chart.addButton(button);
984 <\/svg><\/svg> });
985  
986 <\/svg><\/svg> chart.isDirtyExporting = false;
987 <\/svg><\/svg> }
988  
989 <\/svg><\/svg> // Destroy the export elements at chart destroy
990 <\/svg><\/svg> addEvent(chart, 'destroy', chart.destroyExport);
991 <\/svg><\/svg> };
992  
993 <\/svg><\/svg> Chart.prototype.callbacks.push(function(chart) {
994  
995 <\/svg><\/svg> function update(prop, options, redraw) {
996 <\/svg><\/svg> chart.isDirtyExporting = true;
997 <\/svg><\/svg> merge(true, chart.options[prop], options);
998 <\/svg><\/svg> if (pick(redraw, true)) {
999 <\/svg><\/svg> chart.redraw();
1000 <\/svg><\/svg> }
1001  
1002 <\/svg><\/svg> }
1003  
1004 <\/svg><\/svg> chart.renderExporting();
1005  
1006 <\/svg><\/svg> addEvent(chart, 'redraw', chart.renderExporting);
1007  
1008 <\/svg><\/svg> // Add update methods to handle chart.update and chart.exporting.update
1009 <\/svg><\/svg> // and chart.navigation.update.
1010 <\/svg><\/svg> each(['exporting', 'navigation'], function(prop) {
1011 <\/svg><\/svg> chart[prop] = {
1012 <\/svg><\/svg> update: function(options, redraw) {
1013 <\/svg><\/svg> update(prop, options, redraw);
1014 <\/svg><\/svg> }
1015 <\/svg><\/svg> };
1016 <\/svg><\/svg> });
1017  
1018 <\/svg><\/svg> // Uncomment this to see a button directly below the chart, for quick
1019 <\/svg><\/svg> // testing of export
1020 <\/svg><\/svg> /*
1021 <\/svg><\/svg> if (!chart.renderer.forExport) {
1022 <\/svg><\/svg> var button;
1023  
1024 <\/svg><\/svg> // View SVG Image
1025 <\/svg><\/svg> button = doc.createElement('button');
1026 <\/svg><\/svg> button.innerHTML = 'View SVG Image';
1027 <\/svg><\/svg> chart.renderTo.parentNode.appendChild(button);
1028 <\/svg><\/svg> button.onclick = function () {
1029 <\/svg><\/svg> var div = doc.createElement('div');
1030 <\/svg><\/svg> div.innerHTML = chart.getSVGForExport();
1031 <\/svg><\/svg> chart.renderTo.parentNode.appendChild(div);
1032 <\/svg><\/svg> };
1033  
1034 <\/svg><\/svg> // View SVG Source
1035 <\/svg><\/svg> button = doc.createElement('button');
1036 <\/svg><\/svg> button.innerHTML = 'View SVG Source';
1037 <\/svg><\/svg> chart.renderTo.parentNode.appendChild(button);
1038 <\/svg><\/svg> button.onclick = function () {
1039 <\/svg><\/svg> var pre = doc.createElement('pre');
1040 <\/svg><\/svg> pre.innerHTML = chart.getSVGForExport()
1041 <\/svg><\/svg> .replace(/</g, '\n&lt;')
1042 <\/svg><\/svg> .replace(/>/g, '&gt;');
1043 <\/svg><\/svg> chart.renderTo.parentNode.appendChild(pre);
1044 <\/svg><\/svg> };
1045 <\/svg><\/svg> }
1046 <\/svg><\/svg> // */
1047 <\/svg><\/svg> });
1048  
1049 <\/svg><\/svg> }(Highcharts));
1050 <\/svg><\/svg>}));