~jstys-z/helioviewer.org/timeline

« back to all changes in this revision

Viewing changes to timeline/js/modules/exporting.src.js

  • Committer: Jeff Stys
  • Date: 2014-04-21 12:46:26 UTC
  • Revision ID: jstys@sesda3.com-20140421124626-2332pb2dyjc33jxi
Proof-of-concept version of Data Coverage Timeline using Highchart/Highstock javascript library.  Changes to getDataCoverage API in order to feed the necessary data to the Timeline

Show diffs side-by-side

added added

removed removed

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