highcharts-rails 4.2.5 → 4.2.6
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 +47 -0
- data/app/assets/javascripts/highcharts.js +261 -151
- data/app/assets/javascripts/highcharts/highcharts-3d.js +173 -184
- data/app/assets/javascripts/highcharts/highcharts-more.js +60 -13
- data/app/assets/javascripts/highcharts/modules/broken-axis.js +1 -1
- data/app/assets/javascripts/highcharts/modules/canvas-tools.js +1 -1
- data/app/assets/javascripts/highcharts/modules/data.js +11 -1
- data/app/assets/javascripts/highcharts/modules/drilldown.js +17 -10
- data/app/assets/javascripts/highcharts/modules/exporting.js +6 -9
- data/app/assets/javascripts/highcharts/modules/funnel.js +4 -4
- data/app/assets/javascripts/highcharts/modules/heatmap.js +1 -1
- data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +1 -1
- data/app/assets/javascripts/highcharts/modules/offline-exporting.js +237 -201
- data/app/assets/javascripts/highcharts/modules/solid-gauge.js +1 -1
- data/app/assets/javascripts/highcharts/modules/treemap.js +16 -5
- data/lib/highcharts/version.rb +1 -1
- metadata +2 -2
@@ -2,7 +2,7 @@
|
|
2
2
|
// @compilation_level SIMPLE_OPTIMIZATIONS
|
3
3
|
|
4
4
|
/**
|
5
|
-
* @license Highcharts JS v4.2.
|
5
|
+
* @license Highcharts JS v4.2.6 (2016-08-02)
|
6
6
|
*
|
7
7
|
* (c) 2009-2016 Torstein Honsi
|
8
8
|
*
|
@@ -364,6 +364,7 @@ var arrayMin = Highcharts.arrayMin,
|
|
364
364
|
options.innerRadius,
|
365
365
|
pick(options.thickness, 10)
|
366
366
|
],
|
367
|
+
offset = Math.min(this.offset, 0),
|
367
368
|
percentRegex = /%$/,
|
368
369
|
start,
|
369
370
|
end,
|
@@ -406,6 +407,8 @@ var arrayMin = Highcharts.arrayMin,
|
|
406
407
|
end = startAngleRad + this.translate(to);
|
407
408
|
}
|
408
409
|
|
410
|
+
radii[0] -= offset; // #5283
|
411
|
+
radii[2] -= offset; // #5283
|
409
412
|
|
410
413
|
ret = this.chart.renderer.symbols.arc(
|
411
414
|
this.left + center[0],
|
@@ -822,7 +825,15 @@ var arrayMin = Highcharts.arrayMin,
|
|
822
825
|
if (!this.chart.polar && higherAreaPath[0] === 'M') {
|
823
826
|
higherAreaPath[0] = 'L'; // this probably doesn't work for spline
|
824
827
|
}
|
828
|
+
|
829
|
+
this.graphPath = linePath;
|
825
830
|
this.areaPath = this.areaPath.concat(lowerPath, higherAreaPath);
|
831
|
+
|
832
|
+
// Prepare for sideways animation
|
833
|
+
linePath.isArea = true;
|
834
|
+
linePath.xMap = lowerPath.xMap;
|
835
|
+
this.areaPath.xMap = lowerPath.xMap;
|
836
|
+
|
826
837
|
return linePath;
|
827
838
|
},
|
828
839
|
|
@@ -1120,6 +1131,7 @@ var arrayMin = Highcharts.arrayMin,
|
|
1120
1131
|
drawGraph: noop,
|
1121
1132
|
fixedBox: true,
|
1122
1133
|
forceDL: true,
|
1134
|
+
noSharedTooltip: true,
|
1123
1135
|
trackerGroups: ['group', 'dataLabelsGroup'],
|
1124
1136
|
|
1125
1137
|
/**
|
@@ -1802,7 +1814,7 @@ var arrayMin = Highcharts.arrayMin,
|
|
1802
1814
|
options = series.options,
|
1803
1815
|
stateOptions = options.states,
|
1804
1816
|
upColor = options.upColor || series.color,
|
1805
|
-
hoverColor = Highcharts.Color(upColor).brighten(
|
1817
|
+
hoverColor = Highcharts.Color(upColor).brighten(options.states.hover.brightness).get(),
|
1806
1818
|
seriesDownPointAttr = merge(series.pointAttr),
|
1807
1819
|
upColorProp = series.upColorProp;
|
1808
1820
|
|
@@ -1880,8 +1892,19 @@ var arrayMin = Highcharts.arrayMin,
|
|
1880
1892
|
*/
|
1881
1893
|
defaultPlotOptions.polygon = merge(defaultPlotOptions.scatter, {
|
1882
1894
|
marker: {
|
1883
|
-
enabled: false
|
1884
|
-
|
1895
|
+
enabled: false,
|
1896
|
+
states: {
|
1897
|
+
hover: {
|
1898
|
+
enabled: false
|
1899
|
+
}
|
1900
|
+
}
|
1901
|
+
},
|
1902
|
+
stickyTracking: false,
|
1903
|
+
tooltip: {
|
1904
|
+
followPointer: true,
|
1905
|
+
pointFormat: ''
|
1906
|
+
},
|
1907
|
+
trackByArea: true
|
1885
1908
|
});
|
1886
1909
|
|
1887
1910
|
/**
|
@@ -1889,13 +1912,28 @@ var arrayMin = Highcharts.arrayMin,
|
|
1889
1912
|
*/
|
1890
1913
|
seriesTypes.polygon = extendClass(seriesTypes.scatter, {
|
1891
1914
|
type: 'polygon',
|
1892
|
-
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
1915
|
+
getGraphPath: function () {
|
1916
|
+
|
1917
|
+
var graphPath = Series.prototype.getGraphPath.call(this),
|
1918
|
+
i = graphPath.length + 1;
|
1919
|
+
|
1920
|
+
// Close all segments
|
1921
|
+
while (i--) {
|
1922
|
+
if (i === graphPath.length || (graphPath[i] === 'M' && i > 0)) {
|
1923
|
+
graphPath.splice(i, 0, 'z');
|
1924
|
+
}
|
1925
|
+
}
|
1926
|
+
|
1927
|
+
this.areaPath = graphPath;
|
1928
|
+
return graphPath;
|
1929
|
+
},
|
1930
|
+
drawGraph: function () {
|
1931
|
+
this.options.fillColor = this.color; // Hack into the fill logic in area.drawGraph
|
1932
|
+
seriesTypes.area.prototype.drawGraph.call(this);
|
1896
1933
|
},
|
1897
|
-
|
1898
|
-
|
1934
|
+
drawLegendSymbol: Highcharts.LegendSymbolMixin.drawRectangle,
|
1935
|
+
drawTracker: Series.prototype.drawTracker,
|
1936
|
+
setStackedPoints: noop // No stacking points on polygons (#5310)
|
1899
1937
|
});
|
1900
1938
|
/* ****************************************************************************
|
1901
1939
|
* Start Bubble series code *
|
@@ -2456,15 +2494,24 @@ var arrayMin = Highcharts.arrayMin,
|
|
2456
2494
|
* line-like series.
|
2457
2495
|
*/
|
2458
2496
|
wrap(seriesProto, 'getGraphPath', function (proceed, points) {
|
2459
|
-
var series = this
|
2497
|
+
var series = this,
|
2498
|
+
i,
|
2499
|
+
firstValid;
|
2460
2500
|
|
2461
2501
|
// Connect the path
|
2462
2502
|
if (this.chart.polar) {
|
2463
2503
|
points = points || this.points;
|
2464
2504
|
|
2465
|
-
|
2505
|
+
// Append first valid point in order to connect the ends
|
2506
|
+
for (i = 0; i < points.length; i++) {
|
2507
|
+
if (!points[i].isNull) {
|
2508
|
+
firstValid = i;
|
2509
|
+
break;
|
2510
|
+
}
|
2511
|
+
}
|
2512
|
+
if (this.options.connectEnds !== false && firstValid !== undefined) {
|
2466
2513
|
this.connectEnds = true; // re-used in splines
|
2467
|
-
points.splice(points.length, 0, points[
|
2514
|
+
points.splice(points.length, 0, points[firstValid]);
|
2468
2515
|
}
|
2469
2516
|
|
2470
2517
|
// For area charts, pseudo points are added to the graph, now we need to translate these
|
@@ -2908,7 +2908,7 @@ if (CanvasRenderingContext2D) {
|
|
2908
2908
|
});
|
2909
2909
|
}
|
2910
2910
|
}/**
|
2911
|
-
* @license Highcharts JS v4.2.
|
2911
|
+
* @license Highcharts JS v4.2.6 (2016-08-02)
|
2912
2912
|
* CanVGRenderer Extension module
|
2913
2913
|
*
|
2914
2914
|
* (c) 2011-2016 Torstein Honsi, Erik Olsson
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license Highcharts JS v4.2.
|
2
|
+
* @license Highcharts JS v4.2.6 (2016-08-02)
|
3
3
|
* Data module
|
4
4
|
*
|
5
5
|
* (c) 2012-2016 Torstein Honsi
|
@@ -327,6 +327,16 @@
|
|
327
327
|
columns[gc - startColumn][gr - startRow] = cell.content.$t;
|
328
328
|
}
|
329
329
|
}
|
330
|
+
|
331
|
+
// Insert null for empty spreadsheet cells (#5298)
|
332
|
+
each(columns, function (column) {
|
333
|
+
for (i = 0; i < column.length; i++) {
|
334
|
+
if (column[i] === undefined) {
|
335
|
+
column[i] = null;
|
336
|
+
}
|
337
|
+
}
|
338
|
+
});
|
339
|
+
|
330
340
|
self.dataFound();
|
331
341
|
}
|
332
342
|
});
|
@@ -21,6 +21,7 @@
|
|
21
21
|
each = H.each,
|
22
22
|
extend = H.extend,
|
23
23
|
format = H.format,
|
24
|
+
merge = H.merge,
|
24
25
|
pick = H.pick,
|
25
26
|
wrap = H.wrap,
|
26
27
|
Chart = H.Chart,
|
@@ -146,11 +147,11 @@
|
|
146
147
|
last = undefined;
|
147
148
|
}
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
150
|
+
if (!ddOptions.color) {
|
151
|
+
ddOptions.color = color;
|
152
|
+
}
|
153
|
+
ddOptions._ddSeriesId = ddSeriesId++;
|
154
|
+
|
154
155
|
pointIndex = inArray(point, oldSeries.points);
|
155
156
|
|
156
157
|
// Record options for all current series
|
@@ -440,7 +441,7 @@
|
|
440
441
|
point.graphic
|
441
442
|
.attr(animateFrom)
|
442
443
|
.animate(
|
443
|
-
extend(point.shapeArgs, { fill: point.color }),
|
444
|
+
extend(point.shapeArgs, { fill: point.color || series.color }),
|
444
445
|
animationOptions
|
445
446
|
);
|
446
447
|
}
|
@@ -687,17 +688,23 @@
|
|
687
688
|
});
|
688
689
|
|
689
690
|
wrap(H.Series.prototype, 'drawDataLabels', function (proceed) {
|
690
|
-
var
|
691
|
+
var series = this,
|
692
|
+
css = series.chart.options.drilldown.activeDataLabelStyle,
|
693
|
+
renderer = series.chart.renderer;
|
691
694
|
|
692
|
-
proceed.call(
|
695
|
+
proceed.call(series);
|
693
696
|
|
694
|
-
each(
|
697
|
+
each(series.points, function (point) {
|
698
|
+
var pointCss = {};
|
695
699
|
if (point.drilldown && point.dataLabel) {
|
700
|
+
if (css.color === 'contrast') {
|
701
|
+
pointCss.color = renderer.getContrast(point.color || series.color);
|
702
|
+
}
|
696
703
|
point.dataLabel
|
697
704
|
.attr({
|
698
705
|
'class': 'highcharts-drilldown-data-label'
|
699
706
|
})
|
700
|
-
.css(css);
|
707
|
+
.css(merge(css, pointCss));
|
701
708
|
}
|
702
709
|
});
|
703
710
|
});
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license Highcharts JS v4.2.
|
2
|
+
* @license Highcharts JS v4.2.6 (2016-08-02)
|
3
3
|
* Exporting module
|
4
4
|
*
|
5
5
|
* (c) 2010-2016 Torstein Honsi
|
@@ -102,10 +102,10 @@ defaultOptions.exporting = {
|
|
102
102
|
//enabled: true,
|
103
103
|
//filename: 'chart',
|
104
104
|
type: 'image/png',
|
105
|
-
url: '
|
105
|
+
url: 'https://export.highcharts.com/',
|
106
106
|
//width: undefined,
|
107
107
|
printMaxWidth: 780,
|
108
|
-
|
108
|
+
scale: 2,
|
109
109
|
buttons: {
|
110
110
|
contextButton: {
|
111
111
|
menuClassName: PREFIX + 'contextmenu',
|
@@ -409,7 +409,7 @@ extend(Chart.prototype, {
|
|
409
409
|
filename: options.filename || 'chart',
|
410
410
|
type: options.type,
|
411
411
|
width: options.width || 0, // IE8 fails to post undefined correctly, so use 0
|
412
|
-
scale: options.scale
|
412
|
+
scale: options.scale,
|
413
413
|
svg: svg
|
414
414
|
}, options.formAttributes);
|
415
415
|
|
@@ -427,7 +427,6 @@ extend(Chart.prototype, {
|
|
427
427
|
body = doc.body,
|
428
428
|
childNodes = body.childNodes,
|
429
429
|
printMaxWidth = chart.options.exporting.printMaxWidth,
|
430
|
-
hasUserSize,
|
431
430
|
resetParams,
|
432
431
|
handleMaxWidth;
|
433
432
|
|
@@ -443,9 +442,8 @@ extend(Chart.prototype, {
|
|
443
442
|
// Handle printMaxWidth
|
444
443
|
handleMaxWidth = printMaxWidth && chart.chartWidth > printMaxWidth;
|
445
444
|
if (handleMaxWidth) {
|
446
|
-
|
447
|
-
|
448
|
-
chart.setSize(printMaxWidth, chart.chartHeight, false);
|
445
|
+
resetParams = [chart.options.chart.width, undefined, false];
|
446
|
+
chart.setSize(printMaxWidth, undefined, false);
|
449
447
|
}
|
450
448
|
|
451
449
|
// hide all body content
|
@@ -481,7 +479,6 @@ extend(Chart.prototype, {
|
|
481
479
|
// Reset printMaxWidth
|
482
480
|
if (handleMaxWidth) {
|
483
481
|
chart.setSize.apply(chart, resetParams);
|
484
|
-
chart.hasUserSize = hasUserSize;
|
485
482
|
}
|
486
483
|
|
487
484
|
fireEvent(chart, 'afterPrint');
|
@@ -109,7 +109,7 @@ seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {
|
|
109
109
|
neckWidth + (width - neckWidth) * (1 - (y - top) / (height - neckHeight));
|
110
110
|
};
|
111
111
|
series.getX = function (y, half) {
|
112
|
-
return centerX + (half ? -1 : 1) * ((getWidthAt(reversed ?
|
112
|
+
return centerX + (half ? -1 : 1) * ((getWidthAt(reversed ? 2 * centerY - y : y) / 2) + options.dataLabels.distance);
|
113
113
|
};
|
114
114
|
|
115
115
|
// Expose
|
@@ -176,9 +176,9 @@ seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {
|
|
176
176
|
}
|
177
177
|
|
178
178
|
if (reversed) {
|
179
|
-
y1 =
|
180
|
-
y3 =
|
181
|
-
y5 = (y5 ?
|
179
|
+
y1 = 2 * centerY - y1;
|
180
|
+
y3 = 2 * centerY - y3;
|
181
|
+
y5 = (y5 ? 2 * centerY - y5 : null);
|
182
182
|
}
|
183
183
|
// save the path
|
184
184
|
path = [
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license Highcharts JS v4.2.
|
2
|
+
* @license Highcharts JS v4.2.6 (2016-08-02)
|
3
3
|
* Client side exporting module
|
4
4
|
*
|
5
5
|
* (c) 2015 Torstein Honsi / Oystein Moseng
|
@@ -18,7 +18,10 @@
|
|
18
18
|
|
19
19
|
var win = Highcharts.win,
|
20
20
|
nav = win.navigator,
|
21
|
-
doc = win.document
|
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
|
22
25
|
|
23
26
|
// Dummy object so we can reuse our canvas-tools.js without errors
|
24
27
|
Highcharts.CanVGRenderer = {};
|
@@ -40,217 +43,216 @@
|
|
40
43
|
head.appendChild(script);
|
41
44
|
}
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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';
|
67
71
|
}
|
68
|
-
}
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
taintedHandler,
|
75
|
-
loadHandler = function () {
|
76
|
-
var canvas = doc.createElement('canvas'),
|
77
|
-
ctx = canvas.getContext && canvas.getContext('2d'),
|
78
|
-
dataURL;
|
79
|
-
try {
|
80
|
-
if (!ctx) {
|
81
|
-
noCanvasSupportCallback(imageURL, imageType, callbackArgs);
|
82
|
-
} else {
|
83
|
-
canvas.height = img.height * scale;
|
84
|
-
canvas.width = img.width * scale;
|
85
|
-
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
72
|
+
} catch (e) {
|
73
|
+
// window.open failed, trying location.href
|
74
|
+
win.location.href = dataURL;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
};
|
86
78
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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);
|
103
119
|
}
|
104
120
|
}
|
105
|
-
}
|
106
|
-
// Image load failed (e.g. invalid URL)
|
107
|
-
errorHandler = function () {
|
108
|
-
failedLoadCallback(imageURL, imageType, callbackArgs);
|
121
|
+
} finally {
|
109
122
|
if (finallyCallback) {
|
110
|
-
finallyCallback(imageURL, imageType, callbackArgs);
|
123
|
+
finallyCallback(imageURL, imageType, callbackArgs, scale);
|
111
124
|
}
|
112
|
-
};
|
113
|
-
|
114
|
-
// This is called on load if the image drawing to canvas failed with a security error.
|
115
|
-
// We retry the drawing with crossOrigin set to Anonymous.
|
116
|
-
taintedHandler = function () {
|
117
|
-
img = new win.Image();
|
118
|
-
taintedHandler = taintedCallback;
|
119
|
-
img.crossOrigin = 'Anonymous'; // Must be set prior to loading image source
|
120
|
-
img.onload = loadHandler;
|
121
|
-
img.onerror = errorHandler;
|
122
|
-
img.src = imageURL;
|
123
|
-
};
|
124
|
-
|
125
|
-
img.onload = loadHandler;
|
126
|
-
img.onerror = errorHandler;
|
127
|
-
img.src = imageURL;
|
128
|
-
},
|
129
|
-
// Get blob URL from SVG code. Falls back to normal data URI.
|
130
|
-
svgToDataUrl = function (svg) {
|
131
|
-
try {
|
132
|
-
// Safari requires data URI since it doesn't allow navigation to blob URLs
|
133
|
-
// Firefox has an issue with Blobs and internal references, leading to gradients not working using Blobs (#4550)
|
134
|
-
if (!webKit && nav.userAgent.toLowerCase().indexOf('firefox') < 0) {
|
135
|
-
return domurl.createObjectURL(new win.Blob([svg], { type: 'image/svg+xml;charset-utf-16' }));
|
136
125
|
}
|
137
|
-
}
|
138
|
-
// Ignore
|
139
|
-
}
|
140
|
-
return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
|
126
|
+
}, loadEventDeferDelay); // IE bug where image is not always ready despite calling load event.
|
141
127
|
},
|
142
|
-
//
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
// IE specific blob implementation
|
149
|
-
if (nav.msSaveOrOpenBlob) {
|
150
|
-
nav.msSaveOrOpenBlob(dataURL, filename);
|
151
|
-
return;
|
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);
|
152
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
|
+
};
|
153
151
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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');
|
162
167
|
} else {
|
163
|
-
|
164
|
-
try {
|
165
|
-
windowRef = win.open(dataURL, 'chart');
|
166
|
-
if (windowRef === undefined || windowRef === null) {
|
167
|
-
throw 'Failed to open window';
|
168
|
-
}
|
169
|
-
} catch (e) {
|
170
|
-
// window.open failed, trying location.href
|
171
|
-
win.location.href = dataURL;
|
172
|
-
}
|
168
|
+
svgurl = Highcharts.svgToDataUrl(svg);
|
173
169
|
}
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
182
179
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
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();
|
197
195
|
}
|
198
|
-
}
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
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);
|
205
208
|
try {
|
206
|
-
|
209
|
+
Highcharts.downloadURL(nav.msSaveOrOpenBlob ? canvas.msToBlob() : canvas.toDataURL(imageType), filename);
|
210
|
+
if (successCallback) {
|
211
|
+
successCallback();
|
212
|
+
}
|
207
213
|
} catch (e) {
|
208
|
-
|
214
|
+
failCallback();
|
215
|
+
} finally {
|
216
|
+
finallyHandler();
|
209
217
|
}
|
210
|
-
}
|
211
|
-
// Failed due to tainted canvas
|
212
|
-
// Create new and untainted canvas
|
213
|
-
var canvas = doc.createElement('canvas'),
|
214
|
-
ctx = canvas.getContext('2d'),
|
215
|
-
imageWidth = svg.match(/^<svg[^>]*width\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
|
216
|
-
imageHeight = svg.match(/^<svg[^>]*height\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
|
217
|
-
downloadWithCanVG = function () {
|
218
|
-
ctx.drawSvg(svg, 0, 0, imageWidth, imageHeight);
|
219
|
-
try {
|
220
|
-
download(nav.msSaveOrOpenBlob ? canvas.msToBlob() : canvas.toDataURL(imageType), imageExtension);
|
221
|
-
} catch (e) {
|
222
|
-
fallbackToExportServer();
|
223
|
-
}
|
224
|
-
};
|
218
|
+
};
|
225
219
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
downloadWithCanVG();
|
237
|
-
});
|
238
|
-
}
|
239
|
-
},
|
240
|
-
// No canvas support
|
241
|
-
fallbackToExportServer,
|
242
|
-
// Failed to load image
|
243
|
-
fallbackToExportServer,
|
244
|
-
// Finally
|
245
|
-
function () {
|
246
|
-
try {
|
247
|
-
domurl.revokeObjectURL(svgurl);
|
248
|
-
} catch (e) {
|
249
|
-
// Ignore
|
250
|
-
}
|
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();
|
251
230
|
});
|
252
231
|
}
|
253
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,
|
254
256
|
// Success handler, we converted image to base64!
|
255
257
|
embeddedSuccess = function (imageURL, imageType, callbackArgs) {
|
256
258
|
++imagesEmbedded;
|
@@ -258,9 +260,9 @@
|
|
258
260
|
// Change image href in chart copy
|
259
261
|
callbackArgs.imageElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', imageURL);
|
260
262
|
|
261
|
-
//
|
263
|
+
// When done with last image we have our SVG
|
262
264
|
if (imagesEmbedded === images.length) {
|
263
|
-
|
265
|
+
successCallback(chart.sanitizeSVG(chartCopyContainer.innerHTML));
|
264
266
|
}
|
265
267
|
};
|
266
268
|
|
@@ -275,27 +277,61 @@
|
|
275
277
|
images = chartCopyContainer.getElementsByTagName('image');
|
276
278
|
|
277
279
|
try {
|
278
|
-
// If there are no images to embed,
|
280
|
+
// If there are no images to embed, the SVG is okay now.
|
279
281
|
if (!images.length) {
|
280
|
-
|
282
|
+
successCallback(chart.sanitizeSVG(chartCopyContainer.innerHTML)); // Use SVG of chart copy
|
283
|
+
return;
|
281
284
|
}
|
282
285
|
|
283
286
|
// Go through the images we want to embed
|
284
287
|
for (i = 0, l = images.length; i < l; ++i) {
|
285
288
|
el = images[i];
|
286
|
-
imageToDataUrl(el.getAttributeNS('http://www.w3.org/1999/xlink', 'href'), 'image/png', { imageElement: el },
|
289
|
+
Highcharts.imageToDataUrl(el.getAttributeNS('http://www.w3.org/1999/xlink', 'href'), 'image/png', { imageElement: el }, options.scale,
|
287
290
|
embeddedSuccess,
|
288
291
|
// Tainted canvas
|
289
|
-
|
290
|
-
// No canvas support
|
291
|
-
|
292
|
+
failCallback,
|
293
|
+
// No canvas support
|
294
|
+
failCallback,
|
292
295
|
// Failed to load source
|
293
|
-
|
296
|
+
failCallback
|
294
297
|
);
|
295
298
|
}
|
296
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
|
+
// docs
|
329
|
+
if (isMSBrowser && imageType !== 'image/svg+xml' && chart.container.getElementsByTagName('image').length) {
|
297
330
|
fallbackToExportServer();
|
331
|
+
return;
|
298
332
|
}
|
333
|
+
|
334
|
+
chart.getSVGForLocalExport(options, chartOptions, fallbackToExportServer, svgSuccess);
|
299
335
|
};
|
300
336
|
|
301
337
|
// Extend the default options to use the local exporter logic
|