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.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +34 -0
- data/Gemfile +4 -0
- data/Rakefile +53 -32
- data/app/assets/javascripts/highcharts.js +18775 -17176
- data/app/assets/javascripts/highcharts/highcharts-3d.js +1849 -1563
- data/app/assets/javascripts/highcharts/highcharts-more.js +2162 -1988
- data/app/assets/javascripts/highcharts/modules/accessibility.js +1005 -0
- data/app/assets/javascripts/highcharts/modules/annotations.js +408 -401
- data/app/assets/javascripts/highcharts/modules/boost.js +561 -546
- data/app/assets/javascripts/highcharts/modules/broken-axis.js +330 -324
- data/app/assets/javascripts/highcharts/modules/data.js +973 -965
- data/app/assets/javascripts/highcharts/modules/drilldown.js +783 -723
- data/app/assets/javascripts/highcharts/modules/exporting.js +864 -785
- data/app/assets/javascripts/highcharts/modules/funnel.js +290 -306
- data/app/assets/javascripts/highcharts/modules/heatmap.js +701 -645
- data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +150 -132
- data/app/assets/javascripts/highcharts/modules/offline-exporting.js +414 -355
- data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +164 -0
- data/app/assets/javascripts/highcharts/modules/series-label.js +473 -448
- data/app/assets/javascripts/highcharts/modules/solid-gauge.js +279 -271
- data/app/assets/javascripts/highcharts/modules/treemap.js +921 -886
- data/app/assets/javascripts/highcharts/themes/dark-blue.js +307 -244
- data/app/assets/javascripts/highcharts/themes/dark-green.js +303 -244
- data/app/assets/javascripts/highcharts/themes/dark-unica.js +231 -201
- data/app/assets/javascripts/highcharts/themes/gray.js +314 -245
- data/app/assets/javascripts/highcharts/themes/grid-light.js +91 -66
- data/app/assets/javascripts/highcharts/themes/grid.js +124 -96
- data/app/assets/javascripts/highcharts/themes/sand-signika.js +119 -94
- data/app/assets/javascripts/highcharts/themes/skies.js +108 -85
- data/lib/highcharts/version.rb +1 -1
- metadata +13 -14
- data/app/assets/javascripts/highcharts/adapters/standalone-framework.js +0 -1
- data/app/assets/javascripts/highcharts/modules/canvas-tools.js +0 -3115
- data/app/assets/javascripts/highcharts/modules/map.js +0 -2117
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license Highcharts JS
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
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
|
-
|
11
|
-
|
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
|
}));
|