highcharts-rails 4.2.7 → 5.0.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 (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
  }));