highcharts-rails 5.0.14 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license Highcharts JS
|
2
|
+
* @license Highcharts JS v6.0.0 (2017-10-04)
|
3
3
|
*
|
4
4
|
* (c) 2009-2017 Torstein Honsi
|
5
5
|
*
|
@@ -384,7 +384,7 @@
|
|
384
384
|
* @type {String}
|
385
385
|
* @see [gapSize](plotOptions.series.gapSize)
|
386
386
|
* @default relative
|
387
|
-
* @
|
387
|
+
* @validvalue ["relative", "value"]
|
388
388
|
* @since 5.0.13
|
389
389
|
* @product highstock
|
390
390
|
* @apioption plotOptions.series.gapUnit
|
@@ -0,0 +1,364 @@
|
|
1
|
+
/**
|
2
|
+
* @license Highcharts JS v6.0.0 (2017-10-04)
|
3
|
+
*
|
4
|
+
* Bullet graph series type for Highcharts
|
5
|
+
*
|
6
|
+
* (c) 2010-2017 Kacper Madej
|
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
|
+
(function(H) {
|
19
|
+
/**
|
20
|
+
* (c) 2010-2017 Kacper Madej
|
21
|
+
*
|
22
|
+
* License: www.highcharts.com/license
|
23
|
+
*/
|
24
|
+
|
25
|
+
|
26
|
+
var each = H.each,
|
27
|
+
pick = H.pick,
|
28
|
+
isNumber = H.isNumber,
|
29
|
+
relativeLength = H.relativeLength,
|
30
|
+
seriesType = H.seriesType,
|
31
|
+
columnProto = H.seriesTypes.column.prototype;
|
32
|
+
|
33
|
+
/**
|
34
|
+
* The bullet series type.
|
35
|
+
*
|
36
|
+
* @constructor seriesTypes.bullet
|
37
|
+
* @augments seriesTypes.column
|
38
|
+
*/
|
39
|
+
seriesType('bullet', 'column',
|
40
|
+
/**
|
41
|
+
* A bullet graph is a variation of a bar graph. The bullet graph features
|
42
|
+
* a single measure, compares it to a target, and displays it in the context
|
43
|
+
* of qualitative ranges of performance that could be set using
|
44
|
+
* [plotBands](#yAxis.plotBands) on [yAxis](#yAxis).
|
45
|
+
*
|
46
|
+
* @extends {plotOptions.column}
|
47
|
+
* @product highcharts
|
48
|
+
* @sample {highcharts} highcharts/demo/bullet-graph/ Bullet graph
|
49
|
+
* @since 6.0.0
|
50
|
+
* @excluding allAreas,boostThreshold,colorAxis,compare,compareBase
|
51
|
+
* @optionparent plotOptions.bullet
|
52
|
+
*/
|
53
|
+
{
|
54
|
+
/**
|
55
|
+
* All options related with look and positiong of targets.
|
56
|
+
*
|
57
|
+
* @sample {highcharts} highcharts/plotoptions/bullet-targetoptions/
|
58
|
+
* Target options
|
59
|
+
*
|
60
|
+
* @type {Object}
|
61
|
+
* @since 6.0.0
|
62
|
+
* @product highcharts
|
63
|
+
*/
|
64
|
+
targetOptions: {
|
65
|
+
/**
|
66
|
+
* The width of the rectangle representing the target. Could be set as
|
67
|
+
* a pixel value or as a percentage of a column width.
|
68
|
+
*
|
69
|
+
* @type {Number|String}
|
70
|
+
* @since 6.0.0
|
71
|
+
* @product highcharts
|
72
|
+
*/
|
73
|
+
width: '140%',
|
74
|
+
|
75
|
+
/**
|
76
|
+
* The height of the rectangle representing the target.
|
77
|
+
*
|
78
|
+
* @since 6.0.0
|
79
|
+
* @product highcharts
|
80
|
+
*/
|
81
|
+
height: 3,
|
82
|
+
|
83
|
+
|
84
|
+
/**
|
85
|
+
* The border width of the rectangle representing the target.
|
86
|
+
*
|
87
|
+
* In styled mode, use class `highcharts-bullet-target` instead.
|
88
|
+
*
|
89
|
+
* @since 6.0.0
|
90
|
+
* @product highcharts
|
91
|
+
*/
|
92
|
+
borderWidth: 0
|
93
|
+
|
94
|
+
/**
|
95
|
+
* The border color of the rectangle representing the target. When
|
96
|
+
* not set, the point's border color is used.
|
97
|
+
*
|
98
|
+
* In styled mode, use class `highcharts-bullet-target` instead.
|
99
|
+
*
|
100
|
+
* @type {Color}
|
101
|
+
* @since 6.0.0
|
102
|
+
* @product highcharts
|
103
|
+
* @apioption plotOptions.bullet.targetOptions.borderColor
|
104
|
+
*/
|
105
|
+
|
106
|
+
/**
|
107
|
+
* The color of the rectangle representing the target. When not set,
|
108
|
+
* point's color (if set in point's options -
|
109
|
+
* [`color`](#series.bullet.data.color)) or zone of the target value
|
110
|
+
* (if [`zones`](#plotOptions.bullet.zones) or
|
111
|
+
* [`negativeColor`](#plotOptions.bullet.negativeColor) are set)
|
112
|
+
* or the same color as the point has is used.
|
113
|
+
*
|
114
|
+
* In styled mode, use class `highcharts-bullet-target` instead.
|
115
|
+
*
|
116
|
+
* @type {Color}
|
117
|
+
* @since 6.0.0
|
118
|
+
* @product highcharts
|
119
|
+
* @apioption plotOptions.bullet.targetOptions.color
|
120
|
+
*/
|
121
|
+
|
122
|
+
},
|
123
|
+
|
124
|
+
tooltip: {
|
125
|
+
|
126
|
+
pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: <b>{point.y}</b>. Target: <b>{point.target}</b><br/>'
|
127
|
+
|
128
|
+
}
|
129
|
+
}, {
|
130
|
+
pointArrayMap: ['y', 'target'],
|
131
|
+
parallelArrays: ['x', 'y', 'target'],
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Draws the targets. For inverted chart, the `series.group` is rotated,
|
135
|
+
* so the same coordinates apply. This method is based on
|
136
|
+
* column series drawPoints function.
|
137
|
+
*/
|
138
|
+
drawPoints: function() {
|
139
|
+
var series = this,
|
140
|
+
chart = series.chart,
|
141
|
+
options = series.options,
|
142
|
+
animationLimit = options.animationLimit || 250;
|
143
|
+
|
144
|
+
columnProto.drawPoints.apply(this);
|
145
|
+
|
146
|
+
each(series.points, function(point) {
|
147
|
+
var pointOptions = point.options,
|
148
|
+
shapeArgs,
|
149
|
+
targetGraphic = point.targetGraphic,
|
150
|
+
targetShapeArgs,
|
151
|
+
targetVal = point.target,
|
152
|
+
pointVal = point.y,
|
153
|
+
width,
|
154
|
+
height,
|
155
|
+
targetOptions,
|
156
|
+
y;
|
157
|
+
|
158
|
+
if (isNumber(targetVal) && targetVal !== null) {
|
159
|
+
targetOptions = H.merge(
|
160
|
+
options.targetOptions,
|
161
|
+
pointOptions.targetOptions
|
162
|
+
);
|
163
|
+
height = targetOptions.height;
|
164
|
+
|
165
|
+
shapeArgs = point.shapeArgs;
|
166
|
+
width = relativeLength(
|
167
|
+
targetOptions.width,
|
168
|
+
shapeArgs.width
|
169
|
+
);
|
170
|
+
y = series.yAxis.translate(
|
171
|
+
targetVal,
|
172
|
+
false,
|
173
|
+
true,
|
174
|
+
false,
|
175
|
+
true
|
176
|
+
) - targetOptions.height / 2 - 0.5;
|
177
|
+
|
178
|
+
targetShapeArgs = series.crispCol.apply({
|
179
|
+
// Use fake series object to set borderWidth of target
|
180
|
+
chart: chart,
|
181
|
+
borderWidth: targetOptions.borderWidth,
|
182
|
+
options: {
|
183
|
+
crisp: options.crisp
|
184
|
+
}
|
185
|
+
}, [
|
186
|
+
shapeArgs.x + shapeArgs.width / 2 - width / 2,
|
187
|
+
y,
|
188
|
+
width,
|
189
|
+
height
|
190
|
+
]);
|
191
|
+
|
192
|
+
if (targetGraphic) {
|
193
|
+
// Update
|
194
|
+
targetGraphic[
|
195
|
+
chart.pointCount < animationLimit ?
|
196
|
+
'animate' :
|
197
|
+
'attr'
|
198
|
+
](targetShapeArgs);
|
199
|
+
|
200
|
+
// Add or remove tooltip reference
|
201
|
+
if (isNumber(pointVal) && pointVal !== null) {
|
202
|
+
targetGraphic.element.point = point;
|
203
|
+
} else {
|
204
|
+
targetGraphic.element.point = undefined;
|
205
|
+
}
|
206
|
+
} else {
|
207
|
+
point.targetGraphic = targetGraphic = chart.renderer
|
208
|
+
.rect()
|
209
|
+
.attr(targetShapeArgs)
|
210
|
+
.add(series.group);
|
211
|
+
}
|
212
|
+
|
213
|
+
// Presentational
|
214
|
+
targetGraphic.attr({
|
215
|
+
fill: pick(
|
216
|
+
targetOptions.color,
|
217
|
+
pointOptions.color,
|
218
|
+
(series.zones.length && (point.getZone.call({
|
219
|
+
series: series,
|
220
|
+
x: point.x,
|
221
|
+
y: targetVal,
|
222
|
+
options: {}
|
223
|
+
}).color || series.color)) || undefined,
|
224
|
+
point.color,
|
225
|
+
series.color
|
226
|
+
),
|
227
|
+
stroke: pick(
|
228
|
+
targetOptions.borderColor,
|
229
|
+
point.borderColor,
|
230
|
+
series.options.borderColor
|
231
|
+
),
|
232
|
+
'stroke-width': targetOptions.borderWidth
|
233
|
+
});
|
234
|
+
|
235
|
+
|
236
|
+
// Add tooltip reference
|
237
|
+
if (isNumber(pointVal) && pointVal !== null) {
|
238
|
+
targetGraphic.element.point = point;
|
239
|
+
}
|
240
|
+
|
241
|
+
targetGraphic.addClass(point.getClassName() +
|
242
|
+
' highcharts-bullet-target', true);
|
243
|
+
} else if (targetGraphic) {
|
244
|
+
point.targetGraphic = targetGraphic.destroy(); // #1269
|
245
|
+
}
|
246
|
+
});
|
247
|
+
},
|
248
|
+
|
249
|
+
/**
|
250
|
+
* Includes target values to extend extremes from y values.
|
251
|
+
*/
|
252
|
+
getExtremes: function(yData) {
|
253
|
+
var series = this,
|
254
|
+
targetData = series.targetData,
|
255
|
+
yMax,
|
256
|
+
yMin;
|
257
|
+
|
258
|
+
columnProto.getExtremes.call(this, yData);
|
259
|
+
|
260
|
+
if (targetData && targetData.length) {
|
261
|
+
yMax = series.dataMax;
|
262
|
+
yMin = series.dataMin;
|
263
|
+
columnProto.getExtremes.call(this, targetData);
|
264
|
+
series.dataMax = Math.max(series.dataMax, yMax);
|
265
|
+
series.dataMin = Math.min(series.dataMin, yMin);
|
266
|
+
}
|
267
|
+
}
|
268
|
+
}, /** @lends seriesTypes.ohlc.prototype.pointClass.prototype */ {
|
269
|
+
/**
|
270
|
+
* Destroys target graphic.
|
271
|
+
*/
|
272
|
+
destroy: function() {
|
273
|
+
if (this.targetGraphic) {
|
274
|
+
this.targetGraphic = this.targetGraphic.destroy();
|
275
|
+
}
|
276
|
+
columnProto.pointClass.prototype.destroy.apply(this, arguments);
|
277
|
+
}
|
278
|
+
});
|
279
|
+
|
280
|
+
|
281
|
+
/**
|
282
|
+
* A `bullet` series. If the [type](#series.bullet.type) option is not
|
283
|
+
* specified, it is inherited from [chart.type](#chart.type).
|
284
|
+
*
|
285
|
+
* For options that apply to multiple series, it is recommended to add
|
286
|
+
* them to the [plotOptions.series](#plotOptions.series) options structure.
|
287
|
+
* To apply to all series of this specific type, apply it to [plotOptions.
|
288
|
+
* bullet](#plotOptions.bullet).
|
289
|
+
*
|
290
|
+
* @type {Object}
|
291
|
+
* @since 6.0.0
|
292
|
+
* @extends series,plotOptions.bullet
|
293
|
+
* @excluding dataParser,dataURL
|
294
|
+
* @product highcharts
|
295
|
+
* @apioption series.bullet
|
296
|
+
*/
|
297
|
+
|
298
|
+
/**
|
299
|
+
* An array of data points for the series. For the `bullet` series type,
|
300
|
+
* points can be given in the following ways:
|
301
|
+
*
|
302
|
+
* 1. An array of arrays with 3 or 2 values. In this case, the values
|
303
|
+
* correspond to `x,y,target`. If the first value is a string,
|
304
|
+
* it is applied as the name of the point, and the `x` value is inferred.
|
305
|
+
* The `x` value can also be omitted, in which case the inner arrays
|
306
|
+
* should be of length 2\. Then the `x` value is automatically calculated,
|
307
|
+
* either starting at 0 and incremented by 1, or from `pointStart`
|
308
|
+
* and `pointInterval` given in the series options.
|
309
|
+
*
|
310
|
+
* ```js
|
311
|
+
* data: [
|
312
|
+
* [0, 40, 75],
|
313
|
+
* [1, 50, 50],
|
314
|
+
* [2, 60, 40]
|
315
|
+
* ]
|
316
|
+
* ```
|
317
|
+
*
|
318
|
+
* 2. An array of objects with named values. The objects are point
|
319
|
+
* configuration objects as seen below. If the total number of data
|
320
|
+
* points exceeds the series' [turboThreshold](#series.bullet.turboThreshold),
|
321
|
+
* this option is not available.
|
322
|
+
*
|
323
|
+
* ```js
|
324
|
+
* data: [{
|
325
|
+
* x: 0,
|
326
|
+
* y: 40,
|
327
|
+
* target: 75,
|
328
|
+
* name: "Point1",
|
329
|
+
* color: "#00FF00"
|
330
|
+
* }, {
|
331
|
+
* x: 1,
|
332
|
+
* y: 60,
|
333
|
+
* target: 40,
|
334
|
+
* name: "Point2",
|
335
|
+
* color: "#FF00FF"
|
336
|
+
* }]
|
337
|
+
* ```
|
338
|
+
*
|
339
|
+
* @type {Array<Object|Array>}
|
340
|
+
* @since 6.0.0
|
341
|
+
* @extends series.column.data
|
342
|
+
* @product highcharts
|
343
|
+
* @apioption series.bullet.data
|
344
|
+
*/
|
345
|
+
|
346
|
+
/**
|
347
|
+
* The target value of a point.
|
348
|
+
*
|
349
|
+
* @type {Number}
|
350
|
+
* @since 6.0.0
|
351
|
+
* @product highcharts
|
352
|
+
* @apioption series.bullet.data.target
|
353
|
+
*/
|
354
|
+
|
355
|
+
/**
|
356
|
+
* Individual target options for each point.
|
357
|
+
*
|
358
|
+
* @extends series.bullet.targetOptions
|
359
|
+
* @product highcharts
|
360
|
+
* @apioption series.bullet.data.targetOptions
|
361
|
+
*/
|
362
|
+
|
363
|
+
}(Highcharts));
|
364
|
+
}));
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license Highcharts JS
|
2
|
+
* @license Highcharts JS v6.0.0 (2017-10-04)
|
3
3
|
* Data module
|
4
4
|
*
|
5
5
|
* (c) 2012-2017 Torstein Honsi
|
@@ -34,8 +34,311 @@
|
|
34
34
|
inArray = Highcharts.inArray,
|
35
35
|
isNumber = Highcharts.isNumber,
|
36
36
|
splat = Highcharts.splat,
|
37
|
+
fireEvent = Highcharts.fireEvent,
|
38
|
+
some,
|
37
39
|
SeriesBuilder;
|
38
40
|
|
41
|
+
// `some` function
|
42
|
+
if (!Array.prototype.some) {
|
43
|
+
some = function(arr, fn, ctx) { // legacy
|
44
|
+
var i = 0,
|
45
|
+
len = arr.length;
|
46
|
+
|
47
|
+
for (; i < len; i++) {
|
48
|
+
if (fn.call(ctx, arr[i], i, arr) === true) {
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
};
|
53
|
+
} else {
|
54
|
+
some = function(arr, fn, ctx) {
|
55
|
+
Array.prototype.some.call(arr, fn, ctx);
|
56
|
+
};
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* The Data module provides a simplified interface for adding data to
|
61
|
+
* a chart from sources like CVS, HTML tables or grid views. See also
|
62
|
+
* the [tutorial article on the Data module](http://www.highcharts.com/docs/working-
|
63
|
+
* with-data/data-module).
|
64
|
+
*
|
65
|
+
* It requires the `modules/data.js` file to be loaded.
|
66
|
+
*
|
67
|
+
* Please note that the default way of adding data in Highcharts, without
|
68
|
+
* the need of a module, is through the [series.data](#series.data)
|
69
|
+
* option.
|
70
|
+
*
|
71
|
+
* @sample {highcharts} highcharts/demo/column-parsed/ HTML table
|
72
|
+
* @sample {highcharts} highcharts/data/csv/ CSV
|
73
|
+
* @since 4.0
|
74
|
+
* @product highcharts
|
75
|
+
* @apioption data
|
76
|
+
*/
|
77
|
+
|
78
|
+
/**
|
79
|
+
* A two-dimensional array representing the input data on tabular form.
|
80
|
+
* This input can be used when the data is already parsed, for example
|
81
|
+
* from a grid view component. Each cell can be a string or number.
|
82
|
+
* If not switchRowsAndColumns is set, the columns are interpreted as
|
83
|
+
* series.
|
84
|
+
*
|
85
|
+
* @type {Array<Array<Mixed>>}
|
86
|
+
* @see [data.rows](#data.rows)
|
87
|
+
* @sample {highcharts} highcharts/data/columns/ Columns
|
88
|
+
* @since 4.0
|
89
|
+
* @product highcharts
|
90
|
+
* @apioption data.columns
|
91
|
+
*/
|
92
|
+
|
93
|
+
/**
|
94
|
+
* The callback that is evaluated when the data is finished loading,
|
95
|
+
* optionally from an external source, and parsed. The first argument
|
96
|
+
* passed is a finished chart options object, containing the series.
|
97
|
+
* These options can be extended with additional options and passed
|
98
|
+
* directly to the chart constructor.
|
99
|
+
*
|
100
|
+
* @type {Function}
|
101
|
+
* @see [data.parsed](#data.parsed)
|
102
|
+
* @sample {highcharts} highcharts/data/complete/ Modify data on complete
|
103
|
+
* @since 4.0
|
104
|
+
* @product highcharts
|
105
|
+
* @apioption data.complete
|
106
|
+
*/
|
107
|
+
|
108
|
+
/**
|
109
|
+
* A comma delimited string to be parsed. Related options are [startRow](#data.
|
110
|
+
* startRow), [endRow](#data.endRow), [startColumn](#data.startColumn)
|
111
|
+
* and [endColumn](#data.endColumn) to delimit what part of the table
|
112
|
+
* is used. The [lineDelimiter](#data.lineDelimiter) and [itemDelimiter](#data.
|
113
|
+
* itemDelimiter) options define the CSV delimiter formats.
|
114
|
+
*
|
115
|
+
* The built-in CSV parser doesn't support all flavours of CSV, so in
|
116
|
+
* some cases it may be necessary to use an external CSV parser. See
|
117
|
+
* [this example](http://jsfiddle.net/highcharts/u59176h4/) of parsing
|
118
|
+
* CSV through the MIT licensed [Papa Parse](http://papaparse.com/)
|
119
|
+
* library.
|
120
|
+
*
|
121
|
+
* @type {String}
|
122
|
+
* @sample {highcharts} highcharts/data/csv/ Data from CSV
|
123
|
+
* @since 4.0
|
124
|
+
* @product highcharts
|
125
|
+
* @apioption data.csv
|
126
|
+
*/
|
127
|
+
|
128
|
+
/**
|
129
|
+
* Which of the predefined date formats in Date.prototype.dateFormats
|
130
|
+
* to use to parse date values. Defaults to a best guess based on what
|
131
|
+
* format gives valid and ordered dates.
|
132
|
+
*
|
133
|
+
* Valid options include:
|
134
|
+
*
|
135
|
+
* * `YYYY-mm-dd`
|
136
|
+
* * `dd/mm/YYYY`
|
137
|
+
* * `mm/dd/YYYY`
|
138
|
+
* * `dd/mm/YY`
|
139
|
+
* * `mm/dd/YY`
|
140
|
+
*
|
141
|
+
* @validvalue [undefined, "YYYY-mm-dd", "dd/mm/YYYY", "mm/dd/YYYY", "dd/mm/YYYY", "dd/mm/YY", "mm/dd/YY"]
|
142
|
+
* @type {String}
|
143
|
+
* @see [data.parseDate](#data.parseDate)
|
144
|
+
* @sample {highcharts} highcharts/data/dateformat-auto/ Best guess date format
|
145
|
+
* @since 4.0
|
146
|
+
* @product highcharts
|
147
|
+
* @apioption data.dateFormat
|
148
|
+
*/
|
149
|
+
|
150
|
+
/**
|
151
|
+
* The decimal point used for parsing numbers in the CSV.
|
152
|
+
*
|
153
|
+
* If both this and data.delimiter is set to false, the parser will
|
154
|
+
* attempt to deduce the decimal point automatically.
|
155
|
+
*
|
156
|
+
* @type {String}
|
157
|
+
* @sample {highcharts} highcharts/data/delimiters/ Comma as decimal point
|
158
|
+
* @default .
|
159
|
+
* @since 4.1.0
|
160
|
+
* @product highcharts
|
161
|
+
* @apioption data.decimalPoint
|
162
|
+
*/
|
163
|
+
|
164
|
+
/**
|
165
|
+
* In tabular input data, the last column (indexed by 0) to use. Defaults
|
166
|
+
* to the last column containing data.
|
167
|
+
*
|
168
|
+
* @type {Number}
|
169
|
+
* @sample {highcharts} highcharts/data/start-end/ Limited data
|
170
|
+
* @since 4.0
|
171
|
+
* @product highcharts
|
172
|
+
* @apioption data.endColumn
|
173
|
+
*/
|
174
|
+
|
175
|
+
/**
|
176
|
+
* In tabular input data, the last row (indexed by 0) to use. Defaults
|
177
|
+
* to the last row containing data.
|
178
|
+
*
|
179
|
+
* @type {Number}
|
180
|
+
* @sample {highcharts} highcharts/data/start-end/ Limited data
|
181
|
+
* @since 4.0.4
|
182
|
+
* @product highcharts
|
183
|
+
* @apioption data.endRow
|
184
|
+
*/
|
185
|
+
|
186
|
+
/**
|
187
|
+
* Whether to use the first row in the data set as series names.
|
188
|
+
*
|
189
|
+
* @type {Boolean}
|
190
|
+
* @sample {highcharts} highcharts/data/start-end/ Don't get series names from the CSV
|
191
|
+
* @sample {highstock} highcharts/data/start-end/ Don't get series names from the CSV
|
192
|
+
* @default true
|
193
|
+
* @since 4.1.0
|
194
|
+
* @product highcharts highstock
|
195
|
+
* @apioption data.firstRowAsNames
|
196
|
+
*/
|
197
|
+
|
198
|
+
/**
|
199
|
+
* The key for a Google Spreadsheet to load. See [general information
|
200
|
+
* on GS](https://developers.google.com/gdata/samples/spreadsheet_sample).
|
201
|
+
*
|
202
|
+
* @type {String}
|
203
|
+
* @sample {highcharts} highcharts/data/google-spreadsheet/ Load a Google Spreadsheet
|
204
|
+
* @since 4.0
|
205
|
+
* @product highcharts
|
206
|
+
* @apioption data.googleSpreadsheetKey
|
207
|
+
*/
|
208
|
+
|
209
|
+
/**
|
210
|
+
* The Google Spreadsheet worksheet to use in combination with [googleSpreadsheetKey](#data.
|
211
|
+
* googleSpreadsheetKey). The available id's from your sheet can be
|
212
|
+
* read from `https://spreadsheets.google.com/feeds/worksheets/{key}/public/basic`
|
213
|
+
*
|
214
|
+
* @type {String}
|
215
|
+
* @sample {highcharts} highcharts/data/google-spreadsheet/ Load a Google Spreadsheet
|
216
|
+
* @since 4.0
|
217
|
+
* @product highcharts
|
218
|
+
* @apioption data.googleSpreadsheetWorksheet
|
219
|
+
*/
|
220
|
+
|
221
|
+
/**
|
222
|
+
* Item or cell delimiter for parsing CSV. Defaults to the tab character
|
223
|
+
* `\t` if a tab character is found in the CSV string, if not it defaults
|
224
|
+
* to `,`.
|
225
|
+
*
|
226
|
+
* If this is set to false or undefined, the parser will attempt to deduce
|
227
|
+
* the delimiter automatically.
|
228
|
+
*
|
229
|
+
* @type {String}
|
230
|
+
* @sample {highcharts} highcharts/data/delimiters/ Delimiters
|
231
|
+
* @since 4.0
|
232
|
+
* @product highcharts
|
233
|
+
* @apioption data.itemDelimiter
|
234
|
+
*/
|
235
|
+
|
236
|
+
/**
|
237
|
+
* Line delimiter for parsing CSV.
|
238
|
+
*
|
239
|
+
* @type {String}
|
240
|
+
* @sample {highcharts} highcharts/data/delimiters/ Delimiters
|
241
|
+
* @default \n
|
242
|
+
* @since 4.0
|
243
|
+
* @product highcharts
|
244
|
+
* @apioption data.lineDelimiter
|
245
|
+
*/
|
246
|
+
|
247
|
+
/**
|
248
|
+
* A callback function to parse string representations of dates into
|
249
|
+
* JavaScript timestamps. Should return an integer timestamp on success.
|
250
|
+
*
|
251
|
+
* @type {Function}
|
252
|
+
* @see [dateFormat](#data.dateFormat)
|
253
|
+
* @since 4.0
|
254
|
+
* @product highcharts
|
255
|
+
* @apioption data.parseDate
|
256
|
+
*/
|
257
|
+
|
258
|
+
/**
|
259
|
+
* A callback function to access the parsed columns, the two-dimentional
|
260
|
+
* input data array directly, before they are interpreted into series
|
261
|
+
* data and categories. Return `false` to stop completion, or call `this.
|
262
|
+
* complete()` to continue async.
|
263
|
+
*
|
264
|
+
* @type {Function}
|
265
|
+
* @see [data.complete](#data.complete)
|
266
|
+
* @sample {highcharts} highcharts/data/parsed/ Modify data after parse
|
267
|
+
* @since 4.0
|
268
|
+
* @product highcharts
|
269
|
+
* @apioption data.parsed
|
270
|
+
*/
|
271
|
+
|
272
|
+
/**
|
273
|
+
* The same as the columns input option, but defining rows intead of
|
274
|
+
* columns.
|
275
|
+
*
|
276
|
+
* @type {Array<Array<Mixed>>}
|
277
|
+
* @see [data.columns](#data.columns)
|
278
|
+
* @sample {highcharts} highcharts/data/rows/ Data in rows
|
279
|
+
* @since 4.0
|
280
|
+
* @product highcharts
|
281
|
+
* @apioption data.rows
|
282
|
+
*/
|
283
|
+
|
284
|
+
/**
|
285
|
+
* An array containing object with Point property names along with what
|
286
|
+
* column id the property should be taken from.
|
287
|
+
*
|
288
|
+
* @type {Array<Object>}
|
289
|
+
* @sample {highcharts} highcharts/data/seriesmapping-label/ Label from data set
|
290
|
+
* @since 4.0.4
|
291
|
+
* @product highcharts
|
292
|
+
* @apioption data.seriesMapping
|
293
|
+
*/
|
294
|
+
|
295
|
+
/**
|
296
|
+
* In tabular input data, the first column (indexed by 0) to use.
|
297
|
+
*
|
298
|
+
* @type {Number}
|
299
|
+
* @sample {highcharts} highcharts/data/start-end/ Limited data
|
300
|
+
* @default 0
|
301
|
+
* @since 4.0
|
302
|
+
* @product highcharts
|
303
|
+
* @apioption data.startColumn
|
304
|
+
*/
|
305
|
+
|
306
|
+
/**
|
307
|
+
* In tabular input data, the first row (indexed by 0) to use.
|
308
|
+
*
|
309
|
+
* @type {Number}
|
310
|
+
* @sample {highcharts} highcharts/data/start-end/ Limited data
|
311
|
+
* @default 0
|
312
|
+
* @since 4.0
|
313
|
+
* @product highcharts
|
314
|
+
* @apioption data.startRow
|
315
|
+
*/
|
316
|
+
|
317
|
+
/**
|
318
|
+
* Switch rows and columns of the input data, so that `this.columns`
|
319
|
+
* effectively becomes the rows of the data set, and the rows are interpreted
|
320
|
+
* as series.
|
321
|
+
*
|
322
|
+
* @type {Boolean}
|
323
|
+
* @sample {highcharts} highcharts/data/switchrowsandcolumns/ Switch rows and columns
|
324
|
+
* @default false
|
325
|
+
* @since 4.0
|
326
|
+
* @product highcharts
|
327
|
+
* @apioption data.switchRowsAndColumns
|
328
|
+
*/
|
329
|
+
|
330
|
+
/**
|
331
|
+
* A HTML table or the id of such to be parsed as input data. Related
|
332
|
+
* options are `startRow`, `endRow`, `startColumn` and `endColumn` to
|
333
|
+
* delimit what part of the table is used.
|
334
|
+
*
|
335
|
+
* @type {String|HTMLElement}
|
336
|
+
* @sample {highcharts} highcharts/demo/column-parsed/ Parsed table
|
337
|
+
* @since 4.0
|
338
|
+
* @product highcharts
|
339
|
+
* @apioption data.table
|
340
|
+
*/
|
341
|
+
|
39
342
|
|
40
343
|
// The Data constructor
|
41
344
|
var Data = function(dataOptions, chartOptions) {
|
@@ -74,14 +377,14 @@
|
|
74
377
|
// Parse a HTML table if options.table is given
|
75
378
|
this.parseTable();
|
76
379
|
|
77
|
-
// Parse a Google Spreadsheet
|
380
|
+
// Parse a Google Spreadsheet
|
78
381
|
this.parseGoogleSpreadsheet();
|
79
382
|
}
|
80
383
|
|
81
384
|
},
|
82
385
|
|
83
386
|
/**
|
84
|
-
* Get the column distribution. For example, a line series takes a single column for
|
387
|
+
* Get the column distribution. For example, a line series takes a single column for
|
85
388
|
* Y values. A range series takes two columns for low and high values respectively,
|
86
389
|
* and an OHLC series takes four columns.
|
87
390
|
*/
|
@@ -138,7 +441,7 @@
|
|
138
441
|
// Add missing columns
|
139
442
|
for (i = 0; i < numberOfValueColumnsNeeded; i++) {
|
140
443
|
if (!builder.hasReader(pointArrayMap[i])) {
|
141
|
-
//builder.addNextColumnReader(pointArrayMap[i]);
|
444
|
+
// builder.addNextColumnReader(pointArrayMap[i]);
|
142
445
|
// Create and add a column reader for the next free column index
|
143
446
|
builder.addColumnReader(undefined, pointArrayMap[i]);
|
144
447
|
}
|
@@ -190,18 +493,369 @@
|
|
190
493
|
/**
|
191
494
|
* Parse a CSV input string
|
192
495
|
*/
|
193
|
-
parseCSV: function() {
|
496
|
+
parseCSV: function(inOptions) {
|
194
497
|
var self = this,
|
195
|
-
options = this.options,
|
498
|
+
options = this.options || inOptions,
|
196
499
|
csv = options.csv,
|
197
|
-
columns
|
500
|
+
columns,
|
198
501
|
startRow = options.startRow || 0,
|
199
502
|
endRow = options.endRow || Number.MAX_VALUE,
|
200
503
|
startColumn = options.startColumn || 0,
|
201
504
|
endColumn = options.endColumn || Number.MAX_VALUE,
|
202
505
|
itemDelimiter,
|
203
506
|
lines,
|
204
|
-
|
507
|
+
rowIt = 0,
|
508
|
+
// activeRowNo = 0,
|
509
|
+
dataTypes = [],
|
510
|
+
// We count potential delimiters in the prepass, and use the
|
511
|
+
// result as the basis of half-intelligent guesses.
|
512
|
+
potDelimiters = {
|
513
|
+
',': 0,
|
514
|
+
';': 0,
|
515
|
+
'\t': 0
|
516
|
+
};
|
517
|
+
|
518
|
+
columns = this.columns = this.columns || [];
|
519
|
+
|
520
|
+
/*
|
521
|
+
This implementation is quite verbose. It will be shortened once
|
522
|
+
it's stable and passes all the test.
|
523
|
+
|
524
|
+
It's also not written with speed in mind, instead everything is
|
525
|
+
very seggregated, and there a several redundant loops.
|
526
|
+
This is to make it easier to stabilize the code initially.
|
527
|
+
|
528
|
+
We do a pre-pass on the first 4 rows to make some intelligent
|
529
|
+
guesses on the set. Guessed delimiters are in this pass counted.
|
530
|
+
|
531
|
+
Auto detecting delimiters
|
532
|
+
- If we meet a quoted string, the next symbol afterwards
|
533
|
+
(that's not \s, \t) is the delimiter
|
534
|
+
- If we meet a date, the next symbol afterwards is the delimiter
|
535
|
+
|
536
|
+
Date formats
|
537
|
+
- If we meet a column with date formats, check all of them to
|
538
|
+
see if one of the potential months crossing 12. If it does,
|
539
|
+
we now know the format
|
540
|
+
|
541
|
+
It would make things easier to guess the delimiter before
|
542
|
+
doing the actual parsing.
|
543
|
+
|
544
|
+
General rules:
|
545
|
+
- Quoting is allowed, e.g: "Col 1",123,321
|
546
|
+
- Quoting is optional, e.g.: Col1,123,321
|
547
|
+
- Doubble quoting is escaping, e.g. "Col ""Hello world""",123
|
548
|
+
- Spaces are considered part of the data: Col1 ,123
|
549
|
+
- New line is always the row delimiter
|
550
|
+
- Potential column delimiters are , ; \t
|
551
|
+
- First row may optionally contain headers
|
552
|
+
- The last row may or may not have a row delimiter
|
553
|
+
- Comments are optionally supported, in which case the comment
|
554
|
+
must start at the first column, and the rest of the line will
|
555
|
+
be ignored
|
556
|
+
*/
|
557
|
+
|
558
|
+
// Parse a single row
|
559
|
+
function parseRow(columnStr, rowNumber, noAdd, callbacks) {
|
560
|
+
var i = 0,
|
561
|
+
c = '',
|
562
|
+
cl = '',
|
563
|
+
cn = '',
|
564
|
+
token = '',
|
565
|
+
column = 0;
|
566
|
+
|
567
|
+
function read(j) {
|
568
|
+
c = columnStr[j];
|
569
|
+
cl = columnStr[j - 1];
|
570
|
+
cn = columnStr[j + 1];
|
571
|
+
}
|
572
|
+
|
573
|
+
function pushType(type) {
|
574
|
+
if (dataTypes.length < column + 1) {
|
575
|
+
dataTypes.push([type]);
|
576
|
+
}
|
577
|
+
if (dataTypes[column][dataTypes[column].length - 1] !== type) {
|
578
|
+
dataTypes[column].push(type);
|
579
|
+
}
|
580
|
+
}
|
581
|
+
|
582
|
+
function push() {
|
583
|
+
if (startColumn > column || column > endColumn) {
|
584
|
+
// Skip this column
|
585
|
+
return;
|
586
|
+
}
|
587
|
+
|
588
|
+
if (!isNaN(parseFloat(token)) && isFinite(token)) {
|
589
|
+
token = parseFloat(token);
|
590
|
+
pushType('number');
|
591
|
+
} else if (!isNaN(Date.parse(token))) {
|
592
|
+
token = token.replace(/\//g, '-');
|
593
|
+
pushType('date');
|
594
|
+
} else {
|
595
|
+
pushType('string');
|
596
|
+
}
|
597
|
+
|
598
|
+
if (columns.length < column + 1) {
|
599
|
+
columns.push([]);
|
600
|
+
}
|
601
|
+
|
602
|
+
if (!noAdd) {
|
603
|
+
columns[column].push(token);
|
604
|
+
}
|
605
|
+
|
606
|
+
token = '';
|
607
|
+
++column;
|
608
|
+
}
|
609
|
+
|
610
|
+
if (!columnStr.trim().length) {
|
611
|
+
return;
|
612
|
+
}
|
613
|
+
|
614
|
+
if (columnStr.trim()[0] === '#') {
|
615
|
+
return;
|
616
|
+
}
|
617
|
+
|
618
|
+
for (; i < columnStr.length; i++) {
|
619
|
+
read(i);
|
620
|
+
|
621
|
+
// Quoted string
|
622
|
+
if (c === '#') {
|
623
|
+
// The rest of the row is a comment
|
624
|
+
return;
|
625
|
+
} else if (c === '"') {
|
626
|
+
read(++i);
|
627
|
+
|
628
|
+
while (i < columnStr.length) {
|
629
|
+
if (c === '"' && cl !== '"' && cn !== '"') {
|
630
|
+
break;
|
631
|
+
}
|
632
|
+
|
633
|
+
if (c !== '"' || (c === '"' && cl !== '"')) {
|
634
|
+
token += c;
|
635
|
+
}
|
636
|
+
|
637
|
+
read(++i);
|
638
|
+
}
|
639
|
+
|
640
|
+
// Perform "plugin" handling
|
641
|
+
} else if (callbacks && callbacks[c]) {
|
642
|
+
if (callbacks[c](c, token)) {
|
643
|
+
push();
|
644
|
+
}
|
645
|
+
|
646
|
+
// Delimiter - push current token
|
647
|
+
} else if (c === itemDelimiter) {
|
648
|
+
push();
|
649
|
+
|
650
|
+
// Actual column data
|
651
|
+
} else {
|
652
|
+
token += c;
|
653
|
+
}
|
654
|
+
}
|
655
|
+
|
656
|
+
push();
|
657
|
+
|
658
|
+
if (column < columns.length) {
|
659
|
+
// There might be an issue.
|
660
|
+
// This set is either
|
661
|
+
|
662
|
+
// Fill in
|
663
|
+
if (!noAdd) {
|
664
|
+
for (var z = column; z < columns.length; z++) {
|
665
|
+
columns[z].push(0);
|
666
|
+
}
|
667
|
+
}
|
668
|
+
}
|
669
|
+
}
|
670
|
+
|
671
|
+
// Attempt to guess the delimiter
|
672
|
+
function guessDelimiter(lines) {
|
673
|
+
var points = 0,
|
674
|
+
commas = 0,
|
675
|
+
guessed = false,
|
676
|
+
handler = function(c, token) {
|
677
|
+
if (c === ',') {
|
678
|
+
commas++;
|
679
|
+
}
|
680
|
+
if (c === '.') {
|
681
|
+
points++;
|
682
|
+
}
|
683
|
+
|
684
|
+
if (typeof potDelimiters[c] !== 'undefined') {
|
685
|
+
// Check what we have in token now
|
686
|
+
|
687
|
+
if (
|
688
|
+
// We can't make a deduction when token is a number,
|
689
|
+
// since the decimal delimiter may interfere.
|
690
|
+
(isNaN(parseFloat(token)) || !isFinite(token)) &&
|
691
|
+
(
|
692
|
+
// Highcharts.isString(token) ||
|
693
|
+
!isNaN(Date.parse(token))
|
694
|
+
)
|
695
|
+
) {
|
696
|
+
potDelimiters[c]++;
|
697
|
+
return true;
|
698
|
+
}
|
699
|
+
}
|
700
|
+
},
|
701
|
+
callbacks = {
|
702
|
+
';': handler,
|
703
|
+
',': handler,
|
704
|
+
'\t': handler
|
705
|
+
};
|
706
|
+
|
707
|
+
some(lines, function(columnStr, i) {
|
708
|
+
// We should be able to detect dateformats within 13 rows
|
709
|
+
if (i > 13) {
|
710
|
+
return true;
|
711
|
+
}
|
712
|
+
parseRow(columnStr, i, true, callbacks);
|
713
|
+
});
|
714
|
+
|
715
|
+
// Count the potential delimiters.
|
716
|
+
// This could be improved by checking if the number of delimiters
|
717
|
+
// equals the number of columns - 1
|
718
|
+
if (potDelimiters[';'] > potDelimiters[',']) {
|
719
|
+
guessed = ';';
|
720
|
+
} else if (potDelimiters[','] > potDelimiters[';']) {
|
721
|
+
guessed = ',';
|
722
|
+
} else {
|
723
|
+
// No good guess could be made..
|
724
|
+
guessed = ',';
|
725
|
+
}
|
726
|
+
|
727
|
+
// Try to deduce the decimal point if it's not explicitly set.
|
728
|
+
// If both commas or points is > 0 there is likely an issue
|
729
|
+
if (!options.decimalPoint) {
|
730
|
+
if (points > commas) {
|
731
|
+
options.decimalPoint = '.';
|
732
|
+
} else {
|
733
|
+
options.decimalPoint = ',';
|
734
|
+
}
|
735
|
+
|
736
|
+
// Apply a new decimal regex based on the pressumed decimal sep.
|
737
|
+
self.decimalRegex = new RegExp(
|
738
|
+
'^(-?[0-9]+)' +
|
739
|
+
options.decimalPoint +
|
740
|
+
'([0-9]+)$'
|
741
|
+
);
|
742
|
+
}
|
743
|
+
|
744
|
+
return guessed;
|
745
|
+
}
|
746
|
+
|
747
|
+
/* Tries to guess the date format
|
748
|
+
* - Check if either month candidate exceeds 12
|
749
|
+
* - Check if year is missing (use current year)
|
750
|
+
* - Check if a shortened year format is used (e.g. 1/1/99)
|
751
|
+
* - If no guess can be made, the user must be prompted
|
752
|
+
* data is the data to deduce a format based on
|
753
|
+
*/
|
754
|
+
function deduceDateFormat(data, limit) {
|
755
|
+
var format = 'YYYY-mm-dd',
|
756
|
+
thing,
|
757
|
+
guessedFormat,
|
758
|
+
calculatedFormat,
|
759
|
+
i = 0,
|
760
|
+
madeDeduction = false,
|
761
|
+
// candidates = {},
|
762
|
+
stable = [],
|
763
|
+
max = [],
|
764
|
+
j;
|
765
|
+
|
766
|
+
if (!limit || limit > data.length) {
|
767
|
+
limit = data.length;
|
768
|
+
}
|
769
|
+
|
770
|
+
for (; i < limit; i++) {
|
771
|
+
if (typeof data[i] !== 'undefined' && data[i] && data[i].length) {
|
772
|
+
thing = data[i]
|
773
|
+
.trim()
|
774
|
+
.replace(/\//g, ' ')
|
775
|
+
.replace(/\-/g, ' ')
|
776
|
+
.split(' ');
|
777
|
+
|
778
|
+
guessedFormat = [
|
779
|
+
'',
|
780
|
+
'',
|
781
|
+
''
|
782
|
+
];
|
783
|
+
|
784
|
+
|
785
|
+
for (j = 0; j < thing.length; j++) {
|
786
|
+
if (j < guessedFormat.length) {
|
787
|
+
thing[j] = parseInt(thing[j], 10);
|
788
|
+
|
789
|
+
if (thing[j]) {
|
790
|
+
|
791
|
+
max[j] = (!max[j] || max[j] < thing[j]) ? thing[j] : max[j];
|
792
|
+
|
793
|
+
if (typeof stable[j] !== 'undefined') {
|
794
|
+
if (stable[j] !== thing[j]) {
|
795
|
+
stable[j] = false;
|
796
|
+
}
|
797
|
+
} else {
|
798
|
+
stable[j] = thing[j];
|
799
|
+
}
|
800
|
+
|
801
|
+
if (thing[j] > 31) {
|
802
|
+
if (thing[j] < 100) {
|
803
|
+
guessedFormat[j] = 'YY';
|
804
|
+
} else {
|
805
|
+
guessedFormat[j] = 'YYYY';
|
806
|
+
}
|
807
|
+
// madeDeduction = true;
|
808
|
+
} else if (thing[j] > 12 && thing[j] <= 31) {
|
809
|
+
guessedFormat[j] = 'dd';
|
810
|
+
madeDeduction = true;
|
811
|
+
} else if (!guessedFormat[j].length) {
|
812
|
+
guessedFormat[j] = 'mm';
|
813
|
+
}
|
814
|
+
}
|
815
|
+
}
|
816
|
+
}
|
817
|
+
}
|
818
|
+
}
|
819
|
+
|
820
|
+
if (madeDeduction) {
|
821
|
+
|
822
|
+
// This handles a few edge cases with hard to guess dates
|
823
|
+
for (j = 0; j < stable.length; j++) {
|
824
|
+
if (stable[j] !== false) {
|
825
|
+
if (max[j] > 12 && guessedFormat[j] !== 'YY' && guessedFormat[j] !== 'YYYY') {
|
826
|
+
guessedFormat[j] = 'YY';
|
827
|
+
}
|
828
|
+
} else if (max[j] > 12 && guessedFormat[j] === 'mm') {
|
829
|
+
guessedFormat[j] = 'dd';
|
830
|
+
}
|
831
|
+
}
|
832
|
+
|
833
|
+
calculatedFormat = guessedFormat.join('/');
|
834
|
+
|
835
|
+
|
836
|
+
// If the caculated format is not valid, we need to present an error.
|
837
|
+
|
838
|
+
if (!(options.dateFormats || self.dateFormats)[calculatedFormat]) {
|
839
|
+
// This should emit an event instead
|
840
|
+
fireEvent('invalidDateFormat');
|
841
|
+
Highcharts.error('Could not deduce date format');
|
842
|
+
return format;
|
843
|
+
}
|
844
|
+
|
845
|
+
return calculatedFormat;
|
846
|
+
}
|
847
|
+
|
848
|
+
return format;
|
849
|
+
}
|
850
|
+
|
851
|
+
/* Figure out the best axis types for the data
|
852
|
+
* - If the first column is a number, we're good
|
853
|
+
* - If the first column is a date, set to date/time
|
854
|
+
* - If the first column is a string, set to categories
|
855
|
+
*/
|
856
|
+
function deduceAxisTypes() {
|
857
|
+
|
858
|
+
}
|
205
859
|
|
206
860
|
if (csv) {
|
207
861
|
|
@@ -210,31 +864,67 @@
|
|
210
864
|
.replace(/\r/g, '\n') // Mac
|
211
865
|
.split(options.lineDelimiter || '\n');
|
212
866
|
|
213
|
-
|
867
|
+
if (!startRow || startRow < 0) {
|
868
|
+
startRow = 0;
|
869
|
+
}
|
214
870
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
isBlank = trimmed === '',
|
219
|
-
items;
|
871
|
+
if (!endRow || endRow > lines.length) {
|
872
|
+
endRow = lines.length;
|
873
|
+
}
|
220
874
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
}
|
875
|
+
if (options.itemDelimiter) {
|
876
|
+
itemDelimiter = options.itemDelimiter;
|
877
|
+
} else {
|
878
|
+
itemDelimiter = null;
|
879
|
+
itemDelimiter = guessDelimiter(lines);
|
880
|
+
}
|
228
881
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
882
|
+
for (rowIt = startRow; rowIt < endRow; rowIt++) {
|
883
|
+
parseRow(lines[rowIt], rowIt);
|
884
|
+
}
|
885
|
+
|
886
|
+
// //Make sure that there's header columns for everything
|
887
|
+
// each(columns, function (col) {
|
888
|
+
|
889
|
+
// });
|
890
|
+
|
891
|
+
deduceAxisTypes();
|
892
|
+
|
893
|
+
if ((!options.columnTypes || options.columnTypes.length === 0) &&
|
894
|
+
dataTypes.length &&
|
895
|
+
dataTypes[0].length &&
|
896
|
+
dataTypes[0][1] === 'date' &&
|
897
|
+
!options.dateFormat) {
|
898
|
+
options.dateFormat = deduceDateFormat(columns[0]);
|
899
|
+
}
|
900
|
+
|
901
|
+
|
902
|
+
// each(lines, function (line, rowNo) {
|
903
|
+
// var trimmed = self.trim(line),
|
904
|
+
// isComment = trimmed.indexOf('#') === 0,
|
905
|
+
// isBlank = trimmed === '',
|
906
|
+
// items;
|
907
|
+
|
908
|
+
// if (rowNo >= startRow && rowNo <= endRow && !isComment && !isBlank) {
|
909
|
+
// items = line.split(itemDelimiter);
|
910
|
+
// each(items, function (item, colNo) {
|
911
|
+
// if (colNo >= startColumn && colNo <= endColumn) {
|
912
|
+
// if (!columns[colNo - startColumn]) {
|
913
|
+
// columns[colNo - startColumn] = [];
|
914
|
+
// }
|
915
|
+
|
916
|
+
// columns[colNo - startColumn][activeRowNo] = item;
|
917
|
+
// }
|
918
|
+
// });
|
919
|
+
// activeRowNo += 1;
|
920
|
+
// }
|
921
|
+
// });
|
922
|
+
//
|
235
923
|
|
236
924
|
this.dataFound();
|
237
925
|
}
|
926
|
+
|
927
|
+
return columns;
|
238
928
|
},
|
239
929
|
|
240
930
|
/**
|
@@ -274,6 +964,7 @@
|
|
274
964
|
},
|
275
965
|
|
276
966
|
/**
|
967
|
+
* Parse a Google spreadsheet.
|
277
968
|
*/
|
278
969
|
parseGoogleSpreadsheet: function() {
|
279
970
|
var self = this,
|
@@ -303,7 +994,7 @@
|
|
303
994
|
rowCount = 0,
|
304
995
|
i;
|
305
996
|
|
306
|
-
// First, find the total number of columns and rows that
|
997
|
+
// First, find the total number of columns and rows that
|
307
998
|
// are actually filled with data
|
308
999
|
for (i = 0; i < cellCount; i++) {
|
309
1000
|
cell = cells[i];
|
@@ -423,7 +1114,7 @@
|
|
423
1114
|
|
424
1115
|
// Disable number or date parsing by setting the X axis type to category
|
425
1116
|
if (forceCategory || (row === 0 && firstRowAsNames)) {
|
426
|
-
column[row] = trimVal;
|
1117
|
+
column[row] = '' + trimVal;
|
427
1118
|
|
428
1119
|
} else if (+trimInsideVal === floatVal) { // is numeric
|
429
1120
|
|
@@ -449,7 +1140,7 @@
|
|
449
1140
|
column[row] = dateVal;
|
450
1141
|
column.isDatetime = true;
|
451
1142
|
|
452
|
-
// Check if the dates are uniformly descending or ascending. If they
|
1143
|
+
// Check if the dates are uniformly descending or ascending. If they
|
453
1144
|
// are not, chances are that they are a different time format, so check
|
454
1145
|
// for alternative.
|
455
1146
|
if (column[row + 1] !== undefined) {
|
@@ -476,14 +1167,14 @@
|
|
476
1167
|
}
|
477
1168
|
|
478
1169
|
// If strings are intermixed with numbers or dates in a parsed column, it is an indication
|
479
|
-
// that parsing went wrong or the data was not intended to display as numbers or dates and
|
480
|
-
// parsing is too aggressive. Fall back to categories. Demonstrated in the
|
1170
|
+
// that parsing went wrong or the data was not intended to display as numbers or dates and
|
1171
|
+
// parsing is too aggressive. Fall back to categories. Demonstrated in the
|
481
1172
|
// highcharts/demo/column-drilldown sample.
|
482
1173
|
if (isXColumn && column.mixed) {
|
483
1174
|
columns[col] = rawColumns[col];
|
484
1175
|
}
|
485
1176
|
|
486
|
-
// If the 0 column is date or number and descending, reverse all columns.
|
1177
|
+
// If the 0 column is date or number and descending, reverse all columns.
|
487
1178
|
if (isXColumn && descending && this.options.sort) {
|
488
1179
|
for (col = 0; col < columns.length; col++) {
|
489
1180
|
columns[col].reverse();
|
@@ -505,6 +1196,12 @@
|
|
505
1196
|
return Date.UTC(+match[1], match[2] - 1, +match[3]);
|
506
1197
|
}
|
507
1198
|
},
|
1199
|
+
'YYYY/mm/dd': {
|
1200
|
+
regex: /^([0-9]{4})[\-\/\.]([0-9]{2})[\-\/\.]([0-9]{2})$/,
|
1201
|
+
parser: function(match) {
|
1202
|
+
return Date.UTC(+match[1], match[2] - 1, +match[3]);
|
1203
|
+
}
|
1204
|
+
},
|
508
1205
|
'dd/mm/YYYY': {
|
509
1206
|
regex: /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{4})$/,
|
510
1207
|
parser: function(match) {
|
@@ -521,7 +1218,16 @@
|
|
521
1218
|
'dd/mm/YY': {
|
522
1219
|
regex: /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{2})$/,
|
523
1220
|
parser: function(match) {
|
524
|
-
|
1221
|
+
var year = +match[3],
|
1222
|
+
d = new Date();
|
1223
|
+
|
1224
|
+
if (year > (d.getFullYear() - 2000)) {
|
1225
|
+
year += 1900;
|
1226
|
+
} else {
|
1227
|
+
year += 2000;
|
1228
|
+
}
|
1229
|
+
|
1230
|
+
return Date.UTC(year, match[2] - 1, +match[1]);
|
525
1231
|
},
|
526
1232
|
alternative: 'mm/dd/YY' // different format with the same regex
|
527
1233
|
},
|
@@ -563,12 +1269,20 @@
|
|
563
1269
|
// Next time, use the one previously found
|
564
1270
|
} else {
|
565
1271
|
format = this.dateFormats[dateFormat];
|
1272
|
+
|
1273
|
+
|
1274
|
+
if (!format) {
|
1275
|
+
// The selected format is invalid
|
1276
|
+
format = this.dateFormats['YYYY-mm-dd'];
|
1277
|
+
}
|
1278
|
+
|
566
1279
|
match = val.match(format.regex);
|
567
1280
|
if (match) {
|
568
1281
|
ret = format.parser(match);
|
569
1282
|
}
|
1283
|
+
|
570
1284
|
}
|
571
|
-
// Fall back to Date.parse
|
1285
|
+
// Fall back to Date.parse
|
572
1286
|
if (!match) {
|
573
1287
|
match = Date.parse(val);
|
574
1288
|
// External tools like Date.js and MooTools extend Date object and
|
@@ -652,7 +1366,7 @@
|
|
652
1366
|
},
|
653
1367
|
|
654
1368
|
/**
|
655
|
-
* If a complete callback function is provided in the options, interpret the
|
1369
|
+
* If a complete callback function is provided in the options, interpret the
|
656
1370
|
* columns into a Highcharts options object.
|
657
1371
|
*/
|
658
1372
|
complete: function() {
|
@@ -790,6 +1504,19 @@
|
|
790
1504
|
options.afterComplete(chartOptions);
|
791
1505
|
}
|
792
1506
|
}
|
1507
|
+
|
1508
|
+
},
|
1509
|
+
|
1510
|
+
update: function(options, redraw) {
|
1511
|
+
var chart = this.chart;
|
1512
|
+
if (options) {
|
1513
|
+
// Set the complete handler
|
1514
|
+
options.afterComplete = function(dataOptions) {
|
1515
|
+
chart.update(dataOptions, redraw);
|
1516
|
+
};
|
1517
|
+
// Apply it
|
1518
|
+
Highcharts.data(options);
|
1519
|
+
}
|
793
1520
|
}
|
794
1521
|
});
|
795
1522
|
|
@@ -805,7 +1532,7 @@
|
|
805
1532
|
var chart = this;
|
806
1533
|
|
807
1534
|
if (userOptions && userOptions.data) {
|
808
|
-
|
1535
|
+
chart.data = new Data(Highcharts.extend(userOptions.data, {
|
809
1536
|
|
810
1537
|
afterComplete: function(dataOptions) {
|
811
1538
|
var i, series;
|
@@ -829,6 +1556,7 @@
|
|
829
1556
|
proceed.call(chart, userOptions, callback);
|
830
1557
|
}
|
831
1558
|
}), userOptions);
|
1559
|
+
chart.data.chart = chart;
|
832
1560
|
} else {
|
833
1561
|
proceed.call(chart, userOptions, callback);
|
834
1562
|
}
|
@@ -840,7 +1568,7 @@
|
|
840
1568
|
* Ex: A series builder can be constructed to read column 3 as 'x' and
|
841
1569
|
* column 7 and 8 as 'y1' and 'y2'.
|
842
1570
|
* The output would then be points/rows of the form {x: 11, y1: 22, y2: 33}
|
843
|
-
*
|
1571
|
+
*
|
844
1572
|
* The name of the builder is taken from the second column. In the above
|
845
1573
|
* example it would be the column with index 7.
|
846
1574
|
* @constructor
|