highcharts_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,882 @@
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
+ // Presentational attributes
77
+ merge(true, defaultOptions.navigation, {
78
+ menuStyle: {
79
+ border: '1px solid #999999',
80
+ background: '#ffffff',
81
+ padding: '5px 0'
82
+ },
83
+ menuItemStyle: {
84
+ padding: '0.5em 1em',
85
+ background: 'none',
86
+ color: '#333333',
87
+ fontSize: isTouchDevice ? '14px' : '11px',
88
+ transition: 'background 250ms, color 250ms'
89
+ },
90
+ menuItemHoverStyle: {
91
+ background: '#335cad',
92
+ color: '#ffffff'
93
+ },
94
+ buttonOptions: {
95
+ symbolFill: '#666666',
96
+ symbolStroke: '#666666',
97
+ symbolStrokeWidth: 3,
98
+ theme: {
99
+ fill: '#ffffff', // capture hover
100
+ stroke: 'none',
101
+ padding: 5
102
+ }
103
+ }
104
+ });
105
+
106
+
107
+
108
+ // Add the export related options
109
+ defaultOptions.exporting = {
110
+ //enabled: true,
111
+ //filename: 'chart',
112
+ type: 'image/png',
113
+ url: 'https://export.highcharts.com/',
114
+ //width: undefined,
115
+ printMaxWidth: 780,
116
+ scale: 2,
117
+ buttons: {
118
+ contextButton: {
119
+ className: 'highcharts-contextbutton',
120
+ menuClassName: 'highcharts-contextmenu',
121
+ //x: -10,
122
+ symbol: 'menu',
123
+ _titleKey: 'contextButtonTitle',
124
+ menuItems: [{
125
+ textKey: 'printChart',
126
+ onclick: function() {
127
+ this.print();
128
+ }
129
+ }, {
130
+ separator: true
131
+ }, {
132
+ textKey: 'downloadPNG',
133
+ onclick: function() {
134
+ this.exportChart();
135
+ }
136
+ }, {
137
+ textKey: 'downloadJPEG',
138
+ onclick: function() {
139
+ this.exportChart({
140
+ type: 'image/jpeg'
141
+ });
142
+ }
143
+ }, {
144
+ textKey: 'downloadPDF',
145
+ onclick: function() {
146
+ this.exportChart({
147
+ type: 'application/pdf'
148
+ });
149
+ }
150
+ }, {
151
+ textKey: 'downloadSVG',
152
+ onclick: function() {
153
+ this.exportChart({
154
+ type: 'image/svg+xml'
155
+ });
156
+ }
157
+ }
158
+ // Enable this block to add "View SVG" to the dropdown menu
159
+ /*
160
+ ,{
161
+
162
+ text: 'View SVG',
163
+ onclick: function () {
164
+ var svg = this.getSVG()
165
+ .replace(/</g, '\n&lt;')
166
+ .replace(/>/g, '&gt;');
167
+
168
+ doc.body.innerHTML = '<pre>' + svg + '</pre>';
169
+ }
170
+ } // */
171
+ ]
172
+ }
173
+ }
174
+ };
175
+
176
+ // Add the H.post utility
177
+ H.post = function(url, data, formAttributes) {
178
+ var name,
179
+ form;
180
+
181
+ // create the form
182
+ form = createElement('form', merge({
183
+ method: 'post',
184
+ action: url,
185
+ enctype: 'multipart/form-data'
186
+ }, formAttributes), {
187
+ display: 'none'
188
+ }, doc.body);
189
+
190
+ // add the data
191
+ for (name in data) {
192
+ createElement('input', {
193
+ type: 'hidden',
194
+ name: name,
195
+ value: data[name]
196
+ }, null, form);
197
+ }
198
+
199
+ // submit
200
+ form.submit();
201
+
202
+ // clean up
203
+ discardElement(form);
204
+ };
205
+
206
+ extend(Chart.prototype, {
207
+
208
+ /**
209
+ * A collection of fixes on the produced SVG to account for expando properties,
210
+ * browser bugs, VML problems and other. Returns a cleaned SVG.
211
+ */
212
+ sanitizeSVG: function(svg, options) {
213
+ // Move HTML into a foreignObject
214
+ if (options && options.exporting && options.exporting.allowHTML) {
215
+ var html = svg.match(/<\/svg>(.*?$)/);
216
+ if (html) {
217
+ html = '<foreignObject x="0" y="0" ' +
218
+ 'width="' + options.chart.width + '" ' +
219
+ 'height="' + options.chart.height + '">' +
220
+ '<body xmlns="http://www.w3.org/1999/xhtml">' +
221
+ html[1] +
222
+ '</body>' +
223
+ '</foreignObject>';
224
+ svg = svg.replace('</svg>', html + '</svg>');
225
+ }
226
+ }
227
+
228
+ svg = svg
229
+ .replace(/zIndex="[^"]+"/g, '')
230
+ .replace(/isShadow="[^"]+"/g, '')
231
+ .replace(/symbolName="[^"]+"/g, '')
232
+ .replace(/jQuery[0-9]+="[^"]+"/g, '')
233
+ .replace(/url\(("|&quot;)(\S+)("|&quot;)\)/g, 'url($2)')
234
+ .replace(/url\([^#]+#/g, 'url(#')
235
+ .replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
236
+ .replace(/ (NS[0-9]+\:)?href=/g, ' xlink:href=') // #3567
237
+ .replace(/\n/, ' ')
238
+ // Any HTML added to the container after the SVG (#894)
239
+ .replace(/<\/svg>.*?$/, '</svg>')
240
+ // Batik doesn't support rgba fills and strokes (#3095)
241
+ .replace(/(fill|stroke)="rgba\(([ 0-9]+,[ 0-9]+,[ 0-9]+),([ 0-9\.]+)\)"/g, '$1="rgb($2)" $1-opacity="$3"')
242
+ /* This fails in IE < 8
243
+ .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
244
+ return s2 +'.'+ s3[0];
245
+ })*/
246
+
247
+ // Replace HTML entities, issue #347
248
+ .replace(/&nbsp;/g, '\u00A0') // no-break space
249
+ .replace(/&shy;/g, '\u00AD'); // soft hyphen
250
+
251
+
252
+ // IE specific
253
+ svg = svg
254
+ .replace(/<IMG /g, '<image ')
255
+ .replace(/<(\/?)TITLE>/g, '<$1title>')
256
+ .replace(/height=([^" ]+)/g, 'height="$1"')
257
+ .replace(/width=([^" ]+)/g, 'width="$1"')
258
+ .replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
259
+ .replace(/ id=([^" >]+)/g, ' id="$1"') // #4003
260
+ .replace(/class=([^" >]+)/g, 'class="$1"')
261
+ .replace(/ transform /g, ' ')
262
+ .replace(/:(path|rect)/g, '$1')
263
+ .replace(/style="([^"]+)"/g, function(s) {
264
+ return s.toLowerCase();
265
+ });
266
+
267
+
268
+ return svg;
269
+ },
270
+
271
+ /**
272
+ * Return innerHTML of chart. Used as hook for plugins.
273
+ */
274
+ getChartHTML: function() {
275
+
276
+ return this.container.innerHTML;
277
+ },
278
+
279
+ /**
280
+ * Return an SVG representation of the chart.
281
+ *
282
+ * @param additionalOptions {Object} Additional chart options for the
283
+ * generated SVG representation. For collections like `xAxis`, `yAxis` or
284
+ * `series`, the additional options is either merged in to the orininal
285
+ * item of the same `id`, or to the first item if a commin id is not
286
+ * found.
287
+ */
288
+ getSVG: function(additionalOptions) {
289
+ var chart = this,
290
+ chartCopy,
291
+ sandbox,
292
+ svg,
293
+ seriesOptions,
294
+ sourceWidth,
295
+ sourceHeight,
296
+ cssWidth,
297
+ cssHeight,
298
+ options = merge(chart.options, additionalOptions); // copy the options and add extra options
299
+
300
+
301
+ // IE compatibility hack for generating SVG content that it doesn't really understand
302
+ if (!doc.createElementNS) {
303
+ doc.createElementNS = function(ns, tagName) {
304
+ return doc.createElement(tagName);
305
+ };
306
+ }
307
+
308
+ // create a sandbox where a new chart will be generated
309
+ sandbox = createElement('div', null, {
310
+ position: 'absolute',
311
+ top: '-9999em',
312
+ width: chart.chartWidth + 'px',
313
+ height: chart.chartHeight + 'px'
314
+ }, doc.body);
315
+
316
+ // get the source size
317
+ cssWidth = chart.renderTo.style.width;
318
+ cssHeight = chart.renderTo.style.height;
319
+ sourceWidth = options.exporting.sourceWidth ||
320
+ options.chart.width ||
321
+ (/px$/.test(cssWidth) && parseInt(cssWidth, 10)) ||
322
+ 600;
323
+ sourceHeight = options.exporting.sourceHeight ||
324
+ options.chart.height ||
325
+ (/px$/.test(cssHeight) && parseInt(cssHeight, 10)) ||
326
+ 400;
327
+
328
+ // override some options
329
+ extend(options.chart, {
330
+ animation: false,
331
+ renderTo: sandbox,
332
+ forExport: true,
333
+ renderer: 'SVGRenderer',
334
+ width: sourceWidth,
335
+ height: sourceHeight
336
+ });
337
+ options.exporting.enabled = false; // hide buttons in print
338
+ delete options.data; // #3004
339
+
340
+ // prepare for replicating the chart
341
+ options.series = [];
342
+ each(chart.series, function(serie) {
343
+ seriesOptions = merge(serie.userOptions, { // #4912
344
+ animation: false, // turn off animation
345
+ enableMouseTracking: false,
346
+ showCheckbox: false,
347
+ visible: serie.visible
348
+ });
349
+
350
+ if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
351
+ options.series.push(seriesOptions);
352
+ }
353
+ });
354
+
355
+ // Assign an internal key to ensure a one-to-one mapping (#5924)
356
+ each(chart.axes, function(axis) {
357
+ axis.userOptions.internalKey = H.uniqueKey();
358
+ });
359
+
360
+ // generate the chart copy
361
+ chartCopy = new H.Chart(options, chart.callback);
362
+
363
+ // Axis options and series options (#2022, #3900, #5982)
364
+ if (additionalOptions) {
365
+ each(['xAxis', 'yAxis', 'series'], function(coll) {
366
+ var collOptions = {};
367
+ if (additionalOptions[coll]) {
368
+ collOptions[coll] = additionalOptions[coll];
369
+ chartCopy.update(collOptions);
370
+ }
371
+ });
372
+ }
373
+
374
+ // Reflect axis extremes in the export (#5924)
375
+ each(chart.axes, function(axis) {
376
+ var axisCopy = H.find(chartCopy.axes, function(copy) {
377
+ return copy.options.internalKey ===
378
+ axis.userOptions.internalKey;
379
+ }),
380
+ extremes = axis.getExtremes(),
381
+ userMin = extremes.userMin,
382
+ userMax = extremes.userMax;
383
+
384
+ if (axisCopy && (userMin !== undefined || userMax !== undefined)) {
385
+ axisCopy.setExtremes(userMin, userMax, true, false);
386
+ }
387
+ });
388
+
389
+ // Get the SVG from the container's innerHTML
390
+ svg = chartCopy.getChartHTML();
391
+
392
+ svg = chart.sanitizeSVG(svg, options);
393
+
394
+ // free up memory
395
+ options = null;
396
+ chartCopy.destroy();
397
+ discardElement(sandbox);
398
+
399
+ return svg;
400
+ },
401
+
402
+ getSVGForExport: function(options, chartOptions) {
403
+ var chartExportingOptions = this.options.exporting;
404
+
405
+ return this.getSVG(merge({
406
+ chart: {
407
+ borderRadius: 0
408
+ }
409
+ },
410
+ chartExportingOptions.chartOptions,
411
+ chartOptions, {
412
+ exporting: {
413
+ sourceWidth: (options && options.sourceWidth) || chartExportingOptions.sourceWidth,
414
+ sourceHeight: (options && options.sourceHeight) || chartExportingOptions.sourceHeight
415
+ }
416
+ }
417
+ ));
418
+ },
419
+
420
+ /**
421
+ * Submit the SVG representation of the chart to the server
422
+ * @param {Object} options Exporting options. Possible members are url, type, width and formAttributes.
423
+ * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
424
+ */
425
+ exportChart: function(options, chartOptions) {
426
+
427
+ var svg = this.getSVGForExport(options, chartOptions);
428
+
429
+ // merge the options
430
+ options = merge(this.options.exporting, options);
431
+
432
+ // do the post
433
+ H.post(options.url, {
434
+ filename: options.filename || 'chart',
435
+ type: options.type,
436
+ width: options.width || 0, // IE8 fails to post undefined correctly, so use 0
437
+ scale: options.scale,
438
+ svg: svg
439
+ }, options.formAttributes);
440
+
441
+ },
442
+
443
+ /**
444
+ * Print the chart
445
+ */
446
+ print: function() {
447
+
448
+ var chart = this,
449
+ container = chart.container,
450
+ origDisplay = [],
451
+ origParent = container.parentNode,
452
+ body = doc.body,
453
+ childNodes = body.childNodes,
454
+ printMaxWidth = chart.options.exporting.printMaxWidth,
455
+ resetParams,
456
+ handleMaxWidth;
457
+
458
+ if (chart.isPrinting) { // block the button while in printing mode
459
+ return;
460
+ }
461
+
462
+ chart.isPrinting = true;
463
+ chart.pointer.reset(null, 0);
464
+
465
+ fireEvent(chart, 'beforePrint');
466
+
467
+ // Handle printMaxWidth
468
+ handleMaxWidth = printMaxWidth && chart.chartWidth > printMaxWidth;
469
+ if (handleMaxWidth) {
470
+ resetParams = [chart.options.chart.width, undefined, false];
471
+ chart.setSize(printMaxWidth, undefined, false);
472
+ }
473
+
474
+ // hide all body content
475
+ each(childNodes, function(node, i) {
476
+ if (node.nodeType === 1) {
477
+ origDisplay[i] = node.style.display;
478
+ node.style.display = 'none';
479
+ }
480
+ });
481
+
482
+ // pull out the chart
483
+ body.appendChild(container);
484
+
485
+ // print
486
+ win.focus(); // #1510
487
+ win.print();
488
+
489
+ // allow the browser to prepare before reverting
490
+ setTimeout(function() {
491
+
492
+ // put the chart back in
493
+ origParent.appendChild(container);
494
+
495
+ // restore all body content
496
+ each(childNodes, function(node, i) {
497
+ if (node.nodeType === 1) {
498
+ node.style.display = origDisplay[i];
499
+ }
500
+ });
501
+
502
+ chart.isPrinting = false;
503
+
504
+ // Reset printMaxWidth
505
+ if (handleMaxWidth) {
506
+ chart.setSize.apply(chart, resetParams);
507
+ }
508
+
509
+ fireEvent(chart, 'afterPrint');
510
+
511
+ }, 1000);
512
+
513
+ },
514
+
515
+ /**
516
+ * Display a popup menu for choosing the export type
517
+ *
518
+ * @param {String} className An identifier for the menu
519
+ * @param {Array} items A collection with text and onclicks for the items
520
+ * @param {Number} x The x position of the opener button
521
+ * @param {Number} y The y position of the opener button
522
+ * @param {Number} width The width of the opener button
523
+ * @param {Number} height The height of the opener button
524
+ */
525
+ contextMenu: function(className, items, x, y, width, height, button) {
526
+ var chart = this,
527
+ navOptions = chart.options.navigation,
528
+ chartWidth = chart.chartWidth,
529
+ chartHeight = chart.chartHeight,
530
+ cacheName = 'cache-' + className,
531
+ menu = chart[cacheName],
532
+ menuPadding = Math.max(width, height), // for mouse leave detection
533
+ innerMenu,
534
+ hide,
535
+ menuStyle,
536
+ removeMouseUp;
537
+
538
+ // create the menu only the first time
539
+ if (!menu) {
540
+
541
+ // create a HTML element above the SVG
542
+ chart[cacheName] = menu = createElement('div', {
543
+ className: className
544
+ }, {
545
+ position: 'absolute',
546
+ zIndex: 1000,
547
+ padding: menuPadding + 'px'
548
+ }, chart.container);
549
+
550
+ innerMenu = createElement('div', {
551
+ className: 'highcharts-menu'
552
+ }, null, menu);
553
+
554
+
555
+ // Presentational CSS
556
+ css(innerMenu, extend({
557
+ MozBoxShadow: '3px 3px 10px #888',
558
+ WebkitBoxShadow: '3px 3px 10px #888',
559
+ boxShadow: '3px 3px 10px #888'
560
+ }, navOptions.menuStyle));
561
+
562
+
563
+ // hide on mouse out
564
+ hide = function() {
565
+ css(menu, {
566
+ display: 'none'
567
+ });
568
+ if (button) {
569
+ button.setState(0);
570
+ }
571
+ chart.openMenu = false;
572
+ };
573
+
574
+ // Hide the menu some time after mouse leave (#1357)
575
+ addEvent(menu, 'mouseleave', function() {
576
+ menu.hideTimer = setTimeout(hide, 500);
577
+ });
578
+ addEvent(menu, 'mouseenter', function() {
579
+ clearTimeout(menu.hideTimer);
580
+ });
581
+
582
+
583
+ // Hide it on clicking or touching outside the menu (#2258, #2335,
584
+ // #2407)
585
+ removeMouseUp = addEvent(doc, 'mouseup', function(e) {
586
+ if (!chart.pointer.inClass(e.target, className)) {
587
+ hide();
588
+ }
589
+ });
590
+ addEvent(chart, 'destroy', removeMouseUp);
591
+
592
+
593
+ // create the items
594
+ each(items, function(item) {
595
+ if (item) {
596
+ var element;
597
+
598
+ if (item.separator) {
599
+ element = createElement('hr', null, null, innerMenu);
600
+
601
+ } else {
602
+ element = createElement('div', {
603
+ className: 'highcharts-menu-item',
604
+ onclick: function(e) {
605
+ if (e) { // IE7
606
+ e.stopPropagation();
607
+ }
608
+ hide();
609
+ if (item.onclick) {
610
+ item.onclick.apply(chart, arguments);
611
+ }
612
+ },
613
+ innerHTML: item.text || chart.options.lang[item.textKey]
614
+ }, null, innerMenu);
615
+
616
+
617
+ element.onmouseover = function() {
618
+ css(this, navOptions.menuItemHoverStyle);
619
+ };
620
+ element.onmouseout = function() {
621
+ css(this, navOptions.menuItemStyle);
622
+ };
623
+ css(element, extend({
624
+ cursor: 'pointer'
625
+ }, navOptions.menuItemStyle));
626
+
627
+ }
628
+
629
+ // Keep references to menu divs to be able to destroy them
630
+ chart.exportDivElements.push(element);
631
+ }
632
+ });
633
+
634
+ // Keep references to menu and innerMenu div to be able to destroy them
635
+ chart.exportDivElements.push(innerMenu, menu);
636
+
637
+ chart.exportMenuWidth = menu.offsetWidth;
638
+ chart.exportMenuHeight = menu.offsetHeight;
639
+ }
640
+
641
+ menuStyle = {
642
+ display: 'block'
643
+ };
644
+
645
+ // if outside right, right align it
646
+ if (x + chart.exportMenuWidth > chartWidth) {
647
+ menuStyle.right = (chartWidth - x - width - menuPadding) + 'px';
648
+ } else {
649
+ menuStyle.left = (x - menuPadding) + 'px';
650
+ }
651
+ // if outside bottom, bottom align it
652
+ if (y + height + chart.exportMenuHeight > chartHeight && button.alignOptions.verticalAlign !== 'top') {
653
+ menuStyle.bottom = (chartHeight - y - menuPadding) + 'px';
654
+ } else {
655
+ menuStyle.top = (y + height - menuPadding) + 'px';
656
+ }
657
+
658
+ css(menu, menuStyle);
659
+ chart.openMenu = true;
660
+ },
661
+
662
+ /**
663
+ * Add the export button to the chart
664
+ */
665
+ addButton: function(options) {
666
+ var chart = this,
667
+ renderer = chart.renderer,
668
+ btnOptions = merge(chart.options.navigation.buttonOptions, options),
669
+ onclick = btnOptions.onclick,
670
+ menuItems = btnOptions.menuItems,
671
+ symbol,
672
+ button,
673
+ symbolSize = btnOptions.symbolSize || 12;
674
+ if (!chart.btnCount) {
675
+ chart.btnCount = 0;
676
+ }
677
+
678
+ // Keeps references to the button elements
679
+ if (!chart.exportDivElements) {
680
+ chart.exportDivElements = [];
681
+ chart.exportSVGElements = [];
682
+ }
683
+
684
+ if (btnOptions.enabled === false) {
685
+ return;
686
+ }
687
+
688
+
689
+ var attr = btnOptions.theme,
690
+ states = attr.states,
691
+ hover = states && states.hover,
692
+ select = states && states.select,
693
+ callback;
694
+
695
+ delete attr.states;
696
+
697
+ if (onclick) {
698
+ callback = function(e) {
699
+ e.stopPropagation();
700
+ onclick.call(chart, e);
701
+ };
702
+
703
+ } else if (menuItems) {
704
+ callback = function() {
705
+ chart.contextMenu(
706
+ button.menuClassName,
707
+ menuItems,
708
+ button.translateX,
709
+ button.translateY,
710
+ button.width,
711
+ button.height,
712
+ button
713
+ );
714
+ button.setState(2);
715
+ };
716
+ }
717
+
718
+
719
+ if (btnOptions.text && btnOptions.symbol) {
720
+ attr.paddingLeft = pick(attr.paddingLeft, 25);
721
+
722
+ } else if (!btnOptions.text) {
723
+ extend(attr, {
724
+ width: btnOptions.width,
725
+ height: btnOptions.height,
726
+ padding: 0
727
+ });
728
+ }
729
+
730
+ button = renderer.button(btnOptions.text, 0, 0, callback, attr, hover, select)
731
+ .addClass(options.className)
732
+ .attr({
733
+
734
+ 'stroke-linecap': 'round',
735
+
736
+ title: chart.options.lang[btnOptions._titleKey],
737
+ zIndex: 3 // #4955
738
+ });
739
+ button.menuClassName = options.menuClassName || 'highcharts-menu-' + chart.btnCount++;
740
+
741
+ if (btnOptions.symbol) {
742
+ symbol = renderer.symbol(
743
+ btnOptions.symbol,
744
+ btnOptions.symbolX - (symbolSize / 2),
745
+ btnOptions.symbolY - (symbolSize / 2),
746
+ symbolSize,
747
+ symbolSize
748
+ )
749
+ .addClass('highcharts-button-symbol')
750
+ .attr({
751
+ zIndex: 1
752
+ }).add(button);
753
+
754
+
755
+ symbol.attr({
756
+ stroke: btnOptions.symbolStroke,
757
+ fill: btnOptions.symbolFill,
758
+ 'stroke-width': btnOptions.symbolStrokeWidth || 1
759
+ });
760
+
761
+ }
762
+
763
+ button.add()
764
+ .align(extend(btnOptions, {
765
+ width: button.width,
766
+ x: pick(btnOptions.x, chart.buttonOffset) // #1654
767
+ }), true, 'spacingBox');
768
+
769
+ chart.buttonOffset += (button.width + btnOptions.buttonSpacing) * (btnOptions.align === 'right' ? -1 : 1);
770
+
771
+ chart.exportSVGElements.push(button, symbol);
772
+
773
+ },
774
+
775
+ /**
776
+ * Destroy the buttons.
777
+ */
778
+ destroyExport: function(e) {
779
+ var chart = e ? e.target : this,
780
+ exportSVGElements = chart.exportSVGElements,
781
+ exportDivElements = chart.exportDivElements;
782
+
783
+ // Destroy the extra buttons added
784
+ if (exportSVGElements) {
785
+ each(exportSVGElements, function(elem, i) {
786
+
787
+ // Destroy and null the svg/vml elements
788
+ if (elem) { // #1822
789
+ elem.onclick = elem.ontouchstart = null;
790
+ chart.exportSVGElements[i] = elem.destroy();
791
+ }
792
+ });
793
+ exportSVGElements.length = 0;
794
+ }
795
+
796
+ // Destroy the divs for the menu
797
+ if (exportDivElements) {
798
+ each(exportDivElements, function(elem, i) {
799
+
800
+ // Remove the event handler
801
+ clearTimeout(elem.hideTimer); // #5427
802
+ removeEvent(elem, 'mouseleave');
803
+
804
+ // Remove inline events
805
+ chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
806
+
807
+ // Destroy the div by moving to garbage bin
808
+ discardElement(elem);
809
+ });
810
+ exportDivElements.length = 0;
811
+ }
812
+ }
813
+ });
814
+
815
+
816
+
817
+
818
+ symbols.menu = function(x, y, width, height) {
819
+ var arr = [
820
+ 'M', x, y + 2.5,
821
+ 'L', x + width, y + 2.5,
822
+ 'M', x, y + height / 2 + 0.5,
823
+ 'L', x + width, y + height / 2 + 0.5,
824
+ 'M', x, y + height - 1.5,
825
+ 'L', x + width, y + height - 1.5
826
+ ];
827
+ return arr;
828
+ };
829
+
830
+ // Add the buttons on chart load
831
+ Chart.prototype.renderExporting = function() {
832
+ var n,
833
+ exportingOptions = this.options.exporting,
834
+ buttons = exportingOptions.buttons,
835
+ isDirty = this.isDirtyExporting || !this.exportSVGElements;
836
+
837
+ this.buttonOffset = 0;
838
+ if (this.isDirtyExporting) {
839
+ this.destroyExport();
840
+ }
841
+
842
+ if (isDirty && exportingOptions.enabled !== false) {
843
+
844
+ for (n in buttons) {
845
+ this.addButton(buttons[n]);
846
+ }
847
+
848
+ this.isDirtyExporting = false;
849
+ }
850
+
851
+ // Destroy the export elements at chart destroy
852
+ addEvent(this, 'destroy', this.destroyExport);
853
+ };
854
+
855
+ Chart.prototype.callbacks.push(function(chart) {
856
+
857
+ function update(prop, options, redraw) {
858
+ chart.isDirtyExporting = true;
859
+ merge(true, chart.options[prop], options);
860
+ if (pick(redraw, true)) {
861
+ chart.redraw();
862
+ }
863
+
864
+ }
865
+
866
+ chart.renderExporting();
867
+
868
+ addEvent(chart, 'redraw', chart.renderExporting);
869
+
870
+ // Add update methods to handle chart.update and chart.exporting.update
871
+ // and chart.navigation.update.
872
+ each(['exporting', 'navigation'], function(prop) {
873
+ chart[prop] = {
874
+ update: function(options, redraw) {
875
+ update(prop, options, redraw);
876
+ }
877
+ };
878
+ });
879
+ });
880
+
881
+ }(Highcharts));
882
+ }));