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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +60 -0
  3. data/Rakefile +54 -5
  4. data/app/assets/images/highcharts/earth.svg +432 -0
  5. data/app/assets/javascripts/highcharts.js +5103 -3147
  6. data/app/assets/javascripts/highcharts/highcharts-3d.js +930 -277
  7. data/app/assets/javascripts/highcharts/highcharts-more.js +1374 -249
  8. data/app/assets/javascripts/highcharts/lib/canvg.js +3073 -0
  9. data/app/assets/javascripts/highcharts/lib/jspdf.js +16624 -0
  10. data/app/assets/javascripts/highcharts/lib/rgbcolor.js +299 -0
  11. data/app/assets/javascripts/highcharts/lib/svg2pdf.js +3488 -0
  12. data/app/assets/javascripts/highcharts/modules/accessibility.js +654 -212
  13. data/app/assets/javascripts/highcharts/modules/annotations.js +1552 -274
  14. data/app/assets/javascripts/highcharts/modules/boost-canvas.js +773 -0
  15. data/app/assets/javascripts/highcharts/modules/boost.js +636 -210
  16. data/app/assets/javascripts/highcharts/modules/broken-axis.js +2 -2
  17. data/app/assets/javascripts/highcharts/modules/bullet.js +364 -0
  18. data/app/assets/javascripts/highcharts/modules/data.js +766 -38
  19. data/app/assets/javascripts/highcharts/modules/drag-panes.js +588 -0
  20. data/app/assets/javascripts/highcharts/modules/drilldown.js +106 -36
  21. data/app/assets/javascripts/highcharts/modules/export-data.js +597 -0
  22. data/app/assets/javascripts/highcharts/modules/exporting.js +424 -162
  23. data/app/assets/javascripts/highcharts/modules/funnel.js +144 -22
  24. data/app/assets/javascripts/highcharts/modules/gantt.js +1154 -0
  25. data/app/assets/javascripts/highcharts/modules/grid-axis.js +1 -1
  26. data/app/assets/javascripts/highcharts/modules/heatmap.js +406 -80
  27. data/app/assets/javascripts/highcharts/modules/histogram-bellcurve.js +513 -0
  28. data/app/assets/javascripts/highcharts/modules/item-series.js +126 -0
  29. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +31 -13
  30. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +179 -57
  31. data/app/assets/javascripts/highcharts/modules/oldie.js +1378 -0
  32. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +8 -6
  33. data/app/assets/javascripts/highcharts/modules/parallel-coordinates.js +494 -0
  34. data/app/assets/javascripts/highcharts/modules/pareto.js +275 -0
  35. data/app/assets/javascripts/highcharts/modules/sankey.js +641 -0
  36. data/app/assets/javascripts/highcharts/modules/series-label.js +355 -145
  37. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +122 -1
  38. data/app/assets/javascripts/highcharts/modules/static-scale.js +64 -0
  39. data/app/assets/javascripts/highcharts/modules/stock.js +1944 -676
  40. data/app/assets/javascripts/highcharts/modules/streamgraph.js +139 -0
  41. data/app/assets/javascripts/highcharts/modules/sunburst.js +2403 -0
  42. data/app/assets/javascripts/highcharts/modules/tilemap.js +1199 -0
  43. data/app/assets/javascripts/highcharts/modules/treemap.js +538 -134
  44. data/app/assets/javascripts/highcharts/modules/variable-pie.js +490 -0
  45. data/app/assets/javascripts/highcharts/modules/variwide.js +283 -0
  46. data/app/assets/javascripts/highcharts/modules/vector.js +294 -0
  47. data/app/assets/javascripts/highcharts/modules/windbarb.js +490 -0
  48. data/app/assets/javascripts/highcharts/modules/wordcloud.js +681 -0
  49. data/app/assets/javascripts/highcharts/modules/xrange.js +615 -0
  50. data/app/assets/javascripts/highcharts/themes/avocado.js +54 -0
  51. data/app/assets/javascripts/highcharts/themes/dark-blue.js +6 -6
  52. data/app/assets/javascripts/highcharts/themes/dark-green.js +6 -6
  53. data/app/assets/javascripts/highcharts/themes/dark-unica.js +6 -6
  54. data/app/assets/javascripts/highcharts/themes/gray.js +14 -10
  55. data/app/assets/javascripts/highcharts/themes/grid-light.js +6 -6
  56. data/app/assets/javascripts/highcharts/themes/grid.js +7 -5
  57. data/app/assets/javascripts/highcharts/themes/sand-signika.js +8 -7
  58. data/app/assets/javascripts/highcharts/themes/skies.js +15 -9
  59. data/app/assets/javascripts/highcharts/themes/sunset.js +53 -0
  60. data/app/assets/stylesheets/highcharts/highcharts.css +802 -0
  61. data/app/assets/stylesheets/highcharts/highcharts.scss +665 -0
  62. data/lib/highcharts/version.rb +1 -1
  63. metadata +31 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.14 (2017-07-28)
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
- * @validvalues ["relative", "value"]
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 v5.0.14 (2017-07-28)
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 = this.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
- activeRowNo = 0;
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
- itemDelimiter = options.itemDelimiter || (csv.indexOf('\t') !== -1 ? '\t' : ',');
867
+ if (!startRow || startRow < 0) {
868
+ startRow = 0;
869
+ }
214
870
 
215
- each(lines, function(line, rowNo) {
216
- var trimmed = self.trim(line),
217
- isComment = trimmed.indexOf('#') === 0,
218
- isBlank = trimmed === '',
219
- items;
871
+ if (!endRow || endRow > lines.length) {
872
+ endRow = lines.length;
873
+ }
220
874
 
221
- if (rowNo >= startRow && rowNo <= endRow && !isComment && !isBlank) {
222
- items = line.split(itemDelimiter);
223
- each(items, function(item, colNo) {
224
- if (colNo >= startColumn && colNo <= endColumn) {
225
- if (!columns[colNo - startColumn]) {
226
- columns[colNo - startColumn] = [];
227
- }
875
+ if (options.itemDelimiter) {
876
+ itemDelimiter = options.itemDelimiter;
877
+ } else {
878
+ itemDelimiter = null;
879
+ itemDelimiter = guessDelimiter(lines);
880
+ }
228
881
 
229
- columns[colNo - startColumn][activeRowNo] = item;
230
- }
231
- });
232
- activeRowNo += 1;
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
- return Date.UTC(+match[3] + 2000, match[2] - 1, +match[1]);
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
- Highcharts.data(Highcharts.extend(userOptions.data, {
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