highcharts-js-rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,734 @@
1
+ /**
2
+ * @license Highcharts JS v2.2.0 (2012-02-16)
3
+ * Exporting module
4
+ *
5
+ * (c) 2010-2011 Torstein Hønsi
6
+ *
7
+ * License: www.highcharts.com/license
8
+ */
9
+
10
+ // JSLint options:
11
+ /*global Highcharts, document, window, Math, setTimeout */
12
+
13
+ (function () { // encapsulate
14
+
15
+ // create shortcuts
16
+ var HC = Highcharts,
17
+ Chart = HC.Chart,
18
+ addEvent = HC.addEvent,
19
+ removeEvent = HC.removeEvent,
20
+ createElement = HC.createElement,
21
+ discardElement = HC.discardElement,
22
+ css = HC.css,
23
+ merge = HC.merge,
24
+ each = HC.each,
25
+ extend = HC.extend,
26
+ math = Math,
27
+ mathMax = math.max,
28
+ doc = document,
29
+ win = window,
30
+ hasTouch = doc.documentElement.ontouchstart !== undefined,
31
+ M = 'M',
32
+ L = 'L',
33
+ DIV = 'div',
34
+ HIDDEN = 'hidden',
35
+ NONE = 'none',
36
+ PREFIX = 'highcharts-',
37
+ ABSOLUTE = 'absolute',
38
+ PX = 'px',
39
+ UNDEFINED,
40
+ defaultOptions = HC.getOptions();
41
+
42
+ // Add language
43
+ extend(defaultOptions.lang, {
44
+ downloadPNG: 'Download PNG image',
45
+ downloadJPEG: 'Download JPEG image',
46
+ downloadPDF: 'Download PDF document',
47
+ downloadSVG: 'Download SVG vector image',
48
+ exportButtonTitle: 'Export to raster or vector image',
49
+ printButtonTitle: 'Print the chart'
50
+ });
51
+
52
+ // Buttons and menus are collected in a separate config option set called 'navigation'.
53
+ // This can be extended later to add control buttons like zoom and pan right click menus.
54
+ defaultOptions.navigation = {
55
+ menuStyle: {
56
+ border: '1px solid #A0A0A0',
57
+ background: '#FFFFFF'
58
+ },
59
+ menuItemStyle: {
60
+ padding: '0 5px',
61
+ background: NONE,
62
+ color: '#303030',
63
+ fontSize: hasTouch ? '14px' : '11px'
64
+ },
65
+ menuItemHoverStyle: {
66
+ background: '#4572A5',
67
+ color: '#FFFFFF'
68
+ },
69
+
70
+ buttonOptions: {
71
+ align: 'right',
72
+ backgroundColor: {
73
+ linearGradient: [0, 0, 0, 20],
74
+ stops: [
75
+ [0.4, '#F7F7F7'],
76
+ [0.6, '#E3E3E3']
77
+ ]
78
+ },
79
+ borderColor: '#B0B0B0',
80
+ borderRadius: 3,
81
+ borderWidth: 1,
82
+ //enabled: true,
83
+ height: 20,
84
+ hoverBorderColor: '#909090',
85
+ hoverSymbolFill: '#81A7CF',
86
+ hoverSymbolStroke: '#4572A5',
87
+ symbolFill: '#E0E0E0',
88
+ //symbolSize: 12,
89
+ symbolStroke: '#A0A0A0',
90
+ //symbolStrokeWidth: 1,
91
+ symbolX: 11.5,
92
+ symbolY: 10.5,
93
+ verticalAlign: 'top',
94
+ width: 24,
95
+ y: 10
96
+ }
97
+ };
98
+
99
+
100
+
101
+ // Add the export related options
102
+ defaultOptions.exporting = {
103
+ //enabled: true,
104
+ //filename: 'chart',
105
+ type: 'image/png',
106
+ url: 'http://export.highcharts.com/',
107
+ width: 800,
108
+ buttons: {
109
+ exportButton: {
110
+ //enabled: true,
111
+ symbol: 'exportIcon',
112
+ x: -10,
113
+ symbolFill: '#A8BF77',
114
+ hoverSymbolFill: '#768F3E',
115
+ _id: 'exportButton',
116
+ _titleKey: 'exportButtonTitle',
117
+ menuItems: [{
118
+ textKey: 'downloadPNG',
119
+ onclick: function () {
120
+ this.exportChart();
121
+ }
122
+ }, {
123
+ textKey: 'downloadJPEG',
124
+ onclick: function () {
125
+ this.exportChart({
126
+ type: 'image/jpeg'
127
+ });
128
+ }
129
+ }, {
130
+ textKey: 'downloadPDF',
131
+ onclick: function () {
132
+ this.exportChart({
133
+ type: 'application/pdf'
134
+ });
135
+ }
136
+ }, {
137
+ textKey: 'downloadSVG',
138
+ onclick: function () {
139
+ this.exportChart({
140
+ type: 'image/svg+xml'
141
+ });
142
+ }
143
+ }
144
+ // Enable this block to add "View SVG" to the dropdown menu
145
+ /*
146
+ ,{
147
+
148
+ text: 'View SVG',
149
+ onclick: function () {
150
+ var svg = this.getSVG()
151
+ .replace(/</g, '\n&lt;')
152
+ .replace(/>/g, '&gt;');
153
+
154
+ doc.body.innerHTML = '<pre>' + svg + '</pre>';
155
+ }
156
+ } // */
157
+ ]
158
+
159
+ },
160
+ printButton: {
161
+ //enabled: true,
162
+ symbol: 'printIcon',
163
+ x: -36,
164
+ symbolFill: '#B5C9DF',
165
+ hoverSymbolFill: '#779ABF',
166
+ _id: 'printButton',
167
+ _titleKey: 'printButtonTitle',
168
+ onclick: function () {
169
+ this.print();
170
+ }
171
+ }
172
+ }
173
+ };
174
+
175
+
176
+
177
+ extend(Chart.prototype, {
178
+ /**
179
+ * Return an SVG representation of the chart
180
+ *
181
+ * @param additionalOptions {Object} Additional chart options for the generated SVG representation
182
+ */
183
+ getSVG: function (additionalOptions) {
184
+ var chart = this,
185
+ chartCopy,
186
+ sandbox,
187
+ svg,
188
+ seriesOptions,
189
+ options = merge(chart.options, additionalOptions); // copy the options and add extra options
190
+
191
+ // IE compatibility hack for generating SVG content that it doesn't really understand
192
+ if (!doc.createElementNS) {
193
+ /*jslint unparam: true*//* allow unused parameter ns in function below */
194
+ doc.createElementNS = function (ns, tagName) {
195
+ var elem = doc.createElement(tagName);
196
+ elem.getBBox = function () {
197
+ return HC.Renderer.prototype.Element.prototype.getBBox.apply({ element: elem });
198
+ };
199
+ return elem;
200
+ };
201
+ /*jslint unparam: false*/
202
+ }
203
+
204
+ // create a sandbox where a new chart will be generated
205
+ sandbox = createElement(DIV, null, {
206
+ position: ABSOLUTE,
207
+ top: '-9999em',
208
+ width: chart.chartWidth + PX,
209
+ height: chart.chartHeight + PX
210
+ }, doc.body);
211
+
212
+ // override some options
213
+ extend(options.chart, {
214
+ renderTo: sandbox,
215
+ forExport: true
216
+ });
217
+ options.exporting.enabled = false; // hide buttons in print
218
+ options.chart.plotBackgroundImage = null; // the converter doesn't handle images
219
+
220
+ // prepare for replicating the chart
221
+ options.series = [];
222
+ each(chart.series, function (serie) {
223
+ seriesOptions = merge(serie.options, {
224
+ animation: false, // turn off animation
225
+ showCheckbox: false,
226
+ visible: serie.visible
227
+ });
228
+
229
+ if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
230
+
231
+ // remove image markers
232
+ if (seriesOptions && seriesOptions.marker && /^url\(/.test(seriesOptions.marker.symbol)) {
233
+ seriesOptions.marker.symbol = 'circle';
234
+ }
235
+
236
+ options.series.push(seriesOptions);
237
+ }
238
+ });
239
+
240
+ // generate the chart copy
241
+ chartCopy = new Highcharts.Chart(options);
242
+
243
+ // reflect axis extremes in the export
244
+ each(['xAxis', 'yAxis'], function (axisType) {
245
+ each(chart[axisType], function (axis, i) {
246
+ var axisCopy = chartCopy[axisType][i],
247
+ extremes = axis.getExtremes(),
248
+ userMin = extremes.userMin,
249
+ userMax = extremes.userMax;
250
+
251
+ if (userMin !== UNDEFINED || userMax !== UNDEFINED) {
252
+ axisCopy.setExtremes(userMin, userMax, true, false);
253
+ }
254
+ });
255
+ });
256
+
257
+ // get the SVG from the container's innerHTML
258
+ svg = chartCopy.container.innerHTML;
259
+
260
+ // free up memory
261
+ options = null;
262
+ chartCopy.destroy();
263
+ discardElement(sandbox);
264
+
265
+ // sanitize
266
+ svg = svg
267
+ .replace(/zIndex="[^"]+"/g, '')
268
+ .replace(/isShadow="[^"]+"/g, '')
269
+ .replace(/symbolName="[^"]+"/g, '')
270
+ .replace(/jQuery[0-9]+="[^"]+"/g, '')
271
+ .replace(/isTracker="[^"]+"/g, '')
272
+ .replace(/url\([^#]+#/g, 'url(#')
273
+ /*.replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
274
+ .replace(/ href=/, ' xlink:href=')
275
+ .replace(/preserveAspectRatio="none">/g, 'preserveAspectRatio="none"/>')*/
276
+ /* This fails in IE < 8
277
+ .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
278
+ return s2 +'.'+ s3[0];
279
+ })*/
280
+
281
+ // Replace HTML entities, issue #347
282
+ .replace(/&nbsp;/g, '\u00A0') // no-break space
283
+ .replace(/&shy;/g, '\u00AD') // soft hyphen
284
+
285
+ // IE specific
286
+ .replace(/id=([^" >]+)/g, 'id="$1"')
287
+ .replace(/class=([^" ]+)/g, 'class="$1"')
288
+ .replace(/ transform /g, ' ')
289
+ .replace(/:(path|rect)/g, '$1')
290
+ .replace(/style="([^"]+)"/g, function (s) {
291
+ return s.toLowerCase();
292
+ });
293
+
294
+ // IE9 beta bugs with innerHTML. Test again with final IE9.
295
+ svg = svg.replace(/(url\(#highcharts-[0-9]+)&quot;/g, '$1')
296
+ .replace(/&quot;/g, "'");
297
+ if (svg.match(/ xmlns="/g).length === 2) {
298
+ svg = svg.replace(/xmlns="[^"]+"/, '');
299
+ }
300
+
301
+ return svg;
302
+ },
303
+
304
+ /**
305
+ * Submit the SVG representation of the chart to the server
306
+ * @param {Object} options Exporting options. Possible members are url, type and width.
307
+ * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
308
+ */
309
+ exportChart: function (options, chartOptions) {
310
+ var form,
311
+ chart = this,
312
+ svg = chart.getSVG(merge(chart.options.exporting.chartOptions, chartOptions)); // docs
313
+
314
+ // merge the options
315
+ options = merge(chart.options.exporting, options);
316
+
317
+ // create the form
318
+ form = createElement('form', {
319
+ method: 'post',
320
+ action: options.url
321
+ }, {
322
+ display: NONE
323
+ }, doc.body);
324
+
325
+ // add the values
326
+ each(['filename', 'type', 'width', 'svg'], function (name) {
327
+ createElement('input', {
328
+ type: HIDDEN,
329
+ name: name,
330
+ value: {
331
+ filename: options.filename || 'chart',
332
+ type: options.type,
333
+ width: options.width,
334
+ svg: svg
335
+ }[name]
336
+ }, null, form);
337
+ });
338
+
339
+ // submit
340
+ form.submit();
341
+
342
+ // clean up
343
+ discardElement(form);
344
+ },
345
+
346
+ /**
347
+ * Print the chart
348
+ */
349
+ print: function () {
350
+
351
+ var chart = this,
352
+ container = chart.container,
353
+ origDisplay = [],
354
+ origParent = container.parentNode,
355
+ body = doc.body,
356
+ childNodes = body.childNodes;
357
+
358
+ if (chart.isPrinting) { // block the button while in printing mode
359
+ return;
360
+ }
361
+
362
+ chart.isPrinting = true;
363
+
364
+ // hide all body content
365
+ each(childNodes, function (node, i) {
366
+ if (node.nodeType === 1) {
367
+ origDisplay[i] = node.style.display;
368
+ node.style.display = NONE;
369
+ }
370
+ });
371
+
372
+ // pull out the chart
373
+ body.appendChild(container);
374
+
375
+ // print
376
+ win.print();
377
+
378
+ // allow the browser to prepare before reverting
379
+ setTimeout(function () {
380
+
381
+ // put the chart back in
382
+ origParent.appendChild(container);
383
+
384
+ // restore all body content
385
+ each(childNodes, function (node, i) {
386
+ if (node.nodeType === 1) {
387
+ node.style.display = origDisplay[i];
388
+ }
389
+ });
390
+
391
+ chart.isPrinting = false;
392
+
393
+ }, 1000);
394
+
395
+ },
396
+
397
+ /**
398
+ * Display a popup menu for choosing the export type
399
+ *
400
+ * @param {String} name An identifier for the menu
401
+ * @param {Array} items A collection with text and onclicks for the items
402
+ * @param {Number} x The x position of the opener button
403
+ * @param {Number} y The y position of the opener button
404
+ * @param {Number} width The width of the opener button
405
+ * @param {Number} height The height of the opener button
406
+ */
407
+ contextMenu: function (name, items, x, y, width, height) {
408
+ var chart = this,
409
+ navOptions = chart.options.navigation,
410
+ menuItemStyle = navOptions.menuItemStyle,
411
+ chartWidth = chart.chartWidth,
412
+ chartHeight = chart.chartHeight,
413
+ cacheName = 'cache-' + name,
414
+ menu = chart[cacheName],
415
+ menuPadding = mathMax(width, height), // for mouse leave detection
416
+ boxShadow = '3px 3px 10px #888',
417
+ innerMenu,
418
+ hide,
419
+ menuStyle;
420
+
421
+ // create the menu only the first time
422
+ if (!menu) {
423
+
424
+ // create a HTML element above the SVG
425
+ chart[cacheName] = menu = createElement(DIV, {
426
+ className: PREFIX + name
427
+ }, {
428
+ position: ABSOLUTE,
429
+ zIndex: 1000,
430
+ padding: menuPadding + PX
431
+ }, chart.container);
432
+
433
+ innerMenu = createElement(DIV, null,
434
+ extend({
435
+ MozBoxShadow: boxShadow,
436
+ WebkitBoxShadow: boxShadow,
437
+ boxShadow: boxShadow
438
+ }, navOptions.menuStyle), menu);
439
+
440
+ // hide on mouse out
441
+ hide = function () {
442
+ css(menu, { display: NONE });
443
+ };
444
+
445
+ addEvent(menu, 'mouseleave', hide);
446
+
447
+
448
+ // create the items
449
+ each(items, function (item) {
450
+ if (item) {
451
+ var div = createElement(DIV, {
452
+ onmouseover: function () {
453
+ css(this, navOptions.menuItemHoverStyle);
454
+ },
455
+ onmouseout: function () {
456
+ css(this, menuItemStyle);
457
+ },
458
+ innerHTML: item.text || chart.options.lang[item.textKey]
459
+ }, extend({
460
+ cursor: 'pointer'
461
+ }, menuItemStyle), innerMenu);
462
+
463
+ div[hasTouch ? 'ontouchstart' : 'onclick'] = function () {
464
+ hide();
465
+ item.onclick.apply(chart, arguments);
466
+ };
467
+
468
+ // Keep references to menu divs to be able to destroy them
469
+ chart.exportDivElements.push(div);
470
+ }
471
+ });
472
+
473
+ // Keep references to menu and innerMenu div to be able to destroy them
474
+ chart.exportDivElements.push(innerMenu, menu);
475
+
476
+ chart.exportMenuWidth = menu.offsetWidth;
477
+ chart.exportMenuHeight = menu.offsetHeight;
478
+ }
479
+
480
+ menuStyle = { display: 'block' };
481
+
482
+ // if outside right, right align it
483
+ if (x + chart.exportMenuWidth > chartWidth) {
484
+ menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
485
+ } else {
486
+ menuStyle.left = (x - menuPadding) + PX;
487
+ }
488
+ // if outside bottom, bottom align it
489
+ if (y + height + chart.exportMenuHeight > chartHeight) {
490
+ menuStyle.bottom = (chartHeight - y - menuPadding) + PX;
491
+ } else {
492
+ menuStyle.top = (y + height - menuPadding) + PX;
493
+ }
494
+
495
+ css(menu, menuStyle);
496
+ },
497
+
498
+ /**
499
+ * Add the export button to the chart
500
+ */
501
+ addButton: function (options) {
502
+ var chart = this,
503
+ renderer = chart.renderer,
504
+ btnOptions = merge(chart.options.navigation.buttonOptions, options),
505
+ onclick = btnOptions.onclick,
506
+ menuItems = btnOptions.menuItems,
507
+ buttonWidth = btnOptions.width,
508
+ buttonHeight = btnOptions.height,
509
+ box,
510
+ symbol,
511
+ button,
512
+ borderWidth = btnOptions.borderWidth,
513
+ boxAttr = {
514
+ stroke: btnOptions.borderColor
515
+
516
+ },
517
+ symbolAttr = {
518
+ stroke: btnOptions.symbolStroke,
519
+ fill: btnOptions.symbolFill
520
+ },
521
+ symbolSize = btnOptions.symbolSize || 12;
522
+
523
+ // Keeps references to the button elements
524
+ if (!chart.exportDivElements) {
525
+ chart.exportDivElements = [];
526
+ chart.exportSVGElements = [];
527
+ }
528
+
529
+ if (btnOptions.enabled === false) {
530
+ return;
531
+ }
532
+
533
+ // element to capture the click
534
+ function revert() {
535
+ symbol.attr(symbolAttr);
536
+ box.attr(boxAttr);
537
+ }
538
+
539
+ // the box border
540
+ box = renderer.rect(
541
+ 0,
542
+ 0,
543
+ buttonWidth,
544
+ buttonHeight,
545
+ btnOptions.borderRadius,
546
+ borderWidth
547
+ )
548
+ //.translate(buttonLeft, buttonTop) // to allow gradients
549
+ .align(btnOptions, true)
550
+ .attr(extend({
551
+ fill: btnOptions.backgroundColor,
552
+ 'stroke-width': borderWidth,
553
+ zIndex: 19
554
+ }, boxAttr)).add();
555
+
556
+ // the invisible element to track the clicks
557
+ button = renderer.rect(
558
+ 0,
559
+ 0,
560
+ buttonWidth,
561
+ buttonHeight,
562
+ 0
563
+ )
564
+ .align(btnOptions)
565
+ .attr({
566
+ id: btnOptions._id,
567
+ fill: 'rgba(255, 255, 255, 0.001)',
568
+ title: chart.options.lang[btnOptions._titleKey],
569
+ zIndex: 21
570
+ }).css({
571
+ cursor: 'pointer'
572
+ })
573
+ .on('mouseover', function () {
574
+ symbol.attr({
575
+ stroke: btnOptions.hoverSymbolStroke,
576
+ fill: btnOptions.hoverSymbolFill
577
+ });
578
+ box.attr({
579
+ stroke: btnOptions.hoverBorderColor
580
+ });
581
+ })
582
+ .on('mouseout', revert)
583
+ .on('click', revert)
584
+ .add();
585
+
586
+ // add the click event
587
+ if (menuItems) {
588
+ onclick = function () {
589
+ revert();
590
+ var bBox = button.getBBox();
591
+ chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight);
592
+ };
593
+ }
594
+ /*addEvent(button.element, 'click', function() {
595
+ onclick.apply(chart, arguments);
596
+ });*/
597
+ button.on('click', function () {
598
+ onclick.apply(chart, arguments);
599
+ });
600
+
601
+ // the icon
602
+ symbol = renderer.symbol(
603
+ btnOptions.symbol,
604
+ btnOptions.symbolX - (symbolSize / 2),
605
+ btnOptions.symbolY - (symbolSize / 2),
606
+ symbolSize,
607
+ symbolSize
608
+ )
609
+ .align(btnOptions, true)
610
+ .attr(extend(symbolAttr, {
611
+ 'stroke-width': btnOptions.symbolStrokeWidth || 1,
612
+ zIndex: 20
613
+ })).add();
614
+
615
+ // Keep references to the renderer element so to be able to destroy them later.
616
+ chart.exportSVGElements.push(box, button, symbol);
617
+ },
618
+
619
+ /**
620
+ * Destroy the buttons.
621
+ */
622
+ destroyExport: function () {
623
+ var i,
624
+ chart = this,
625
+ elem;
626
+
627
+ // Destroy the extra buttons added
628
+ for (i = 0; i < chart.exportSVGElements.length; i++) {
629
+ elem = chart.exportSVGElements[i];
630
+ // Destroy and null the svg/vml elements
631
+ elem.onclick = elem.ontouchstart = null;
632
+ chart.exportSVGElements[i] = elem.destroy();
633
+ }
634
+
635
+ // Destroy the divs for the menu
636
+ for (i = 0; i < chart.exportDivElements.length; i++) {
637
+ elem = chart.exportDivElements[i];
638
+
639
+ // Remove the event handler
640
+ removeEvent(elem, 'mouseleave');
641
+
642
+ // Remove inline events
643
+ chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
644
+
645
+ // Destroy the div by moving to garbage bin
646
+ discardElement(elem);
647
+ }
648
+ }
649
+ });
650
+
651
+ /**
652
+ * Crisp for 1px stroke width, which is default. In the future, consider a smarter,
653
+ * global function.
654
+ */
655
+ function crisp(arr) {
656
+ var i = arr.length;
657
+ while (i--) {
658
+ if (typeof arr[i] === 'number') {
659
+ arr[i] = Math.round(arr[i]) - 0.5;
660
+ }
661
+ }
662
+ return arr;
663
+ }
664
+
665
+ // Create the export icon
666
+ HC.Renderer.prototype.symbols.exportIcon = function (x, y, width, height) {
667
+ return crisp([
668
+ M, // the disk
669
+ x, y + width,
670
+ L,
671
+ x + width, y + height,
672
+ x + width, y + height * 0.8,
673
+ x, y + height * 0.8,
674
+ 'Z',
675
+ M, // the arrow
676
+ x + width * 0.5, y + height * 0.8,
677
+ L,
678
+ x + width * 0.8, y + height * 0.4,
679
+ x + width * 0.4, y + height * 0.4,
680
+ x + width * 0.4, y,
681
+ x + width * 0.6, y,
682
+ x + width * 0.6, y + height * 0.4,
683
+ x + width * 0.2, y + height * 0.4,
684
+ 'Z'
685
+ ]);
686
+ };
687
+ // Create the print icon
688
+ HC.Renderer.prototype.symbols.printIcon = function (x, y, width, height) {
689
+ return crisp([
690
+ M, // the printer
691
+ x, y + height * 0.7,
692
+ L,
693
+ x + width, y + height * 0.7,
694
+ x + width, y + height * 0.4,
695
+ x, y + height * 0.4,
696
+ 'Z',
697
+ M, // the upper sheet
698
+ x + width * 0.2, y + height * 0.4,
699
+ L,
700
+ x + width * 0.2, y,
701
+ x + width * 0.8, y,
702
+ x + width * 0.8, y + height * 0.4,
703
+ 'Z',
704
+ M, // the lower sheet
705
+ x + width * 0.2, y + height * 0.7,
706
+ L,
707
+ x, y + height,
708
+ x + width, y + height,
709
+ x + width * 0.8, y + height * 0.7,
710
+ 'Z'
711
+ ]);
712
+ };
713
+
714
+
715
+ // Add the buttons on chart load
716
+ Chart.prototype.callbacks.push(function (chart) {
717
+ var n,
718
+ exportingOptions = chart.options.exporting,
719
+ buttons = exportingOptions.buttons;
720
+
721
+ if (exportingOptions.enabled !== false) {
722
+
723
+ for (n in buttons) {
724
+ chart.addButton(buttons[n]);
725
+ }
726
+
727
+ // Destroy the export elements at chart destroy
728
+ addEvent(chart, 'destroy', chart.destroyExport);
729
+ }
730
+
731
+ });
732
+
733
+
734
+ }());