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,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
+ }));