highcharts-rails 4.2.7 → 5.0.0

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