highcharts-rails 5.0.14 → 6.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 +60 -0
- data/Rakefile +54 -5
- data/app/assets/images/highcharts/earth.svg +432 -0
- data/app/assets/javascripts/highcharts.js +5103 -3147
- data/app/assets/javascripts/highcharts/highcharts-3d.js +930 -277
- data/app/assets/javascripts/highcharts/highcharts-more.js +1374 -249
- data/app/assets/javascripts/highcharts/lib/canvg.js +3073 -0
- data/app/assets/javascripts/highcharts/lib/jspdf.js +16624 -0
- data/app/assets/javascripts/highcharts/lib/rgbcolor.js +299 -0
- data/app/assets/javascripts/highcharts/lib/svg2pdf.js +3488 -0
- data/app/assets/javascripts/highcharts/modules/accessibility.js +654 -212
- data/app/assets/javascripts/highcharts/modules/annotations.js +1552 -274
- data/app/assets/javascripts/highcharts/modules/boost-canvas.js +773 -0
- data/app/assets/javascripts/highcharts/modules/boost.js +636 -210
- data/app/assets/javascripts/highcharts/modules/broken-axis.js +2 -2
- data/app/assets/javascripts/highcharts/modules/bullet.js +364 -0
- data/app/assets/javascripts/highcharts/modules/data.js +766 -38
- data/app/assets/javascripts/highcharts/modules/drag-panes.js +588 -0
- data/app/assets/javascripts/highcharts/modules/drilldown.js +106 -36
- data/app/assets/javascripts/highcharts/modules/export-data.js +597 -0
- data/app/assets/javascripts/highcharts/modules/exporting.js +424 -162
- data/app/assets/javascripts/highcharts/modules/funnel.js +144 -22
- data/app/assets/javascripts/highcharts/modules/gantt.js +1154 -0
- data/app/assets/javascripts/highcharts/modules/grid-axis.js +1 -1
- data/app/assets/javascripts/highcharts/modules/heatmap.js +406 -80
- data/app/assets/javascripts/highcharts/modules/histogram-bellcurve.js +513 -0
- data/app/assets/javascripts/highcharts/modules/item-series.js +126 -0
- data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +31 -13
- data/app/assets/javascripts/highcharts/modules/offline-exporting.js +179 -57
- data/app/assets/javascripts/highcharts/modules/oldie.js +1378 -0
- data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +8 -6
- data/app/assets/javascripts/highcharts/modules/parallel-coordinates.js +494 -0
- data/app/assets/javascripts/highcharts/modules/pareto.js +275 -0
- data/app/assets/javascripts/highcharts/modules/sankey.js +641 -0
- data/app/assets/javascripts/highcharts/modules/series-label.js +355 -145
- data/app/assets/javascripts/highcharts/modules/solid-gauge.js +122 -1
- data/app/assets/javascripts/highcharts/modules/static-scale.js +64 -0
- data/app/assets/javascripts/highcharts/modules/stock.js +1944 -676
- data/app/assets/javascripts/highcharts/modules/streamgraph.js +139 -0
- data/app/assets/javascripts/highcharts/modules/sunburst.js +2403 -0
- data/app/assets/javascripts/highcharts/modules/tilemap.js +1199 -0
- data/app/assets/javascripts/highcharts/modules/treemap.js +538 -134
- data/app/assets/javascripts/highcharts/modules/variable-pie.js +490 -0
- data/app/assets/javascripts/highcharts/modules/variwide.js +283 -0
- data/app/assets/javascripts/highcharts/modules/vector.js +294 -0
- data/app/assets/javascripts/highcharts/modules/windbarb.js +490 -0
- data/app/assets/javascripts/highcharts/modules/wordcloud.js +681 -0
- data/app/assets/javascripts/highcharts/modules/xrange.js +615 -0
- data/app/assets/javascripts/highcharts/themes/avocado.js +54 -0
- data/app/assets/javascripts/highcharts/themes/dark-blue.js +6 -6
- data/app/assets/javascripts/highcharts/themes/dark-green.js +6 -6
- data/app/assets/javascripts/highcharts/themes/dark-unica.js +6 -6
- data/app/assets/javascripts/highcharts/themes/gray.js +14 -10
- data/app/assets/javascripts/highcharts/themes/grid-light.js +6 -6
- data/app/assets/javascripts/highcharts/themes/grid.js +7 -5
- data/app/assets/javascripts/highcharts/themes/sand-signika.js +8 -7
- data/app/assets/javascripts/highcharts/themes/skies.js +15 -9
- data/app/assets/javascripts/highcharts/themes/sunset.js +53 -0
- data/app/assets/stylesheets/highcharts/highcharts.css +802 -0
- data/app/assets/stylesheets/highcharts/highcharts.scss +665 -0
- data/lib/highcharts/version.rb +1 -1
- metadata +31 -1
@@ -0,0 +1,275 @@
|
|
1
|
+
/**
|
2
|
+
* @license Highcharts JS v6.0.0 (2017-10-04)
|
3
|
+
*
|
4
|
+
* Pareto series type for Highcharts
|
5
|
+
*
|
6
|
+
* (c) 2010-2017 Sebastian Bochan
|
7
|
+
*
|
8
|
+
* License: www.highcharts.com/license
|
9
|
+
*/
|
10
|
+
'use strict';
|
11
|
+
(function(factory) {
|
12
|
+
if (typeof module === 'object' && module.exports) {
|
13
|
+
module.exports = factory;
|
14
|
+
} else {
|
15
|
+
factory(Highcharts);
|
16
|
+
}
|
17
|
+
}(function(Highcharts) {
|
18
|
+
var derivedSeriesMixin = (function(H) {
|
19
|
+
|
20
|
+
var each = H.each,
|
21
|
+
Series = H.Series,
|
22
|
+
addEvent = H.addEvent,
|
23
|
+
fireEvent = H.fireEvent,
|
24
|
+
wrap = H.wrap,
|
25
|
+
noop = H.noop;
|
26
|
+
|
27
|
+
|
28
|
+
/* ***************************************************************************
|
29
|
+
*
|
30
|
+
* DERIVED SERIES MIXIN
|
31
|
+
*
|
32
|
+
**************************************************************************** */
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Provides methods for auto setting/updating series data based on the based series data,
|
36
|
+
*
|
37
|
+
* @mixin
|
38
|
+
**/
|
39
|
+
var derivedSeriesMixin = {
|
40
|
+
/**
|
41
|
+
* Initialise series
|
42
|
+
*
|
43
|
+
* returns {undefined}
|
44
|
+
**/
|
45
|
+
init: function() {
|
46
|
+
Series.prototype.init.apply(this, arguments);
|
47
|
+
|
48
|
+
this.initialised = false;
|
49
|
+
this.baseSeries = null;
|
50
|
+
this.eventRemovers = [];
|
51
|
+
|
52
|
+
this.addEvents();
|
53
|
+
},
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Method to be implemented - inside the method the series has already access to the base series
|
57
|
+
* via m `this.baseSeries` and the bases data is initialised. It should
|
58
|
+
* return data in the format accepted by Series.setData() method
|
59
|
+
*
|
60
|
+
* @returns {Array} - an array of data
|
61
|
+
**/
|
62
|
+
setDerivedData: noop,
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Sets base series for the series
|
66
|
+
*
|
67
|
+
* returns {undefined}
|
68
|
+
**/
|
69
|
+
setBaseSeries: function() {
|
70
|
+
var chart = this.chart,
|
71
|
+
baseSeriesOptions = this.options.baseSeries,
|
72
|
+
baseSeries =
|
73
|
+
baseSeriesOptions &&
|
74
|
+
(chart.series[baseSeriesOptions] || chart.get(baseSeriesOptions));
|
75
|
+
|
76
|
+
this.baseSeries = baseSeries || null;
|
77
|
+
},
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Adds events for the series
|
81
|
+
*
|
82
|
+
* @returns {undefined}
|
83
|
+
**/
|
84
|
+
addEvents: function() {
|
85
|
+
var derivedSeries = this,
|
86
|
+
chartSeriesLinked;
|
87
|
+
|
88
|
+
chartSeriesLinked = addEvent(this.chart, 'seriesLinked', function() {
|
89
|
+
derivedSeries.setBaseSeries();
|
90
|
+
|
91
|
+
if (derivedSeries.baseSeries && !derivedSeries.initialised) {
|
92
|
+
derivedSeries.setDerivedData();
|
93
|
+
derivedSeries.addBaseSeriesEvents();
|
94
|
+
derivedSeries.initialised = true;
|
95
|
+
}
|
96
|
+
});
|
97
|
+
|
98
|
+
this.eventRemovers.push(
|
99
|
+
chartSeriesLinked
|
100
|
+
);
|
101
|
+
},
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Adds events to the base series - it required for recalculating the data in
|
105
|
+
* the series if the base series is updated / removed / etc.
|
106
|
+
*
|
107
|
+
* @returns {undefined}
|
108
|
+
**/
|
109
|
+
addBaseSeriesEvents: function() {
|
110
|
+
var derivedSeries = this,
|
111
|
+
updatedDataRemover,
|
112
|
+
destroyRemover;
|
113
|
+
|
114
|
+
updatedDataRemover = addEvent(derivedSeries.baseSeries, 'updatedData', function() {
|
115
|
+
derivedSeries.setDerivedData();
|
116
|
+
});
|
117
|
+
|
118
|
+
destroyRemover = addEvent(derivedSeries.baseSeries, 'destroy', function() {
|
119
|
+
derivedSeries.baseSeries = null;
|
120
|
+
derivedSeries.initialised = false;
|
121
|
+
});
|
122
|
+
|
123
|
+
derivedSeries.eventRemovers.push(
|
124
|
+
updatedDataRemover,
|
125
|
+
destroyRemover
|
126
|
+
);
|
127
|
+
},
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Destroys the series
|
131
|
+
*
|
132
|
+
* @returns {undefined}
|
133
|
+
**/
|
134
|
+
destroy: function() {
|
135
|
+
each(this.eventRemovers, function(remover) {
|
136
|
+
remover();
|
137
|
+
});
|
138
|
+
|
139
|
+
Series.prototype.destroy.apply(this, arguments);
|
140
|
+
}
|
141
|
+
};
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Adds a new chart event after the series are linked
|
145
|
+
**/
|
146
|
+
wrap(H.Chart.prototype, 'linkSeries', function(p) {
|
147
|
+
p.call(this);
|
148
|
+
|
149
|
+
fireEvent(this, 'seriesLinked');
|
150
|
+
});
|
151
|
+
return derivedSeriesMixin;
|
152
|
+
}(Highcharts));
|
153
|
+
(function(H, derivedSeriesMixin) {
|
154
|
+
/**
|
155
|
+
* (c) 2010-2017 Sebastian Bochan
|
156
|
+
*
|
157
|
+
* License: www.highcharts.com/license
|
158
|
+
*/
|
159
|
+
|
160
|
+
|
161
|
+
var each = H.each,
|
162
|
+
correctFloat = H.correctFloat,
|
163
|
+
seriesType = H.seriesType,
|
164
|
+
merge = H.merge;
|
165
|
+
|
166
|
+
|
167
|
+
/**
|
168
|
+
* The pareto series type.
|
169
|
+
*
|
170
|
+
* @constructor seriesTypes.pareto
|
171
|
+
* @augments seriesTypes.line
|
172
|
+
*/
|
173
|
+
|
174
|
+
/**
|
175
|
+
* A pareto diagram is a type of chart that contains both bars and a line graph,
|
176
|
+
* where individual values are represented in descending order by bars,
|
177
|
+
* and the cumulative total is represented by the line.
|
178
|
+
*
|
179
|
+
* @extends {plotOptions.line}
|
180
|
+
* @product highcharts
|
181
|
+
* @sample {highcharts} highcharts/demo/pareto/
|
182
|
+
* Pareto diagram
|
183
|
+
* @since 6.0.0
|
184
|
+
* @excluding allAreas,boostThreshold,borderColor,borderRadius,
|
185
|
+
* borderWidth,crisp,colorAxis,depth,data,edgeColor,edgeWidth,
|
186
|
+
* findNearestPointBy,gapSize,gapUnit,grouping,groupPadding,groupZPadding,maxPointWidth,
|
187
|
+
* keys,negativeColor,pointInterval,pointIntervalUnit,pointPadding,
|
188
|
+
* pointPlacement,pointRange,pointStart,pointWidth,shadow,step,softThreshold,
|
189
|
+
* stacking,threshold,zoneAxis,zones
|
190
|
+
* @optionparent plotOptions.pareto
|
191
|
+
*/
|
192
|
+
|
193
|
+
seriesType('pareto', 'line', {
|
194
|
+
/**
|
195
|
+
* Higher zIndex than column series to draw line above shapes.
|
196
|
+
*/
|
197
|
+
zIndex: 3
|
198
|
+
}, merge(derivedSeriesMixin, {
|
199
|
+
/**
|
200
|
+
* calculate sum and return percent points
|
201
|
+
*
|
202
|
+
* @param {Object} series
|
203
|
+
* @return {Array} Returns array of points [x,y]
|
204
|
+
*/
|
205
|
+
setDerivedData: function() {
|
206
|
+
if (this.baseSeries.yData.length > 1) {
|
207
|
+
var xValues = this.baseSeries.xData,
|
208
|
+
yValues = this.baseSeries.yData,
|
209
|
+
sum = this.sumPointsPercents(yValues, xValues, null, true);
|
210
|
+
|
211
|
+
this.setData(this.sumPointsPercents(yValues, xValues, sum, false), false);
|
212
|
+
}
|
213
|
+
},
|
214
|
+
/**
|
215
|
+
* calculate y sum and each percent point
|
216
|
+
*
|
217
|
+
* @param {Array} yValues y values
|
218
|
+
* @param {Array} xValues x values
|
219
|
+
* @param {Number} sum of all y values
|
220
|
+
* @param {Boolean} isSum declares if calculate sum of all points
|
221
|
+
* @return {Array} Returns sum of points or array of points [x,y]
|
222
|
+
*/
|
223
|
+
sumPointsPercents: function(yValues, xValues, sum, isSum) {
|
224
|
+
var sumY = 0,
|
225
|
+
sumPercent = 0,
|
226
|
+
percentPoints = [],
|
227
|
+
percentPoint;
|
228
|
+
|
229
|
+
each(yValues, function(point, i) {
|
230
|
+
if (point !== null) {
|
231
|
+
if (isSum) {
|
232
|
+
sumY += point;
|
233
|
+
} else {
|
234
|
+
percentPoint = (point / sum) * 100;
|
235
|
+
percentPoints.push([xValues[i], correctFloat(sumPercent + percentPoint)]);
|
236
|
+
sumPercent += percentPoint;
|
237
|
+
}
|
238
|
+
}
|
239
|
+
});
|
240
|
+
|
241
|
+
return isSum ? sumY : percentPoints;
|
242
|
+
}
|
243
|
+
}));
|
244
|
+
|
245
|
+
/**
|
246
|
+
* A `pareto` series. If the [type](#series.pareto.type) option is not
|
247
|
+
* specified, it is inherited from [chart.type](#chart.type).
|
248
|
+
*
|
249
|
+
* For options that apply to multiple series, it is recommended to add
|
250
|
+
* them to the [plotOptions.series](#plotOptions.series) options structure.
|
251
|
+
* To apply to all series of this specific type, apply it to [plotOptions.
|
252
|
+
* pareto](#plotOptions.pareto).
|
253
|
+
*
|
254
|
+
* @type {Object}
|
255
|
+
* @since 6.0.0
|
256
|
+
* @extends series,plotOptions.pareto
|
257
|
+
* @excluding data,dataParser,dataURL
|
258
|
+
* @product highcharts
|
259
|
+
* @apioption series.pareto
|
260
|
+
*/
|
261
|
+
|
262
|
+
|
263
|
+
/**
|
264
|
+
* An array of data points for the series. For the `pareto` series type,
|
265
|
+
* points are calculated dynamically.
|
266
|
+
*
|
267
|
+
* @type {Array<Object|Array>}
|
268
|
+
* @since 6.0.0
|
269
|
+
* @extends series.column.data
|
270
|
+
* @product highcharts
|
271
|
+
* @apioption series.pareto.data
|
272
|
+
*/
|
273
|
+
|
274
|
+
}(Highcharts, derivedSeriesMixin));
|
275
|
+
}));
|
@@ -0,0 +1,641 @@
|
|
1
|
+
/**
|
2
|
+
* @license Highcharts JS v6.0.0 (2017-10-04)
|
3
|
+
* Sankey diagram module
|
4
|
+
*
|
5
|
+
* (c) 2010-2017 Torstein Honsi
|
6
|
+
*
|
7
|
+
* License: www.highcharts.com/license
|
8
|
+
*/
|
9
|
+
'use strict';
|
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
|
+
* Solid angular gauge module
|
20
|
+
*
|
21
|
+
* (c) 2010-2017 Torstein Honsi
|
22
|
+
*
|
23
|
+
* License: www.highcharts.com/license
|
24
|
+
*/
|
25
|
+
|
26
|
+
|
27
|
+
var defined = H.defined,
|
28
|
+
each = H.each,
|
29
|
+
extend = H.extend,
|
30
|
+
seriesType = H.seriesType,
|
31
|
+
pick = H.pick,
|
32
|
+
Point = H.Point;
|
33
|
+
|
34
|
+
/**
|
35
|
+
* A sankey diagram is a type of flow diagram, in which the width of the
|
36
|
+
* link between two nodes is shown proportionally to the flow quantity.
|
37
|
+
*
|
38
|
+
* @extends {plotOptions.column}
|
39
|
+
* @product highcharts
|
40
|
+
* @sample highcharts/demo/sankey-diagram/
|
41
|
+
* Sankey diagram
|
42
|
+
* @sample highcharts/plotoptions/sankey-inverted/
|
43
|
+
* Inverted sankey diagram
|
44
|
+
* @sample highcharts/plotoptions/sankey-outgoing
|
45
|
+
* Sankey diagram with outgoing links
|
46
|
+
* @since 6.0.0
|
47
|
+
* @excluding animationLimit,boostThreshold,borderColor,borderRadius,
|
48
|
+
* borderWidth,crisp,cropThreshold,depth,edgeColor,edgeWidth,
|
49
|
+
* findNearestPointBy,grouping,groupPadding,groupZPadding,maxPointWidth,
|
50
|
+
* negativeColor,pointInterval,pointIntervalUnit,pointPadding,
|
51
|
+
* pointPlacement,pointRange,pointStart,pointWidth,shadow,softThreshold,
|
52
|
+
* stacking,threshold,zoneAxis,zones
|
53
|
+
* @optionparent plotOptions.sankey
|
54
|
+
*/
|
55
|
+
seriesType('sankey', 'column', {
|
56
|
+
colorByPoint: true,
|
57
|
+
/**
|
58
|
+
* Higher numbers makes the links in a sankey diagram render more curved.
|
59
|
+
* A `curveFactor` of 0 makes the lines straight.
|
60
|
+
*/
|
61
|
+
curveFactor: 0.33,
|
62
|
+
/**
|
63
|
+
* Options for the data labels appearing on top of the nodes and links. For
|
64
|
+
* sankey charts, data labels are visible for the nodes by default, but
|
65
|
+
* hidden for links. This is controlled by modifying the `nodeFormat`, and
|
66
|
+
* the `format` that applies to links and is an empty string by default.
|
67
|
+
*/
|
68
|
+
dataLabels: {
|
69
|
+
enabled: true,
|
70
|
+
backgroundColor: 'none', // enable padding
|
71
|
+
crop: false,
|
72
|
+
/**
|
73
|
+
* The [format string](http://www.highcharts.com/docs/chart-concepts/labels-
|
74
|
+
* and-string-formatting) specifying what to show for _nodes_ in the
|
75
|
+
* sankey diagram.
|
76
|
+
*/
|
77
|
+
nodeFormat: '{point.name}',
|
78
|
+
/**
|
79
|
+
* The [format string](http://www.highcharts.com/docs/chart-concepts/labels-
|
80
|
+
* and-string-formatting) specifying what to show for _links_ in the
|
81
|
+
* sankey diagram. Defaults to an empty string, in effect disabling the
|
82
|
+
* labels.
|
83
|
+
* @default ""
|
84
|
+
*/
|
85
|
+
format: '',
|
86
|
+
inside: true
|
87
|
+
},
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Opacity for the links between nodes in the sankey diagram.
|
91
|
+
*/
|
92
|
+
linkOpacity: 0.5,
|
93
|
+
|
94
|
+
/**
|
95
|
+
* The pixel width of each node in a sankey diagram, or the height in case
|
96
|
+
* the chart is inverted.
|
97
|
+
*/
|
98
|
+
nodeWidth: 20,
|
99
|
+
/**
|
100
|
+
* The padding between nodes in a sankey diagram, in pixels.
|
101
|
+
*/
|
102
|
+
nodePadding: 10,
|
103
|
+
showInLegend: false,
|
104
|
+
states: {
|
105
|
+
hover: {
|
106
|
+
/**
|
107
|
+
* Opacity for the links between nodes in the sankey diagram in
|
108
|
+
* hover mode.
|
109
|
+
*/
|
110
|
+
linkOpacity: 1
|
111
|
+
}
|
112
|
+
},
|
113
|
+
tooltip: {
|
114
|
+
followPointer: true,
|
115
|
+
|
116
|
+
|
117
|
+
headerFormat: '<span style="font-size: 0.85em">{series.name}</span><br/>',
|
118
|
+
|
119
|
+
pointFormat: '{point.fromNode.name} \u2192 {point.toNode.name}: <b>{point.weight}</b><br/>',
|
120
|
+
/**
|
121
|
+
* The [format string](http://www.highcharts.com/docs/chart-concepts/labels-
|
122
|
+
* and-string-formatting) specifying what to show for _nodes_ in tooltip
|
123
|
+
* of a sankey diagram series.
|
124
|
+
*/
|
125
|
+
nodeFormat: '{point.name}: <b>{point.sum}</b><br/>'
|
126
|
+
}
|
127
|
+
|
128
|
+
}, {
|
129
|
+
isCartesian: false,
|
130
|
+
forceDL: true,
|
131
|
+
/**
|
132
|
+
* Create a single node that holds information on incoming and outgoing
|
133
|
+
* links.
|
134
|
+
*/
|
135
|
+
createNode: function(id) {
|
136
|
+
|
137
|
+
function findById(nodes, id) {
|
138
|
+
return H.find(nodes, function(node) {
|
139
|
+
return node.id === id;
|
140
|
+
});
|
141
|
+
}
|
142
|
+
|
143
|
+
var node = findById(this.nodes, id),
|
144
|
+
options;
|
145
|
+
|
146
|
+
if (!node) {
|
147
|
+
options = this.options.nodes && findById(this.options.nodes, id);
|
148
|
+
node = (new Point()).init(
|
149
|
+
this,
|
150
|
+
extend({
|
151
|
+
className: 'highcharts-node',
|
152
|
+
isNode: true,
|
153
|
+
id: id,
|
154
|
+
y: 1 // Pass isNull test
|
155
|
+
}, options)
|
156
|
+
);
|
157
|
+
node.linksTo = [];
|
158
|
+
node.linksFrom = [];
|
159
|
+
node.formatPrefix = 'node';
|
160
|
+
node.name = node.name || node.id; // for use in formats
|
161
|
+
|
162
|
+
/**
|
163
|
+
* Return the largest sum of either the incoming or outgoing links.
|
164
|
+
*/
|
165
|
+
node.getSum = function() {
|
166
|
+
var sumTo = 0,
|
167
|
+
sumFrom = 0;
|
168
|
+
each(node.linksTo, function(link) {
|
169
|
+
sumTo += link.weight;
|
170
|
+
});
|
171
|
+
each(node.linksFrom, function(link) {
|
172
|
+
sumFrom += link.weight;
|
173
|
+
});
|
174
|
+
return Math.max(sumTo, sumFrom);
|
175
|
+
};
|
176
|
+
/**
|
177
|
+
* Get the offset in weight values of a point/link.
|
178
|
+
*/
|
179
|
+
node.offset = function(point, coll) {
|
180
|
+
var offset = 0;
|
181
|
+
for (var i = 0; i < node[coll].length; i++) {
|
182
|
+
if (node[coll][i] === point) {
|
183
|
+
return offset;
|
184
|
+
}
|
185
|
+
offset += node[coll][i].weight;
|
186
|
+
}
|
187
|
+
};
|
188
|
+
|
189
|
+
/**
|
190
|
+
* Return true if the node has a shape, otherwise all links are
|
191
|
+
* outgoing.
|
192
|
+
*/
|
193
|
+
node.hasShape = function() {
|
194
|
+
var outgoing = 0;
|
195
|
+
each(node.linksTo, function(link) {
|
196
|
+
if (link.outgoing) {
|
197
|
+
outgoing++;
|
198
|
+
}
|
199
|
+
});
|
200
|
+
return !node.linksTo.length || outgoing !== node.linksTo.length;
|
201
|
+
};
|
202
|
+
|
203
|
+
this.nodes.push(node);
|
204
|
+
}
|
205
|
+
return node;
|
206
|
+
},
|
207
|
+
|
208
|
+
/**
|
209
|
+
* Create a node column.
|
210
|
+
*/
|
211
|
+
createNodeColumn: function() {
|
212
|
+
var chart = this.chart,
|
213
|
+
column = [],
|
214
|
+
nodePadding = this.options.nodePadding;
|
215
|
+
|
216
|
+
column.sum = function() {
|
217
|
+
var sum = 0;
|
218
|
+
each(this, function(node) {
|
219
|
+
sum += node.getSum();
|
220
|
+
});
|
221
|
+
return sum;
|
222
|
+
};
|
223
|
+
/**
|
224
|
+
* Get the offset in pixels of a node inside the column.
|
225
|
+
*/
|
226
|
+
column.offset = function(node, factor) {
|
227
|
+
var offset = 0;
|
228
|
+
for (var i = 0; i < column.length; i++) {
|
229
|
+
if (column[i] === node) {
|
230
|
+
return offset;
|
231
|
+
}
|
232
|
+
offset += column[i].getSum() * factor + nodePadding;
|
233
|
+
}
|
234
|
+
};
|
235
|
+
|
236
|
+
/**
|
237
|
+
* Get the column height in pixels.
|
238
|
+
*/
|
239
|
+
column.top = function(factor) {
|
240
|
+
var height = 0;
|
241
|
+
for (var i = 0; i < column.length; i++) {
|
242
|
+
if (i > 0) {
|
243
|
+
height += nodePadding;
|
244
|
+
}
|
245
|
+
height += column[i].getSum() * factor;
|
246
|
+
}
|
247
|
+
return (chart.plotSizeY - height) / 2;
|
248
|
+
};
|
249
|
+
|
250
|
+
return column;
|
251
|
+
},
|
252
|
+
|
253
|
+
/**
|
254
|
+
* Create node columns by analyzing the nodes and the relations between
|
255
|
+
* incoming and outgoing links.
|
256
|
+
*/
|
257
|
+
createNodeColumns: function() {
|
258
|
+
var columns = [];
|
259
|
+
each(this.nodes, function(node) {
|
260
|
+
var fromColumn = 0,
|
261
|
+
i,
|
262
|
+
point;
|
263
|
+
|
264
|
+
// No links to this node, place it left
|
265
|
+
if (node.linksTo.length === 0) {
|
266
|
+
node.column = 0;
|
267
|
+
|
268
|
+
// There are incoming links, place it to the right of the
|
269
|
+
// highest order column that links to this one.
|
270
|
+
} else {
|
271
|
+
for (i = 0; i < node.linksTo.length; i++) {
|
272
|
+
point = node.linksTo[0];
|
273
|
+
if (point.fromNode.column > fromColumn) {
|
274
|
+
fromColumn = point.fromNode.column;
|
275
|
+
}
|
276
|
+
}
|
277
|
+
node.column = fromColumn + 1;
|
278
|
+
}
|
279
|
+
|
280
|
+
if (!columns[node.column]) {
|
281
|
+
columns[node.column] = this.createNodeColumn();
|
282
|
+
}
|
283
|
+
|
284
|
+
columns[node.column].push(node);
|
285
|
+
|
286
|
+
}, this);
|
287
|
+
return columns;
|
288
|
+
},
|
289
|
+
|
290
|
+
|
291
|
+
/**
|
292
|
+
* Return the presentational attributes.
|
293
|
+
*/
|
294
|
+
pointAttribs: function(point, state) {
|
295
|
+
|
296
|
+
var opacity = this.options.linkOpacity;
|
297
|
+
|
298
|
+
if (state) {
|
299
|
+
opacity = this.options.states[state].linkOpacity || opacity;
|
300
|
+
}
|
301
|
+
|
302
|
+
return {
|
303
|
+
fill: point.isNode ?
|
304
|
+
point.color : H.color(point.color).setOpacity(opacity).get()
|
305
|
+
};
|
306
|
+
},
|
307
|
+
|
308
|
+
|
309
|
+
/**
|
310
|
+
* Extend generatePoints by adding the nodes, which are Point objects
|
311
|
+
* but pushed to the this.nodes array.
|
312
|
+
*/
|
313
|
+
generatePoints: function() {
|
314
|
+
|
315
|
+
var nodeLookup = {};
|
316
|
+
|
317
|
+
H.Series.prototype.generatePoints.call(this);
|
318
|
+
|
319
|
+
if (!this.nodes) {
|
320
|
+
this.nodes = []; // List of Point-like node items
|
321
|
+
}
|
322
|
+
this.colorCounter = 0;
|
323
|
+
|
324
|
+
// Reset links from previous run
|
325
|
+
each(this.nodes, function(node) {
|
326
|
+
node.linksFrom.length = 0;
|
327
|
+
node.linksTo.length = 0;
|
328
|
+
});
|
329
|
+
|
330
|
+
// Create the node list and set up links
|
331
|
+
each(this.points, function(point) {
|
332
|
+
if (defined(point.from)) {
|
333
|
+
if (!nodeLookup[point.from]) {
|
334
|
+
nodeLookup[point.from] = this.createNode(point.from);
|
335
|
+
}
|
336
|
+
nodeLookup[point.from].linksFrom.push(point);
|
337
|
+
point.fromNode = nodeLookup[point.from];
|
338
|
+
|
339
|
+
// Point color defaults to the fromNode's color
|
340
|
+
|
341
|
+
point.color =
|
342
|
+
point.options.color || nodeLookup[point.from].color;
|
343
|
+
|
344
|
+
|
345
|
+
}
|
346
|
+
if (defined(point.to)) {
|
347
|
+
if (!nodeLookup[point.to]) {
|
348
|
+
nodeLookup[point.to] = this.createNode(point.to);
|
349
|
+
}
|
350
|
+
nodeLookup[point.to].linksTo.push(point);
|
351
|
+
point.toNode = nodeLookup[point.to];
|
352
|
+
}
|
353
|
+
|
354
|
+
point.name = point.name || point.id; // for use in formats
|
355
|
+
|
356
|
+
}, this);
|
357
|
+
},
|
358
|
+
|
359
|
+
/**
|
360
|
+
* Run pre-translation by generating the nodeColumns.
|
361
|
+
*/
|
362
|
+
translate: function() {
|
363
|
+
if (!this.processedXData) {
|
364
|
+
this.processData();
|
365
|
+
}
|
366
|
+
this.generatePoints();
|
367
|
+
|
368
|
+
this.nodeColumns = this.createNodeColumns();
|
369
|
+
|
370
|
+
var chart = this.chart,
|
371
|
+
inverted = chart.inverted,
|
372
|
+
options = this.options,
|
373
|
+
left = 0,
|
374
|
+
nodeWidth = options.nodeWidth,
|
375
|
+
nodeColumns = this.nodeColumns,
|
376
|
+
colDistance = (chart.plotSizeX - nodeWidth) /
|
377
|
+
(nodeColumns.length - 1),
|
378
|
+
curvy = (
|
379
|
+
(inverted ? -colDistance : colDistance) *
|
380
|
+
options.curveFactor
|
381
|
+
),
|
382
|
+
factor = Infinity;
|
383
|
+
|
384
|
+
// Find out how much space is needed. Base it on the translation
|
385
|
+
// factor of the most spaceous column.
|
386
|
+
each(this.nodeColumns, function(column) {
|
387
|
+
var height = chart.plotSizeY -
|
388
|
+
(column.length - 1) * options.nodePadding;
|
389
|
+
|
390
|
+
factor = Math.min(factor, height / column.sum());
|
391
|
+
});
|
392
|
+
|
393
|
+
each(this.nodeColumns, function(column) {
|
394
|
+
each(column, function(node) {
|
395
|
+
var sum = node.getSum(),
|
396
|
+
height = sum * factor,
|
397
|
+
fromNodeTop = (
|
398
|
+
column.top(factor) +
|
399
|
+
column.offset(node, factor)
|
400
|
+
),
|
401
|
+
nodeLeft = inverted ?
|
402
|
+
chart.plotSizeX - left :
|
403
|
+
left;
|
404
|
+
|
405
|
+
node.sum = sum;
|
406
|
+
|
407
|
+
// Draw the node
|
408
|
+
node.shapeType = 'rect';
|
409
|
+
if (!inverted) {
|
410
|
+
node.shapeArgs = {
|
411
|
+
x: nodeLeft,
|
412
|
+
y: fromNodeTop,
|
413
|
+
width: nodeWidth,
|
414
|
+
height: height
|
415
|
+
};
|
416
|
+
} else {
|
417
|
+
node.shapeArgs = {
|
418
|
+
x: nodeLeft - nodeWidth,
|
419
|
+
y: chart.plotSizeY - fromNodeTop - height,
|
420
|
+
width: nodeWidth,
|
421
|
+
height: height
|
422
|
+
};
|
423
|
+
}
|
424
|
+
node.shapeArgs.display = node.hasShape() ? '' : 'none';
|
425
|
+
|
426
|
+
// Pass test in drawPoints
|
427
|
+
node.plotY = 1;
|
428
|
+
|
429
|
+
// Draw the links from this node
|
430
|
+
each(node.linksFrom, function(point) {
|
431
|
+
var linkHeight = point.weight * factor,
|
432
|
+
fromLinkTop = node.offset(point, 'linksFrom') *
|
433
|
+
factor,
|
434
|
+
fromY = fromNodeTop + fromLinkTop,
|
435
|
+
toNode = point.toNode,
|
436
|
+
toColTop = nodeColumns[toNode.column].top(factor),
|
437
|
+
toY = (
|
438
|
+
toColTop +
|
439
|
+
(toNode.offset(point, 'linksTo') * factor) +
|
440
|
+
nodeColumns[toNode.column].offset(
|
441
|
+
toNode,
|
442
|
+
factor
|
443
|
+
)
|
444
|
+
),
|
445
|
+
nodeW = nodeWidth,
|
446
|
+
right = toNode.column * colDistance,
|
447
|
+
outgoing = point.outgoing;
|
448
|
+
|
449
|
+
if (inverted) {
|
450
|
+
fromY = chart.plotSizeY - fromY;
|
451
|
+
toY = chart.plotSizeY - toY;
|
452
|
+
right = chart.plotSizeX - right;
|
453
|
+
nodeW = -nodeW;
|
454
|
+
linkHeight = -linkHeight;
|
455
|
+
}
|
456
|
+
|
457
|
+
point.shapeType = 'path';
|
458
|
+
point.shapeArgs = {
|
459
|
+
d: [
|
460
|
+
'M', nodeLeft + nodeW, fromY,
|
461
|
+
'C', nodeLeft + nodeW + curvy, fromY,
|
462
|
+
right - curvy, toY,
|
463
|
+
right, toY,
|
464
|
+
'L',
|
465
|
+
right + (outgoing ? nodeW : 0),
|
466
|
+
toY + linkHeight / 2,
|
467
|
+
'L',
|
468
|
+
right,
|
469
|
+
toY + linkHeight,
|
470
|
+
'C', right - curvy, toY + linkHeight,
|
471
|
+
nodeLeft + nodeW + curvy, fromY + linkHeight,
|
472
|
+
nodeLeft + nodeW, fromY + linkHeight,
|
473
|
+
'z'
|
474
|
+
]
|
475
|
+
};
|
476
|
+
|
477
|
+
// Place data labels in the middle
|
478
|
+
point.dlBox = {
|
479
|
+
x: nodeLeft + (right - nodeLeft + nodeW) / 2,
|
480
|
+
y: fromY + (toY - fromY) / 2,
|
481
|
+
height: linkHeight,
|
482
|
+
width: 0
|
483
|
+
};
|
484
|
+
// Pass test in drawPoints
|
485
|
+
point.y = point.plotY = 1;
|
486
|
+
|
487
|
+
if (!point.color) {
|
488
|
+
point.color = node.color;
|
489
|
+
}
|
490
|
+
});
|
491
|
+
});
|
492
|
+
left += colDistance;
|
493
|
+
|
494
|
+
}, this);
|
495
|
+
},
|
496
|
+
/**
|
497
|
+
* Extend the render function to also render this.nodes together with
|
498
|
+
* the points.
|
499
|
+
*/
|
500
|
+
render: function() {
|
501
|
+
var points = this.points;
|
502
|
+
this.points = this.points.concat(this.nodes);
|
503
|
+
H.seriesTypes.column.prototype.render.call(this);
|
504
|
+
this.points = points;
|
505
|
+
},
|
506
|
+
animate: H.Series.prototype.animate
|
507
|
+
}, {
|
508
|
+
getClassName: function() {
|
509
|
+
return 'highcharts-link ' + Point.prototype.getClassName.call(this);
|
510
|
+
},
|
511
|
+
isValid: function() {
|
512
|
+
return this.isNode || typeof this.weight === 'number';
|
513
|
+
}
|
514
|
+
});
|
515
|
+
|
516
|
+
|
517
|
+
/**
|
518
|
+
* A `sankey` series. If the [type](#series.sankey.type) option is not
|
519
|
+
* specified, it is inherited from [chart.type](#chart.type).
|
520
|
+
*
|
521
|
+
* For options that apply to multiple series, it is recommended to add
|
522
|
+
* them to the [plotOptions.series](#plotOptions.series) options structure.
|
523
|
+
* To apply to all series of this specific type, apply it to [plotOptions.
|
524
|
+
* sankey](#plotOptions.sankey).
|
525
|
+
*
|
526
|
+
* @type {Object}
|
527
|
+
* @extends series,plotOptions.sankey
|
528
|
+
* @excluding dataParser,dataURL
|
529
|
+
* @product highcharts
|
530
|
+
* @apioption series.sankey
|
531
|
+
*/
|
532
|
+
|
533
|
+
|
534
|
+
/**
|
535
|
+
* A collection of options for the individual nodes. The nodes in a sankey
|
536
|
+
* diagram are auto-generated instances of `Highcharts.Point`, but options can
|
537
|
+
* be applied here and linked by the `id`.
|
538
|
+
*
|
539
|
+
* @sample highcharts/css/sankey/ Sankey diagram with node options
|
540
|
+
* @type {Array.<Object>}
|
541
|
+
* @product highcharts
|
542
|
+
* @apioption series.sankey.nodes
|
543
|
+
*/
|
544
|
+
|
545
|
+
/**
|
546
|
+
* The id of the auto-generated node, refering to the `from` or `to` setting of
|
547
|
+
* the link.
|
548
|
+
*
|
549
|
+
* @type {String}
|
550
|
+
* @product highcharts
|
551
|
+
* @apioption series.sankey.nodes.id
|
552
|
+
*/
|
553
|
+
|
554
|
+
/**
|
555
|
+
* The color of the auto generated node.
|
556
|
+
*
|
557
|
+
* @type {Color}
|
558
|
+
* @product highcharts
|
559
|
+
* @apioption series.sankey.nodes.color
|
560
|
+
*/
|
561
|
+
|
562
|
+
/**
|
563
|
+
* The color index of the auto generated node, especially for use in styled
|
564
|
+
* mode.
|
565
|
+
*
|
566
|
+
* @type {Number}
|
567
|
+
* @product highcharts
|
568
|
+
* @apioption series.sankey.nodes.colorIndex
|
569
|
+
*/
|
570
|
+
|
571
|
+
/**
|
572
|
+
* An array of data points for the series. For the `sankey` series type,
|
573
|
+
* points can be given in the following way:
|
574
|
+
*
|
575
|
+
* An array of objects with named values. The objects are point
|
576
|
+
* configuration objects as seen below. If the total number of data
|
577
|
+
* points exceeds the series' [turboThreshold](#series.area.turboThreshold),
|
578
|
+
* this option is not available.
|
579
|
+
*
|
580
|
+
* ```js
|
581
|
+
* data: [{
|
582
|
+
* from: 'Category1',
|
583
|
+
* to: 'Category2',
|
584
|
+
* weight: 2
|
585
|
+
* }, {
|
586
|
+
* from: 'Category1',
|
587
|
+
* to: 'Category3',
|
588
|
+
* weight: 5
|
589
|
+
* }]
|
590
|
+
* ```
|
591
|
+
*
|
592
|
+
* @type {Array<Object|Array|Number>}
|
593
|
+
* @extends series.line.data
|
594
|
+
* @excluding drilldown,marker,x,y
|
595
|
+
* @sample {highcharts} highcharts/chart/reflow-true/ Numerical values
|
596
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y
|
597
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y
|
598
|
+
* @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y
|
599
|
+
* @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects
|
600
|
+
* @product highcharts
|
601
|
+
* @apioption series.sankey.data
|
602
|
+
*/
|
603
|
+
|
604
|
+
|
605
|
+
/**
|
606
|
+
* The node that the link runs from.
|
607
|
+
*
|
608
|
+
* @type {String}
|
609
|
+
* @product highcharts
|
610
|
+
* @apioption series.sankey.data.from
|
611
|
+
*/
|
612
|
+
|
613
|
+
/**
|
614
|
+
* The node that the link runs to.
|
615
|
+
*
|
616
|
+
* @type {String}
|
617
|
+
* @product highcharts
|
618
|
+
* @apioption series.sankey.data.to
|
619
|
+
*/
|
620
|
+
|
621
|
+
/**
|
622
|
+
* Whether the link goes out of the system.
|
623
|
+
*
|
624
|
+
* @type {Boolean}
|
625
|
+
* @default false
|
626
|
+
* @sample highcharts/plotoptions/sankey-outgoing
|
627
|
+
* Sankey chart with outgoing links
|
628
|
+
* @product highcharts
|
629
|
+
* @apioption series.sankey.data.outgoing
|
630
|
+
*/
|
631
|
+
|
632
|
+
/**
|
633
|
+
* The weight of the link.
|
634
|
+
*
|
635
|
+
* @type {Number}
|
636
|
+
* @product highcharts
|
637
|
+
* @apioption series.sankey.data.weight
|
638
|
+
*/
|
639
|
+
|
640
|
+
}(Highcharts));
|
641
|
+
}));
|