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
@@ -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
|