Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
776 lars 1
/**
2
 * @license Highmaps JS v1.1.9 (2015-10-07)
3
 * Client side exporting module
4
 *
5
 * (c) 2015 Torstein Honsi / Oystein Moseng
6
 *
7
 * License: www.highcharts.com/license
8
 */
9
 
10
// JSLint options:
11
/*global Highcharts, HighchartsAdapter, document, window, Blob, MSBlobBuilder */
12
 
13
(function (Highcharts) {
14
 
15
// Dummy object so we can reuse our canvas-tools.js without errors
16
Highcharts.CanVGRenderer = {};
17
 
18
/**
19
 * Add a new method to the Chart object to perform a local download
20
 */
21
Highcharts.Chart.prototype.exportChartLocal = function (exportingOptions, chartOptions) {
22
	var chart = this,
23
		options = Highcharts.merge(chart.options.exporting, exportingOptions),
24
		webKit = navigator.userAgent.indexOf('WebKit') > -1 && navigator.userAgent.indexOf("Chrome") < 0, // Webkit and not chrome
25
		scale = options.scale || 2,
26
		chartCopyContainer,
27
		domurl = window.URL || window.webkitURL || window,
28
		images,
29
		imagesEmbedded = 0,
30
		el,
31
		i,
32
		l,
33
		fallbackToExportServer = function () {
34
			if (options.fallbackToExportServer === false) {
35
				throw 'Fallback to export server disabled';
36
			}
37
			chart.exportChart(options);
38
		},
39
		// Get data:URL from image URL
40
		// Pass in callbacks to handle results. finallyCallback is always called at the end of the process. Supplying this callback is optional.
41
		// All callbacks receive two arguments: imageURL, and callbackArgs. callbackArgs is used only by callbacks and can contain whatever.
42
		imageToDataUrl = function (imageURL, callbackArgs, successCallback, taintedCallback, noCanvasSupportCallback, failedLoadCallback, finallyCallback) {
43
			var img = new Image();
44
			if (!webKit) {
45
				img.crossOrigin = 'Anonymous'; // For some reason Safari chokes on this attribute
46
			}
47
			img.onload = function () {
48
				var canvas = document.createElement('canvas'),
49
					ctx = canvas.getContext && canvas.getContext('2d'),
50
					dataURL;
51
 
52
				if (!ctx) {
53
					noCanvasSupportCallback(imageURL, callbackArgs);
54
				} else {
55
					canvas.height = img.height * scale;
56
					canvas.width = img.width * scale;
57
					ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
58
 
59
					// Now we try to get the contents of the canvas.
60
					try {
61
						dataURL = canvas.toDataURL();
62
						successCallback(dataURL, callbackArgs);
63
					} catch (e) {
64
						// Failed - either tainted canvas or something else went horribly wrong
65
						if (e.name === 'SecurityError' || e.name === 'SECURITY_ERR' || e.message === 'SecurityError') {
66
							taintedCallback(imageURL, callbackArgs);
67
						} else {
68
							throw e;
69
						}
70
					}
71
				}
72
				if (finallyCallback) {
73
					finallyCallback(imageURL, callbackArgs);
74
				}
75
			};
76
			img.onerror = function () {
77
				failedLoadCallback(imageURL, callbackArgs);
78
				if (finallyCallback) {
79
					finallyCallback(imageURL, callbackArgs);
80
				}
81
			};
82
			img.src = imageURL;
83
		},
84
		// Get blob URL from SVG code. Falls back to normal data URI.
85
		svgToDataUrl = function (svg) {
86
			try {
87
				// Safari requires data URI since it doesn't allow navigation to blob URLs
88
				// Firefox has an issue with Blobs and internal references, leading to gradients not working using Blobs (#4550)
89
				if (!webKit && navigator.userAgent.toLowerCase().indexOf('firefox') < 0) {
90
					return domurl.createObjectURL(new Blob([svg], { type: 'image/svg+xml;charset-utf-16'}));
91
				}
92
			} catch (e) {
93
				// Ignore
94
			}
95
			return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
96
		},
97
		// Download contents by dataURL/blob
98
		download = function (dataURL, extension) {
99
			var a = document.createElement('a'),
100
				filename = (options.filename || 'chart') + '.' + extension,
101
				windowRef;
102
 
103
			// IE specific blob implementation
104
			if (navigator.msSaveOrOpenBlob) {
105
				navigator.msSaveOrOpenBlob(dataURL, filename);
106
				return;
107
			}
108
 
109
			// Try HTML5 download attr if supported
110
			if (typeof a.download !== 'undefined') {
111
				a.href = dataURL;
112
				a.download = filename; // HTML5 download attribute
113
				a.target = '_blank';
114
				document.body.appendChild(a);
115
				a.click();
116
				document.body.removeChild(a);
117
			} else {
118
				// No download attr, just opening data URI
119
				try {
120
					windowRef = window.open(dataURL, 'chart');
121
					if (typeof windowRef === 'undefined' || windowRef === null) {
122
						throw 1;
123
					}
124
				} catch (e) {
125
					// window.open failed, trying location.href
126
					window.location.href = dataURL;
127
				}
128
			}
129
		},
130
		// Get data URL to an image of the chart and call download on it
131
		initiateDownload = function () {
132
			var svgurl,
133
				blob,
134
				svg = chart.sanitizeSVG(chartCopyContainer.innerHTML); // SVG of chart copy
135
 
136
			// Initiate download depending on file type
137
			if (options && options.type === 'image/svg+xml') {
138
				// SVG download. In this case, we want to use Microsoft specific Blob if available
139
				try {
140
					if (navigator.msSaveOrOpenBlob) {
141
						blob = new MSBlobBuilder();
142
						blob.append(svg);
143
						svgurl = blob.getBlob('image/svg+xml');
144
					} else {
145
						svgurl = svgToDataUrl(svg);
146
					}
147
					download(svgurl, 'svg');
148
				} catch (e) {
149
					fallbackToExportServer();
150
				}
151
			} else {
152
				// PNG download - create bitmap from SVG
153
 
154
				// First, try to get PNG by rendering on canvas
155
				svgurl = svgToDataUrl(svg);
156
				imageToDataUrl(svgurl, { /* args */ }, function (imageURL) {
157
					// Success
158
					try {
159
						download(imageURL, 'png');
160
					} catch (e) {
161
						fallbackToExportServer();
162
					}
163
				}, function () {
164
					// Failed due to tainted canvas
165
					// Create new and untainted canvas
166
					var canvas = document.createElement('canvas'),
167
						ctx = canvas.getContext('2d'),
168
						imageWidth = svg.match(/^<svg[^>]*width\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
169
						imageHeight = svg.match(/^<svg[^>]*height\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
170
						downloadWithCanVG = function () {
171
							ctx.drawSvg(svg, 0, 0, imageWidth, imageHeight);
172
							try {
173
								download(navigator.msSaveOrOpenBlob ? canvas.msToBlob() : canvas.toDataURL('image/png'), 'png');
174
							} catch (e) {
175
								fallbackToExportServer();
176
							}
177
						};
178
 
179
					canvas.width = imageWidth;
180
					canvas.height = imageHeight;
181
					if (window.canvg) {
182
						// Use preloaded canvg
183
						downloadWithCanVG();
184
					} else {
185
						// Must load canVG first
186
						chart.showLoading();
187
						HighchartsAdapter.getScript(Highcharts.getOptions().global.canvasToolsURL, function () {
188
							chart.hideLoading();
189
							downloadWithCanVG();
190
						});
191
					}
192
				},
193
				// No canvas support
194
				fallbackToExportServer,
195
				// Failed to load image
196
				fallbackToExportServer,
197
				// Finally
198
				function () {
199
					try {
200
						domurl.revokeObjectURL(svgurl);
201
					} catch (e) {
202
						// Ignore
203
					}
204
				});
205
			}
206
		};
207
 
208
	// Hook into getSVG to get a copy of the chart copy's container
209
	Highcharts.wrap(Highcharts.Chart.prototype, 'getChartHTML', function (proceed) {
210
		chartCopyContainer = this.container.cloneNode(true);
211
		return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
212
	});
213
 
214
	// Trigger hook to get chart copy
215
	chart.getSVGForExport(options, chartOptions);
216
	images = chartCopyContainer.getElementsByTagName('image');
217
 
218
	try {
219
		// If there are no images to embed, just go ahead and start the download process
220
		if (!images.length) {
221
			initiateDownload();
222
		}
223
 
224
		// Success handler, we converted image to base64!
225
		function embeddedSuccess(imageURL, callbackArgs) {
226
			++imagesEmbedded;
227
 
228
			// Change image href in chart copy
229
			callbackArgs.imageElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', imageURL);
230
 
231
			// Start download when done with the last image
232
			if (imagesEmbedded === images.length) {
233
				initiateDownload();
234
			}
235
		}
236
 
237
		// Go through the images we want to embed
238
		for (i = 0, l = images.length; i < l; ++i) {
239
			el = images[i];
240
			imageToDataUrl(el.getAttributeNS('http://www.w3.org/1999/xlink', 'href'), { imageElement: el },
241
				embeddedSuccess,
242
				// Tainted canvas
243
				fallbackToExportServer,
244
				// No canvas support
245
				fallbackToExportServer,
246
				// Failed to load source
247
				fallbackToExportServer
248
			);
249
		}
250
	} catch (e) {
251
		fallbackToExportServer();
252
	}
253
};
254
 
255
// Extend the default options to use the local exporter logic
256
Highcharts.getOptions().exporting.buttons.contextButton.menuItems = [{
257
	textKey: 'printChart',
258
	onclick: function () {
259
		this.print();
260
	}
261
}, {
262
	separator: true
263
}, {
264
	textKey: 'downloadPNG',
265
	onclick: function () {
266
		this.exportChartLocal();
267
	}
268
}, {
269
	textKey: 'downloadSVG',
270
	onclick: function () {
271
		this.exportChartLocal({
272
			type: 'image/svg+xml'
273
		});
274
	}
275
}];
276
 
277
}(Highcharts));