highcharts_rails 0.1.0

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