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,161 @@
1
+ /**
2
+ * @license Highcharts JS v5.0.6 (2016-12-07)
3
+ * Plugin for displaying a message when there is no data visible in chart.
4
+ *
5
+ * (c) 2010-2016 Highsoft AS
6
+ * Author: Oystein Moseng
7
+ *
8
+ * License: www.highcharts.com/license
9
+ */
10
+ (function(factory) {
11
+ if (typeof module === 'object' && module.exports) {
12
+ module.exports = factory;
13
+ } else {
14
+ factory(Highcharts);
15
+ }
16
+ }(function(Highcharts) {
17
+ (function(H) {
18
+ /**
19
+ * Plugin for displaying a message when there is no data visible in chart.
20
+ *
21
+ * (c) 2010-2016 Highsoft AS
22
+ * Author: Oystein Moseng
23
+ *
24
+ * License: www.highcharts.com/license
25
+ */
26
+ 'use strict';
27
+
28
+ var seriesTypes = H.seriesTypes,
29
+ chartPrototype = H.Chart.prototype,
30
+ defaultOptions = H.getOptions(),
31
+ extend = H.extend,
32
+ each = H.each;
33
+
34
+ // Add language option
35
+ extend(defaultOptions.lang, {
36
+ noData: 'No data to display'
37
+ });
38
+
39
+ // Add default display options for message
40
+ defaultOptions.noData = {
41
+ position: {
42
+ x: 0,
43
+ y: 0,
44
+ align: 'center',
45
+ verticalAlign: 'middle'
46
+ }
47
+ // useHTML: false
48
+ };
49
+
50
+
51
+ // Presentational
52
+ defaultOptions.noData.style = {
53
+ fontWeight: 'bold',
54
+ fontSize: '12px',
55
+ color: '#666666'
56
+ };
57
+
58
+
59
+ /**
60
+ * Define hasData functions for series. These return true if there are data points on this series within the plot area
61
+ */
62
+ function hasDataPie() {
63
+ return !!this.points.length; /* != 0 */
64
+ }
65
+
66
+ each(['pie', 'gauge', 'waterfall', 'bubble', 'treemap'], function(type) {
67
+ if (seriesTypes[type]) {
68
+ seriesTypes[type].prototype.hasData = hasDataPie;
69
+ }
70
+ });
71
+
72
+ H.Series.prototype.hasData = function() {
73
+ return this.visible && this.dataMax !== undefined && this.dataMin !== undefined; // #3703
74
+ };
75
+
76
+ /**
77
+ * Display a no-data message.
78
+ *
79
+ * @param {String} str An optional message to show in place of the default one
80
+ */
81
+ chartPrototype.showNoData = function(str) {
82
+ var chart = this,
83
+ options = chart.options,
84
+ text = str || options.lang.noData,
85
+ noDataOptions = options.noData;
86
+
87
+ if (!chart.noDataLabel) {
88
+ chart.noDataLabel = chart.renderer
89
+ .label(
90
+ text,
91
+ 0,
92
+ 0,
93
+ null,
94
+ null,
95
+ null,
96
+ noDataOptions.useHTML,
97
+ null,
98
+ 'no-data'
99
+ );
100
+
101
+
102
+ chart.noDataLabel
103
+ .attr(noDataOptions.attr)
104
+ .css(noDataOptions.style);
105
+
106
+
107
+ chart.noDataLabel.add();
108
+
109
+ chart.noDataLabel.align(extend(chart.noDataLabel.getBBox(), noDataOptions.position), false, 'plotBox');
110
+ }
111
+ };
112
+
113
+ /**
114
+ * Hide no-data message
115
+ */
116
+ chartPrototype.hideNoData = function() {
117
+ var chart = this;
118
+ if (chart.noDataLabel) {
119
+ chart.noDataLabel = chart.noDataLabel.destroy();
120
+ }
121
+ };
122
+
123
+ /**
124
+ * Returns true if there are data points within the plot area now
125
+ */
126
+ chartPrototype.hasData = function() {
127
+ var chart = this,
128
+ series = chart.series,
129
+ i = series.length;
130
+
131
+ while (i--) {
132
+ if (series[i].hasData() && !series[i].options.isInternal) {
133
+ return true;
134
+ }
135
+ }
136
+
137
+ return false;
138
+ };
139
+
140
+ /**
141
+ * Show no-data message if there is no data in sight. Otherwise, hide it.
142
+ */
143
+ function handleNoData() {
144
+ var chart = this;
145
+ if (chart.hasData()) {
146
+ chart.hideNoData();
147
+ } else {
148
+ chart.showNoData();
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Add event listener to handle automatic display of no-data message
154
+ */
155
+ chartPrototype.callbacks.push(function(chart) {
156
+ H.addEvent(chart, 'load', handleNoData);
157
+ H.addEvent(chart, 'redraw', handleNoData);
158
+ });
159
+
160
+ }(Highcharts));
161
+ }));
@@ -0,0 +1,492 @@
1
+ /**
2
+ * @license Highcharts JS v5.0.6 (2016-12-07)
3
+ * Client side exporting module
4
+ *
5
+ * (c) 2015 Torstein Honsi / Oystein Moseng
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(Highcharts) {
17
+ /**
18
+ * Client side exporting module
19
+ *
20
+ * (c) 2015 Torstein Honsi / Oystein Moseng
21
+ *
22
+ * License: www.highcharts.com/license
23
+ */
24
+
25
+ 'use strict';
26
+ /*global MSBlobBuilder */
27
+
28
+ var merge = Highcharts.merge,
29
+ win = Highcharts.win,
30
+ nav = win.navigator,
31
+ doc = win.document,
32
+ each = Highcharts.each,
33
+ domurl = win.URL || win.webkitURL || win,
34
+ isMSBrowser = /Edge\/|Trident\/|MSIE /.test(nav.userAgent),
35
+ loadEventDeferDelay = isMSBrowser ? 150 : 0; // Milliseconds to defer image load event handlers to offset IE bug
36
+
37
+ // Dummy object so we can reuse our canvas-tools.js without errors
38
+ Highcharts.CanVGRenderer = {};
39
+
40
+
41
+ /**
42
+ * Downloads a script and executes a callback when done.
43
+ * @param {String} scriptLocation
44
+ * @param {Function} callback
45
+ */
46
+ function getScript(scriptLocation, callback) {
47
+ var head = doc.getElementsByTagName('head')[0],
48
+ script = doc.createElement('script');
49
+
50
+ script.type = 'text/javascript';
51
+ script.src = scriptLocation;
52
+ script.onload = callback;
53
+ script.onerror = function() {
54
+ console.error('Error loading script', scriptLocation); // eslint-disable-line no-console
55
+ };
56
+
57
+ head.appendChild(script);
58
+ }
59
+
60
+ // Download contents by dataURL/blob
61
+ Highcharts.downloadURL = function(dataURL, filename) {
62
+ var a = doc.createElement('a'),
63
+ windowRef;
64
+
65
+ // IE specific blob implementation
66
+ if (nav.msSaveOrOpenBlob) {
67
+ nav.msSaveOrOpenBlob(dataURL, filename);
68
+ return;
69
+ }
70
+
71
+ // Try HTML5 download attr if supported
72
+ if (a.download !== undefined) {
73
+ a.href = dataURL;
74
+ a.download = filename; // HTML5 download attribute
75
+ a.target = '_blank';
76
+ doc.body.appendChild(a);
77
+ a.click();
78
+ doc.body.removeChild(a);
79
+ } else {
80
+ // No download attr, just opening data URI
81
+ try {
82
+ windowRef = win.open(dataURL, 'chart');
83
+ if (windowRef === undefined || windowRef === null) {
84
+ throw 'Failed to open window';
85
+ }
86
+ } catch (e) {
87
+ // window.open failed, trying location.href
88
+ win.location.href = dataURL;
89
+ }
90
+ }
91
+ };
92
+
93
+ // Get blob URL from SVG code. Falls back to normal data URI.
94
+ Highcharts.svgToDataUrl = function(svg) {
95
+ var webKit = nav.userAgent.indexOf('WebKit') > -1 && nav.userAgent.indexOf('Chrome') < 0; // Webkit and not chrome
96
+ try {
97
+ // Safari requires data URI since it doesn't allow navigation to blob URLs
98
+ // Firefox has an issue with Blobs and internal references, leading to gradients not working using Blobs (#4550)
99
+ if (!webKit && nav.userAgent.toLowerCase().indexOf('firefox') < 0) {
100
+ return domurl.createObjectURL(new win.Blob([svg], {
101
+ type: 'image/svg+xml;charset-utf-16'
102
+ }));
103
+ }
104
+ } catch (e) {
105
+ // Ignore
106
+ }
107
+ return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
108
+ };
109
+
110
+ // Get data:URL from image URL
111
+ // Pass in callbacks to handle results. finallyCallback is always called at the end of the process. Supplying this callback is optional.
112
+ // All callbacks receive four arguments: imageURL, imageType, callbackArgs and scale. callbackArgs is used only by callbacks and can contain whatever.
113
+ Highcharts.imageToDataUrl = function(imageURL, imageType, callbackArgs, scale, successCallback, taintedCallback, noCanvasSupportCallback, failedLoadCallback, finallyCallback) {
114
+ var img = new win.Image(),
115
+ taintedHandler,
116
+ loadHandler = function() {
117
+ setTimeout(function() {
118
+ var canvas = doc.createElement('canvas'),
119
+ ctx = canvas.getContext && canvas.getContext('2d'),
120
+ dataURL;
121
+ try {
122
+ if (!ctx) {
123
+ noCanvasSupportCallback(imageURL, imageType, callbackArgs, scale);
124
+ } else {
125
+ canvas.height = img.height * scale;
126
+ canvas.width = img.width * scale;
127
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
128
+
129
+ // Now we try to get the contents of the canvas.
130
+ try {
131
+ dataURL = canvas.toDataURL(imageType);
132
+ successCallback(dataURL, imageType, callbackArgs, scale);
133
+ } catch (e) {
134
+ taintedHandler(imageURL, imageType, callbackArgs, scale);
135
+ }
136
+ }
137
+ } finally {
138
+ if (finallyCallback) {
139
+ finallyCallback(imageURL, imageType, callbackArgs, scale);
140
+ }
141
+ }
142
+ }, loadEventDeferDelay); // IE bug where image is not always ready despite calling load event.
143
+ },
144
+ // Image load failed (e.g. invalid URL)
145
+ errorHandler = function() {
146
+ failedLoadCallback(imageURL, imageType, callbackArgs, scale);
147
+ if (finallyCallback) {
148
+ finallyCallback(imageURL, imageType, callbackArgs, scale);
149
+ }
150
+ };
151
+
152
+ // This is called on load if the image drawing to canvas failed with a security error.
153
+ // We retry the drawing with crossOrigin set to Anonymous.
154
+ taintedHandler = function() {
155
+ img = new win.Image();
156
+ taintedHandler = taintedCallback;
157
+ img.crossOrigin = 'Anonymous'; // Must be set prior to loading image source
158
+ img.onload = loadHandler;
159
+ img.onerror = errorHandler;
160
+ img.src = imageURL;
161
+ };
162
+
163
+ img.onload = loadHandler;
164
+ img.onerror = errorHandler;
165
+ img.src = imageURL;
166
+ };
167
+
168
+ /**
169
+ * Get data URL to an image of an SVG and call download on it
170
+ *
171
+ * options object:
172
+ * filename: Name of resulting downloaded file without extension
173
+ * type: File type of resulting download
174
+ * scale: Scaling factor of downloaded image compared to source
175
+ * libURL: URL pointing to location of dependency scripts to download on demand
176
+ */
177
+ Highcharts.downloadSVGLocal = function(svg, options, failCallback, successCallback) {
178
+ var svgurl,
179
+ blob,
180
+ objectURLRevoke = true,
181
+ finallyHandler,
182
+ libURL = options.libURL || Highcharts.getOptions().exporting.libURL,
183
+ dummySVGContainer = doc.createElement('div'),
184
+ imageType = options.type || 'image/png',
185
+ filename = (options.filename || 'chart') + '.' + (imageType === 'image/svg+xml' ? 'svg' : imageType.split('/')[1]),
186
+ scale = options.scale || 1;
187
+
188
+ libURL = libURL.slice(-1) !== '/' ? libURL + '/' : libURL; // Allow libURL to end with or without fordward slash
189
+
190
+ function svgToPdf(svgElement, margin) {
191
+ var width = svgElement.width.baseVal.value + 2 * margin,
192
+ height = svgElement.height.baseVal.value + 2 * margin,
193
+ pdf = new win.jsPDF('l', 'pt', [width, height]); // eslint-disable-line new-cap
194
+ win.svgElementToPdf(svgElement, pdf, {
195
+ removeInvalid: true
196
+ });
197
+ return pdf.output('datauristring');
198
+ }
199
+
200
+ function downloadPDF() {
201
+ dummySVGContainer.innerHTML = svg;
202
+ var textElements = dummySVGContainer.getElementsByTagName('text'),
203
+ titleElements,
204
+ svgElementStyle = dummySVGContainer.getElementsByTagName('svg')[0].style;
205
+ // Workaround for the text styling. Making sure it does pick up the root element
206
+ each(textElements, function(el) {
207
+ // Workaround for the text styling. making sure it does pick up the root element
208
+ each(['font-family', 'font-size'], function(property) {
209
+ if (!el.style[property] && svgElementStyle[property]) {
210
+ el.style[property] = svgElementStyle[property];
211
+ }
212
+ });
213
+ el.style['font-family'] = el.style['font-family'] && el.style['font-family'].split(' ').splice(-1);
214
+ // Workaround for plotband with width, removing title from text nodes
215
+ titleElements = el.getElementsByTagName('title');
216
+ each(titleElements, function(titleElement) {
217
+ el.removeChild(titleElement);
218
+ });
219
+ });
220
+ var svgData = svgToPdf(dummySVGContainer.firstChild, 0);
221
+ Highcharts.downloadURL(svgData, filename);
222
+ if (successCallback) {
223
+ successCallback();
224
+ }
225
+ }
226
+
227
+ // Initiate download depending on file type
228
+ if (imageType === 'image/svg+xml') {
229
+ // SVG download. In this case, we want to use Microsoft specific Blob if available
230
+ try {
231
+ if (nav.msSaveOrOpenBlob) {
232
+ blob = new MSBlobBuilder();
233
+ blob.append(svg);
234
+ svgurl = blob.getBlob('image/svg+xml');
235
+ } else {
236
+ svgurl = Highcharts.svgToDataUrl(svg);
237
+ }
238
+ Highcharts.downloadURL(svgurl, filename);
239
+ if (successCallback) {
240
+ successCallback();
241
+ }
242
+ } catch (e) {
243
+ failCallback();
244
+ }
245
+ } else if (imageType === 'application/pdf') {
246
+ if (win.jsPDF && win.svgElementToPdf) {
247
+ downloadPDF();
248
+ } else {
249
+ // Must load pdf libraries first
250
+ objectURLRevoke = true; // Don't destroy the object URL yet since we are doing things asynchronously. A cleaner solution would be nice, but this will do for now.
251
+ getScript(libURL + 'jspdf.js', function() {
252
+ getScript(libURL + 'rgbcolor.js', function() {
253
+ getScript(libURL + 'svg2pdf.js', function() {
254
+ downloadPDF();
255
+ });
256
+ });
257
+ });
258
+ }
259
+ } else {
260
+ // PNG/JPEG download - create bitmap from SVG
261
+
262
+ svgurl = Highcharts.svgToDataUrl(svg);
263
+ finallyHandler = function() {
264
+ try {
265
+ domurl.revokeObjectURL(svgurl);
266
+ } catch (e) {
267
+ // Ignore
268
+ }
269
+ };
270
+ // First, try to get PNG by rendering on canvas
271
+ Highcharts.imageToDataUrl(svgurl, imageType, { /* args */ }, scale, function(imageURL) {
272
+ // Success
273
+ try {
274
+ Highcharts.downloadURL(imageURL, filename);
275
+ if (successCallback) {
276
+ successCallback();
277
+ }
278
+ } catch (e) {
279
+ failCallback();
280
+ }
281
+ }, function() {
282
+ // Failed due to tainted canvas
283
+ // Create new and untainted canvas
284
+ var canvas = doc.createElement('canvas'),
285
+ ctx = canvas.getContext('2d'),
286
+ imageWidth = svg.match(/^<svg[^>]*width\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
287
+ imageHeight = svg.match(/^<svg[^>]*height\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
288
+ downloadWithCanVG = function() {
289
+ ctx.drawSvg(svg, 0, 0, imageWidth, imageHeight);
290
+ try {
291
+ Highcharts.downloadURL(nav.msSaveOrOpenBlob ? canvas.msToBlob() : canvas.toDataURL(imageType), filename);
292
+ if (successCallback) {
293
+ successCallback();
294
+ }
295
+ } catch (e) {
296
+ failCallback();
297
+ } finally {
298
+ finallyHandler();
299
+ }
300
+ };
301
+
302
+ canvas.width = imageWidth;
303
+ canvas.height = imageHeight;
304
+ if (win.canvg) {
305
+ // Use preloaded canvg
306
+ downloadWithCanVG();
307
+ } else {
308
+ // Must load canVG first
309
+ objectURLRevoke = true; // Don't destroy the object URL yet since we are doing things asynchronously. A cleaner solution would be nice, but this will do for now.
310
+ getScript(libURL + 'rgbcolor.js', function() { // Get RGBColor.js first
311
+ getScript(libURL + 'canvg.js', function() {
312
+ downloadWithCanVG();
313
+ });
314
+ });
315
+ }
316
+ },
317
+ // No canvas support
318
+ failCallback,
319
+ // Failed to load image
320
+ failCallback,
321
+ // Finally
322
+ function() {
323
+ if (objectURLRevoke) {
324
+ finallyHandler();
325
+ }
326
+ });
327
+ }
328
+ };
329
+
330
+ // Get SVG of chart prepared for client side export. This converts embedded images in the SVG to data URIs.
331
+ // The options and chartOptions arguments are passed to the getSVGForExport function.
332
+ Highcharts.Chart.prototype.getSVGForLocalExport = function(options, chartOptions, failCallback, successCallback) {
333
+ var chart = this,
334
+ images,
335
+ imagesEmbedded = 0,
336
+ chartCopyContainer,
337
+ chartCopyOptions,
338
+ el,
339
+ i,
340
+ l,
341
+ // After grabbing the SVG of the chart's copy container we need to do sanitation on the SVG
342
+ sanitize = function(svg) {
343
+ return chart.sanitizeSVG(svg, chartCopyOptions);
344
+ },
345
+ // Success handler, we converted image to base64!
346
+ embeddedSuccess = function(imageURL, imageType, callbackArgs) {
347
+ ++imagesEmbedded;
348
+
349
+ // Change image href in chart copy
350
+ callbackArgs.imageElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', imageURL);
351
+
352
+ // When done with last image we have our SVG
353
+ if (imagesEmbedded === images.length) {
354
+ successCallback(sanitize(chartCopyContainer.innerHTML));
355
+ }
356
+ };
357
+
358
+ // Hook into getSVG to get a copy of the chart copy's container
359
+ Highcharts.wrap(
360
+ Highcharts.Chart.prototype,
361
+ 'getChartHTML',
362
+ function(proceed) {
363
+ var ret = proceed.apply(
364
+ this,
365
+ Array.prototype.slice.call(arguments, 1)
366
+ );
367
+ chartCopyOptions = this.options;
368
+ chartCopyContainer = this.container.cloneNode(true);
369
+ return ret;
370
+ }
371
+ );
372
+
373
+ // Trigger hook to get chart copy
374
+ chart.getSVGForExport(options, chartOptions);
375
+ images = chartCopyContainer.getElementsByTagName('image');
376
+
377
+ try {
378
+ // If there are no images to embed, the SVG is okay now.
379
+ if (!images.length) {
380
+ successCallback(sanitize(chartCopyContainer.innerHTML)); // Use SVG of chart copy
381
+ return;
382
+ }
383
+
384
+ // Go through the images we want to embed
385
+ for (i = 0, l = images.length; i < l; ++i) {
386
+ el = images[i];
387
+ Highcharts.imageToDataUrl(el.getAttributeNS('http://www.w3.org/1999/xlink', 'href'), 'image/png', {
388
+ imageElement: el
389
+ }, options.scale,
390
+ embeddedSuccess,
391
+ // Tainted canvas
392
+ failCallback,
393
+ // No canvas support
394
+ failCallback,
395
+ // Failed to load source
396
+ failCallback
397
+ );
398
+ }
399
+ } catch (e) {
400
+ failCallback();
401
+ }
402
+ };
403
+
404
+ /**
405
+ * Add a new method to the Chart object to perform a local download
406
+ */
407
+ Highcharts.Chart.prototype.exportChartLocal = function(exportingOptions, chartOptions) {
408
+ var chart = this,
409
+ options = Highcharts.merge(chart.options.exporting, exportingOptions),
410
+ fallbackToExportServer = function() {
411
+ if (options.fallbackToExportServer === false) {
412
+ if (options.error) {
413
+ options.error();
414
+ } else {
415
+ throw 'Fallback to export server disabled';
416
+ }
417
+ } else {
418
+ chart.exportChart(options);
419
+ }
420
+ },
421
+ svgSuccess = function(svg) {
422
+ // If SVG contains foreignObjects all exports except SVG will fail,
423
+ // as both CanVG and svg2pdf choke on this. Gracefully fall back.
424
+ if (
425
+ svg.indexOf('<foreignObject') > -1 &&
426
+ options.type !== 'image/svg+xml'
427
+ ) {
428
+ fallbackToExportServer();
429
+ } else {
430
+ Highcharts.downloadSVGLocal(svg, options, fallbackToExportServer);
431
+ }
432
+ };
433
+
434
+ // If we have embedded images and are exporting to JPEG/PNG, Microsoft
435
+ // browsers won't handle it, so fall back.
436
+ if (
437
+ (isMSBrowser && options.type !== 'image/svg+xml' ||
438
+ options.type === 'application/pdf') &&
439
+ chart.container.getElementsByTagName('image').length
440
+ ) {
441
+ fallbackToExportServer();
442
+ return;
443
+ }
444
+
445
+ chart.getSVGForLocalExport(options, chartOptions, fallbackToExportServer, svgSuccess);
446
+ };
447
+
448
+ // Extend the default options to use the local exporter logic
449
+ merge(true, Highcharts.getOptions().exporting, {
450
+ libURL: 'https://code.highcharts.com/5.0.6/lib/',
451
+ buttons: {
452
+ contextButton: {
453
+ menuItems: [{
454
+ textKey: 'printChart',
455
+ onclick: function() {
456
+ this.print();
457
+ }
458
+ }, {
459
+ separator: true
460
+ }, {
461
+ textKey: 'downloadPNG',
462
+ onclick: function() {
463
+ this.exportChartLocal();
464
+ }
465
+ }, {
466
+ textKey: 'downloadJPEG',
467
+ onclick: function() {
468
+ this.exportChartLocal({
469
+ type: 'image/jpeg'
470
+ });
471
+ }
472
+ }, {
473
+ textKey: 'downloadSVG',
474
+ onclick: function() {
475
+ this.exportChartLocal({
476
+ type: 'image/svg+xml'
477
+ });
478
+ }
479
+ }, {
480
+ textKey: 'downloadPDF',
481
+ onclick: function() {
482
+ this.exportChartLocal({
483
+ type: 'application/pdf'
484
+ });
485
+ }
486
+ }]
487
+ }
488
+ }
489
+ });
490
+
491
+ }(Highcharts));
492
+ }));