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.
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
  * Solid angular gauge module
4
4
  *
5
5
  * (c) 2010-2017 Torstein Honsi
@@ -164,13 +164,54 @@
164
164
  }
165
165
  };
166
166
  /**
167
+ * A solid gauge is a circular gauge where the value is indicated by a filled
168
+ * arc, and the color of the arc may variate with the value.
169
+ *
170
+ * @sample highcharts/demo/gauge-solid/ Solid gauges
167
171
  * @extends plotOptions.gauge
172
+ * @excluding dial,pivot
173
+ * @product highcharts
168
174
  * @optionparent plotOptions.solidgauge
169
175
  */
170
176
  var solidGaugeOptions = {
171
177
  /**
178
+ * Whether to give each point an individual color.
172
179
  */
173
180
  colorByPoint: true
181
+ /**
182
+ * Whether the strokes of the solid gauge should be `round` or `square`.
183
+ *
184
+ * @validvalue ["square", "round"]
185
+ * @type {String}
186
+ * @sample {highcharts} highcharts/demo/gauge-activity/ Rounded gauge
187
+ * @default round
188
+ * @since 4.2.2
189
+ * @product highcharts
190
+ * @apioption plotOptions.solidgauge.linecap
191
+ */
192
+
193
+ /**
194
+ * Wether to draw rounded edges on the gauge.
195
+ *
196
+ * @type {Boolean}
197
+ * @sample {highcharts} highcharts/demo/gauge-activity/ Activity Gauge
198
+ * @default false
199
+ * @since 5.0.8
200
+ * @product highcharts
201
+ * @apioption plotOptions.solidgauge.rounded
202
+ */
203
+
204
+ /**
205
+ * The threshold or base level for the gauge.
206
+ *
207
+ * @type {Number}
208
+ * @sample {highcharts} highcharts/plotoptions/solidgauge-threshold/
209
+ * Zero threshold with negative and positive values
210
+ * @default null
211
+ * @since 5.0.3
212
+ * @product highcharts
213
+ * @apioption plotOptions.solidgauge.threshold
214
+ */
174
215
 
175
216
  };
176
217
 
@@ -313,5 +354,85 @@
313
354
  }
314
355
  });
315
356
 
357
+ /**
358
+ * A `solidgauge` series. If the [type](#series.solidgauge.type) option
359
+ * is not specified, it is inherited from [chart.type](#chart.type).
360
+ *
361
+ *
362
+ * For options that apply to multiple series, it is recommended to add
363
+ * them to the [plotOptions.series](#plotOptions.series) options structure.
364
+ * To apply to all series of this specific type, apply it to [plotOptions.
365
+ * solidgauge](#plotOptions.solidgauge).
366
+ *
367
+ * @type {Object}
368
+ * @extends series,plotOptions.solidgauge
369
+ * @excluding dataParser,dataURL,stack
370
+ * @product highcharts
371
+ * @apioption series.solidgauge
372
+ */
373
+
374
+ /**
375
+ * An array of data points for the series. For the `solidgauge` series
376
+ * type, points can be given in the following ways:
377
+ *
378
+ * 1. An array of numerical values. In this case, the numerical values
379
+ * will be interpreted as `y` options. Example:
380
+ *
381
+ * ```js
382
+ * data: [0, 5, 3, 5]
383
+ * ```
384
+ *
385
+ * 2. An array of objects with named values. The objects are point
386
+ * configuration objects as seen below. If the total number of data
387
+ * points exceeds the series' [turboThreshold](#series.solidgauge.turboThreshold),
388
+ * this option is not available.
389
+ *
390
+ * ```js
391
+ * data: [{
392
+ * y: 5,
393
+ * name: "Point2",
394
+ * color: "#00FF00"
395
+ * }, {
396
+ * y: 7,
397
+ * name: "Point1",
398
+ * color: "#FF00FF"
399
+ * }]
400
+ * ```
401
+ *
402
+ * The typical gauge only contains a single data value.
403
+ *
404
+ * @type {Array<Object|Number>}
405
+ * @extends series.gauge.data
406
+ * @sample {highcharts} highcharts/chart/reflow-true/ Numerical values
407
+ * @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y
408
+ * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y
409
+ * @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y
410
+ * @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects
411
+ * @product highcharts
412
+ * @apioption series.solidgauge.data
413
+ */
414
+
415
+ /**
416
+ * The inner radius of an individual point in a solid gauge. Can be
417
+ * given as a number (pixels) or percentage string.
418
+ *
419
+ * @type {Number|String}
420
+ * @sample {highcharts} highcharts/plotoptions/solidgauge-radius/ Individual radius and innerRadius
421
+ * @since 4.1.6
422
+ * @product highcharts
423
+ * @apioption series.solidgauge.data.innerRadius
424
+ */
425
+
426
+ /**
427
+ * The outer radius of an individual point in a solid gauge. Can be
428
+ * given as a number (pixels) or percentage string.
429
+ *
430
+ * @type {Number|String}
431
+ * @sample {highcharts} highcharts/plotoptions/solidgauge-radius/ Individual radius and innerRadius
432
+ * @since 4.1.6
433
+ * @product highcharts
434
+ * @apioption series.solidgauge.data.radius
435
+ */
436
+
316
437
  }(Highcharts));
317
438
  }));
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @license Highcharts JS v6.0.0 (2017-10-04)
3
+ * StaticScale
4
+ *
5
+ * (c) 2016 Torstein Honsi, Lars A. V. Cabrera
6
+ *
7
+ * --- WORK IN PROGRESS ---
8
+ *
9
+ * License: www.highcharts.com/license
10
+ */
11
+ 'use strict';
12
+ (function(factory) {
13
+ if (typeof module === 'object' && module.exports) {
14
+ module.exports = factory;
15
+ } else {
16
+ factory(Highcharts);
17
+ }
18
+ }(function(Highcharts) {
19
+ (function(H) {
20
+ /**
21
+ * (c) 2017 Torstein Honsi, Lars Cabrera
22
+ *
23
+ * License: www.highcharts.com/license
24
+ */
25
+
26
+ var Chart = H.Chart,
27
+ each = H.each,
28
+ pick = H.pick;
29
+
30
+ Chart.prototype.adjustHeight = function() {
31
+ each(this.axes, function(axis) {
32
+ var chart = axis.chart,
33
+ animate = !!chart.initiatedScale && chart.options.animation,
34
+ staticScale = axis.options.staticScale,
35
+ height,
36
+ diff;
37
+ if (
38
+ H.isNumber(staticScale) &&
39
+ !axis.horiz &&
40
+ H.defined(axis.min)
41
+ ) {
42
+ height = pick(
43
+ axis.unitLength,
44
+ axis.max + axis.tickInterval - axis.min
45
+ ) * staticScale;
46
+
47
+ // Minimum height is 1 x staticScale.
48
+ height = Math.max(height, staticScale);
49
+
50
+ diff = height - chart.plotHeight;
51
+
52
+ if (Math.abs(diff) >= 1) {
53
+ chart.plotHeight = height;
54
+ chart.setSize(null, chart.chartHeight + diff, animate);
55
+ }
56
+ }
57
+
58
+ });
59
+ this.initiatedScale = true;
60
+ };
61
+ H.addEvent(Chart.prototype, 'render', Chart.prototype.adjustHeight);
62
+
63
+ }(Highcharts));
64
+ }));
@@ -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
  * Highstock as a plugin for Highcharts
4
4
  *
5
5
  * (c) 2017 Torstein Honsi
@@ -29,6 +29,7 @@
29
29
  each = H.each,
30
30
  extend = H.extend,
31
31
  noop = H.noop,
32
+ pick = H.pick,
32
33
  Series = H.Series,
33
34
  timeUnits = H.timeUnits,
34
35
  wrap = H.wrap;
@@ -238,15 +239,42 @@
238
239
  slope,
239
240
  hasBreaks = axis.isXAxis && !!axis.options.breaks,
240
241
  isOrdinal = axis.options.ordinal,
242
+ overscrollPointsRange = Number.MAX_SAFE_INTEGER,
241
243
  ignoreHiddenSeries = axis.chart.options.chart.ignoreHiddenSeries,
244
+ isNavigatorAxis = axis.options.className === 'highcharts-navigator-xaxis',
242
245
  i;
243
246
 
244
- // apply the ordinal logic
247
+ if (
248
+ axis.options.overscroll &&
249
+ axis.max === axis.dataMax &&
250
+ (
251
+ // Panning is an execption,
252
+ // We don't want to apply overscroll when panning over the dataMax
253
+ !axis.chart.mouseIsDown ||
254
+ isNavigatorAxis
255
+ ) && (
256
+ // Scrollbar buttons are the other execption:
257
+ !axis.eventArgs ||
258
+ axis.eventArgs && axis.eventArgs.trigger !== 'navigator'
259
+ )
260
+ ) {
261
+ axis.max += axis.options.overscroll;
262
+
263
+ // Live data and buttons require translation for the min:
264
+ if (!isNavigatorAxis && defined(axis.userMin)) {
265
+ axis.min += axis.options.overscroll;
266
+ }
267
+ }
268
+
269
+ // Apply the ordinal logic
245
270
  if (isOrdinal || hasBreaks) { // #4167 YAxis is never ordinal ?
246
271
 
247
272
  each(axis.series, function(series, i) {
248
273
 
249
- if ((!ignoreHiddenSeries || series.visible !== false) && (series.takeOrdinalPosition !== false || hasBreaks)) {
274
+ if (
275
+ (!ignoreHiddenSeries || series.visible !== false) &&
276
+ (series.takeOrdinalPosition !== false || hasBreaks)
277
+ ) {
250
278
 
251
279
  // concatenate the processed X data into the existing positions, or the empty array
252
280
  ordinalPositions = ordinalPositions.concat(series.processedXData);
@@ -257,6 +285,15 @@
257
285
  return a - b; // without a custom function it is sorted as strings
258
286
  });
259
287
 
288
+ overscrollPointsRange = Math.min(
289
+ overscrollPointsRange,
290
+ pick(
291
+ // Check for a single-point series:
292
+ series.closestPointRange,
293
+ overscrollPointsRange
294
+ )
295
+ );
296
+
260
297
  if (len) {
261
298
  i = len - 1;
262
299
  while (i--) {
@@ -285,9 +322,27 @@
285
322
 
286
323
  // When zooming in on a week, prevent axis padding for weekends even though the data within
287
324
  // the week is evenly spaced.
288
- if (!axis.options.keepOrdinalPadding && (ordinalPositions[0] - min > dist || max - ordinalPositions[ordinalPositions.length - 1] > dist)) {
325
+ if (!axis.options.keepOrdinalPadding &&
326
+ (
327
+ ordinalPositions[0] - min > dist ||
328
+ max - ordinalPositions[ordinalPositions.length - 1] > dist
329
+ )
330
+ ) {
289
331
  useOrdinal = true;
290
332
  }
333
+ } else if (axis.options.overscroll) {
334
+ if (len === 2) {
335
+ // Exactly two points, distance for overscroll is fixed:
336
+ overscrollPointsRange = ordinalPositions[1] - ordinalPositions[0];
337
+ } else if (len === 1) {
338
+ // We have just one point, closest distance is unknown.
339
+ // Assume then it is last point and overscrolled range:
340
+ overscrollPointsRange = axis.options.overscroll;
341
+ ordinalPositions = [ordinalPositions[0], ordinalPositions[0] + overscrollPointsRange];
342
+ } else {
343
+ // In case of zooming in on overscrolled range, stick to the old range:
344
+ overscrollPointsRange = axis.overscrollPointsRange;
345
+ }
291
346
  }
292
347
 
293
348
  // Record the slope and offset to compute the linear values from the array index.
@@ -295,6 +350,11 @@
295
350
  // end positions within it (#719, #665b)
296
351
  if (useOrdinal) {
297
352
 
353
+ if (axis.options.overscroll) {
354
+ axis.overscrollPointsRange = overscrollPointsRange;
355
+ ordinalPositions = ordinalPositions.concat(axis.getOverscrollPositions());
356
+ }
357
+
298
358
  // Register
299
359
  axis.ordinalPositions = ordinalPositions;
300
360
 
@@ -320,6 +380,7 @@
320
380
  axis.ordinalOffset = min - (minIndex * slope);
321
381
 
322
382
  } else {
383
+ axis.overscrollPointsRange = pick(axis.closestPointRange, axis.overscrollPointsRange);
323
384
  axis.ordinalPositions = axis.ordinalSlope = axis.ordinalOffset = undefined;
324
385
  }
325
386
  }
@@ -444,6 +505,7 @@
444
505
  grouping = axis.series[0].currentDataGrouping,
445
506
  ordinalIndex = axis.ordinalIndex,
446
507
  key = grouping ? grouping.count + grouping.unitName : 'raw',
508
+ overscroll = axis.options.overscroll,
447
509
  extremes = axis.getExtremes(),
448
510
  fakeAxis,
449
511
  fakeSeries;
@@ -464,7 +526,7 @@
464
526
  getExtremes: function() {
465
527
  return {
466
528
  min: extremes.dataMin,
467
- max: extremes.dataMax
529
+ max: extremes.dataMax + overscroll
468
530
  };
469
531
  },
470
532
  options: {
@@ -478,10 +540,13 @@
478
540
  each(axis.series, function(series) {
479
541
  fakeSeries = {
480
542
  xAxis: fakeAxis,
481
- xData: series.xData,
543
+ xData: series.xData.slice(),
482
544
  chart: chart,
483
545
  destroyGroupedData: noop
484
546
  };
547
+
548
+ fakeSeries.xData = fakeSeries.xData.concat(axis.getOverscrollPositions());
549
+
485
550
  fakeSeries.options = {
486
551
  dataGrouping: grouping ? {
487
552
  enabled: true,
@@ -496,6 +561,7 @@
496
561
  };
497
562
  series.processData.apply(fakeSeries);
498
563
 
564
+
499
565
  fakeAxis.series.push(fakeSeries);
500
566
  });
501
567
 
@@ -508,6 +574,38 @@
508
574
  return ordinalIndex[key];
509
575
  },
510
576
 
577
+ /**
578
+ * Get ticks for an ordinal axis within a range where points don't exist.
579
+ * It is required when overscroll is enabled. We can't base on points,
580
+ * because we may not have any, so we use approximated pointRange and
581
+ * generate these ticks between <Axis.dataMax, Axis.dataMax + Axis.overscroll>
582
+ * evenly spaced. Used in panning and navigator scrolling.
583
+ *
584
+ * @returns positions {Array} Generated ticks
585
+ * @private
586
+ */
587
+ getOverscrollPositions: function() {
588
+ var axis = this,
589
+ extraRange = axis.options.overscroll,
590
+ distance = axis.overscrollPointsRange,
591
+ positions = [],
592
+ max = axis.dataMax;
593
+
594
+ if (H.defined(distance)) {
595
+ // Max + pointRange because we need to scroll to the last
596
+
597
+ positions.push(max);
598
+
599
+ while (max <= axis.dataMax + extraRange) {
600
+ max += distance;
601
+ positions.push(max);
602
+ }
603
+
604
+ }
605
+
606
+ return positions;
607
+ },
608
+
511
609
  /**
512
610
  * Find the factor to estimate how wide the plot area would have been if ordinal
513
611
  * gaps were included. This value is used to compute an imagined plot width in order
@@ -595,6 +693,7 @@
595
693
  wrap(Chart.prototype, 'pan', function(proceed, e) {
596
694
  var chart = this,
597
695
  xAxis = chart.xAxis[0],
696
+ overscroll = xAxis.options.overscroll,
598
697
  chartX = e.chartX,
599
698
  runBase = false;
600
699
 
@@ -607,7 +706,7 @@
607
706
  max = extremes.max,
608
707
  trimmedRange,
609
708
  hoverPoints = chart.hoverPoints,
610
- closestPointRange = xAxis.closestPointRange,
709
+ closestPointRange = xAxis.closestPointRange || xAxis.overscrollPointsRange,
611
710
  pointPixelWidth = xAxis.translationSlope * (xAxis.ordinalSlope || closestPointRange),
612
711
  movedUnits = (mouseDownX - chartX) / pointPixelWidth, // how many ordinal units did we move?
613
712
  extendedAxis = {
@@ -664,7 +763,10 @@
664
763
  );
665
764
 
666
765
  // Apply it if it is within the available data range
667
- if (trimmedRange.min >= Math.min(extremes.dataMin, min) && trimmedRange.max <= Math.max(dataMax, max)) {
766
+ if (
767
+ trimmedRange.min >= Math.min(extremes.dataMin, min) &&
768
+ trimmedRange.max <= Math.max(dataMax, max) + overscroll
769
+ ) {
668
770
  xAxis.setExtremes(trimmedRange.min, trimmedRange.max, true, false, {
669
771
  trigger: 'pan'
670
772
  });
@@ -682,6 +784,9 @@
682
784
 
683
785
  // revert to the linear chart.pan version
684
786
  if (runBase) {
787
+ if (overscroll) {
788
+ xAxis.max = xAxis.dataMax + overscroll;
789
+ }
685
790
  // call the original function
686
791
  proceed.apply(this, Array.prototype.slice.call(arguments, 1));
687
792
  }
@@ -1063,7 +1168,7 @@
1063
1168
  * @type {String}
1064
1169
  * @see [gapSize](plotOptions.series.gapSize)
1065
1170
  * @default relative
1066
- * @validvalues ["relative", "value"]
1171
+ * @validvalue ["relative", "value"]
1067
1172
  * @since 5.0.13
1068
1173
  * @product highstock
1069
1174
  * @apioption plotOptions.series.gapUnit
@@ -1142,6 +1247,191 @@
1142
1247
  * Start data grouping module *
1143
1248
  ******************************************************************************/
1144
1249
 
1250
+ /**
1251
+ * Data grouping is the concept of sampling the data values into larger
1252
+ * blocks in order to ease readability and increase performance of the
1253
+ * JavaScript charts. Highstock by default applies data grouping when
1254
+ * the points become closer than a certain pixel value, determined by
1255
+ * the `groupPixelWidth` option.
1256
+ *
1257
+ * If data grouping is applied, the grouping information of grouped
1258
+ * points can be read from the [Point.dataGroup](#Point.dataGroup).
1259
+ *
1260
+ * @product highstock
1261
+ * @apioption plotOptions.series.dataGrouping
1262
+ */
1263
+
1264
+ /**
1265
+ * The method of approximation inside a group. When for example 30 days
1266
+ * are grouped into one month, this determines what value should represent
1267
+ * the group. Possible values are "average", "averages", "open", "high",
1268
+ * "low", "close" and "sum". For OHLC and candlestick series the approximation
1269
+ * is "ohlc" by default, which finds the open, high, low and close values
1270
+ * within all the grouped data. For ranges, the approximation is "range",
1271
+ * which finds the low and high values. For multi-dimensional data,
1272
+ * like ranges and OHLC, "averages" will compute the average for each
1273
+ * dimension.
1274
+ *
1275
+ * Custom aggregate methods can be added by assigning a callback function
1276
+ * as the approximation. This function takes a numeric array as the
1277
+ * argument and should return a single numeric value or `null`. Note
1278
+ * that the numeric array will never contain null values, only true
1279
+ * numbers. Instead, if null values are present in the raw data, the
1280
+ * numeric array will have an `.hasNulls` property set to `true`. For
1281
+ * single-value data sets the data is available in the first argument
1282
+ * of the callback function. For OHLC data sets, all the open values
1283
+ * are in the first argument, all high values in the second etc.
1284
+ *
1285
+ * Since v4.2.7, grouping meta data is available in the approximation
1286
+ * callback from `this.dataGroupInfo`. It can be used to extract information
1287
+ * from the raw data.
1288
+ *
1289
+ * Defaults to `average` for line-type series, `sum` for columns, `range`
1290
+ * for range series and `ohlc` for OHLC and candlestick.
1291
+ *
1292
+ * @validvalue ["average", "averages", "open", "high", "low", "close", "sum"]
1293
+ * @type {String|Function}
1294
+ * @sample {highstock} stock/plotoptions/series-datagrouping-approximation Approximation callback with custom data
1295
+ * @product highstock
1296
+ * @apioption plotOptions.series.dataGrouping.approximation
1297
+ */
1298
+
1299
+ /**
1300
+ * Datetime formats for the header of the tooltip in a stock chart.
1301
+ * The format can vary within a chart depending on the currently selected
1302
+ * time range and the current data grouping.
1303
+ *
1304
+ * The default formats are:
1305
+ *
1306
+ * <pre>{
1307
+ * millisecond: ['%A, %b %e, %H:%M:%S.%L', '%A, %b %e, %H:%M:%S.%L', '-%H:%M:%S.%L'],
1308
+ * second: ['%A, %b %e, %H:%M:%S', '%A, %b %e, %H:%M:%S', '-%H:%M:%S'],
1309
+ * minute: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
1310
+ * hour: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
1311
+ * day: ['%A, %b %e, %Y', '%A, %b %e', '-%A, %b %e, %Y'],
1312
+ * week: ['Week from %A, %b %e, %Y', '%A, %b %e', '-%A, %b %e, %Y'],
1313
+ * month: ['%B %Y', '%B', '-%B %Y'],
1314
+ * year: ['%Y', '%Y', '-%Y']
1315
+ * }</pre>
1316
+ *
1317
+ * For each of these array definitions, the first item is the format
1318
+ * used when the active time span is one unit. For instance, if the
1319
+ * current data applies to one week, the first item of the week array
1320
+ * is used. The second and third items are used when the active time
1321
+ * span is more than two units. For instance, if the current data applies
1322
+ * to two weeks, the second and third item of the week array are used,
1323
+ * and applied to the start and end date of the time span.
1324
+ *
1325
+ * @type {Object}
1326
+ * @product highstock
1327
+ * @apioption plotOptions.series.dataGrouping.dateTimeLabelFormats
1328
+ */
1329
+
1330
+ /**
1331
+ * Enable or disable data grouping.
1332
+ *
1333
+ * @type {Boolean}
1334
+ * @default true
1335
+ * @product highstock
1336
+ * @apioption plotOptions.series.dataGrouping.enabled
1337
+ */
1338
+
1339
+ /**
1340
+ * When data grouping is forced, it runs no matter how small the intervals
1341
+ * are. This can be handy for example when the sum should be calculated
1342
+ * for values appearing at random times within each hour.
1343
+ *
1344
+ * @type {Boolean}
1345
+ * @default false
1346
+ * @product highstock
1347
+ * @apioption plotOptions.series.dataGrouping.forced
1348
+ */
1349
+
1350
+ /**
1351
+ * The approximate pixel width of each group. If for example a series
1352
+ * with 30 points is displayed over a 600 pixel wide plot area, no grouping
1353
+ * is performed. If however the series contains so many points that
1354
+ * the spacing is less than the groupPixelWidth, Highcharts will try
1355
+ * to group it into appropriate groups so that each is more or less
1356
+ * two pixels wide. If multiple series with different group pixel widths
1357
+ * are drawn on the same x axis, all series will take the greatest width.
1358
+ * For example, line series have 2px default group width, while column
1359
+ * series have 10px. If combined, both the line and the column will
1360
+ * have 10px by default.
1361
+ *
1362
+ * @type {Number}
1363
+ * @default 2
1364
+ * @product highstock
1365
+ * @apioption plotOptions.series.dataGrouping.groupPixelWidth
1366
+ */
1367
+
1368
+ /**
1369
+ * Normally, a group is indexed by the start of that group, so for example
1370
+ * when 30 daily values are grouped into one month, that month's x value
1371
+ * will be the 1st of the month. This apparently shifts the data to
1372
+ * the left. When the smoothed option is true, this is compensated for.
1373
+ * The data is shifted to the middle of the group, and min and max
1374
+ * values are preserved. Internally, this is used in the Navigator series.
1375
+ *
1376
+ * @type {Boolean}
1377
+ * @default false
1378
+ * @product highstock
1379
+ * @apioption plotOptions.series.dataGrouping.smoothed
1380
+ */
1381
+
1382
+ /**
1383
+ * An array determining what time intervals the data is allowed to be
1384
+ * grouped to. Each array item is an array where the first value is
1385
+ * the time unit and the second value another array of allowed multiples.
1386
+ * Defaults to:
1387
+ *
1388
+ * <pre>units: [[
1389
+ * 'millisecond', // unit name
1390
+ * [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
1391
+ * ], [
1392
+ * 'second',
1393
+ * [1, 2, 5, 10, 15, 30]
1394
+ * ], [
1395
+ * 'minute',
1396
+ * [1, 2, 5, 10, 15, 30]
1397
+ * ], [
1398
+ * 'hour',
1399
+ * [1, 2, 3, 4, 6, 8, 12]
1400
+ * ], [
1401
+ * 'day',
1402
+ * [1]
1403
+ * ], [
1404
+ * 'week',
1405
+ * [1]
1406
+ * ], [
1407
+ * 'month',
1408
+ * [1, 3, 6]
1409
+ * ], [
1410
+ * 'year',
1411
+ * null
1412
+ * ]]</pre>
1413
+ *
1414
+ * @type {Array}
1415
+ * @product highstock
1416
+ * @apioption plotOptions.series.dataGrouping.units
1417
+ */
1418
+
1419
+ /**
1420
+ * The approximate pixel width of each group. If for example a series
1421
+ * with 30 points is displayed over a 600 pixel wide plot area, no grouping
1422
+ * is performed. If however the series contains so many points that
1423
+ * the spacing is less than the groupPixelWidth, Highcharts will try
1424
+ * to group it into appropriate groups so that each is more or less
1425
+ * two pixels wide. Defaults to `10`.
1426
+ *
1427
+ * @type {Number}
1428
+ * @sample {highstock} stock/plotoptions/series-datagrouping-grouppixelwidth/
1429
+ * Two series with the same data density but different groupPixelWidth
1430
+ * @default 10
1431
+ * @product highstock
1432
+ * @apioption plotOptions.column.dataGrouping.groupPixelWidth
1433
+ */
1434
+
1145
1435
  var seriesProto = Series.prototype,
1146
1436
  baseProcessData = seriesProto.processData,
1147
1437
  baseGeneratePoints = seriesProto.generatePoints,
@@ -1152,8 +1442,8 @@
1152
1442
  */
1153
1443
  commonOptions = {
1154
1444
  approximation: 'average', // average, open, high, low, close, sum
1155
- //enabled: null, // (true for stock charts, false for basic),
1156
- //forced: undefined,
1445
+ // enabled: null, // (true for stock charts, false for basic),
1446
+ // forced: undefined,
1157
1447
  groupPixelWidth: 2,
1158
1448
  // the first one is the point or start value, the second is the start value if we're dealing with range,
1159
1449
  // the third one is the end value if dealing with a range
@@ -1237,7 +1527,7 @@
1237
1527
  * only of numbers. In case null values belong to the group, the property
1238
1528
  * .hasNulls will be set to true on the array.
1239
1529
  */
1240
- approximations = {
1530
+ approximations = H.approximations = {
1241
1531
  sum: function(arr) {
1242
1532
  var len = arr.length,
1243
1533
  ret;
@@ -1317,7 +1607,6 @@
1317
1607
  }
1318
1608
  };
1319
1609
 
1320
-
1321
1610
  /**
1322
1611
  * Takes parallel arrays of x and y data and groups the data into intervals
1323
1612
  * defined by groupPositions, a collection of starting x values for each group.
@@ -1508,7 +1797,7 @@
1508
1797
 
1509
1798
  // prevent the smoothed data to spill out left and right, and make
1510
1799
  // sure data is not shifted to the left
1511
- if (dataGroupingOptions.smoothed) {
1800
+ if (dataGroupingOptions.smoothed && groupedXData.length) {
1512
1801
  i = groupedXData.length - 1;
1513
1802
  groupedXData[i] = Math.min(groupedXData[i], xMax);
1514
1803
  while (i-- && i > 0) {
@@ -1814,29 +2103,47 @@
1814
2103
  * @augments seriesTypes.column
1815
2104
  */
1816
2105
  /**
2106
+ * An OHLC chart is a style of financial chart used to describe price
2107
+ * movements over time. It displays open, high, low and close values per data
2108
+ * point.
2109
+ *
2110
+ * @sample stock/demo/ohlc/ OHLC chart
1817
2111
  * @extends {plotOptions.column}
2112
+ * @excluding borderColor,borderRadius,borderWidth
2113
+ * @product highstock
1818
2114
  * @optionparent plotOptions.ohlc
1819
2115
  */
1820
2116
  seriesType('ohlc', 'column', {
1821
2117
 
2118
+ /**
2119
+ * The approximate pixel width of each group. If for example a series
2120
+ * with 30 points is displayed over a 600 pixel wide plot area, no grouping
2121
+ * is performed. If however the series contains so many points that
2122
+ * the spacing is less than the groupPixelWidth, Highcharts will try
2123
+ * to group it into appropriate groups so that each is more or less
2124
+ * two pixels wide. Defaults to `5`.
2125
+ *
2126
+ * @type {Number}
2127
+ * @default 5
2128
+ * @product highstock
2129
+ * @apioption plotOptions.ohlc.dataGrouping.groupPixelWidth
2130
+ */
2131
+
1822
2132
  /**
1823
2133
  * The pixel width of the line/border. Defaults to `1`.
1824
2134
  *
1825
2135
  * @type {Number}
1826
- * @sample {highstock} stock/plotoptions/ohlc-linewidth/ A greater line width
2136
+ * @sample {highstock} stock/plotoptions/ohlc-linewidth/
2137
+ * A greater line width
1827
2138
  * @default 1
1828
2139
  * @product highstock
1829
2140
  */
1830
2141
  lineWidth: 1,
1831
2142
 
1832
- /**
1833
- */
1834
2143
  tooltip: {
1835
2144
 
1836
2145
 
1837
- /**
1838
- */
1839
- pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {series.name}</b><br/>' +
2146
+ pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {series.name}</b><br/>' + // eslint-disable-line max-len
1840
2147
  'Open: {point.open}<br/>' +
1841
2148
  'High: {point.high}<br/>' +
1842
2149
  'Low: {point.low}<br/>' +
@@ -1844,13 +2151,9 @@
1844
2151
 
1845
2152
  },
1846
2153
 
1847
- /**
1848
- */
1849
2154
  threshold: null,
1850
2155
 
1851
2156
 
1852
- /**
1853
- */
1854
2157
  states: {
1855
2158
 
1856
2159
  /**
@@ -1860,8 +2163,7 @@
1860
2163
  hover: {
1861
2164
 
1862
2165
  /**
1863
- * The pixel width of the line representing the OHLC point. Defaults
1864
- * to `3`.
2166
+ * The pixel width of the line representing the OHLC point.
1865
2167
  *
1866
2168
  * @type {Number}
1867
2169
  * @default 3
@@ -1871,15 +2173,22 @@
1871
2173
  }
1872
2174
  },
1873
2175
 
2176
+
1874
2177
  /**
2178
+ * Line color for up points.
2179
+ *
2180
+ * @type {Color}
2181
+ * @product highstock
2182
+ * @apioption plotOptions.ohlc.upColor
1875
2183
  */
1876
- stickyTracking: true
1877
- //upColor: undefined
1878
2184
 
1879
2185
 
2186
+
2187
+ stickyTracking: true
2188
+
1880
2189
  }, /** @lends seriesTypes.ohlc */ {
1881
2190
  directTouch: false,
1882
- pointArrayMap: ['open', 'high', 'low', 'close'], // array point configs are mapped to this
2191
+ pointArrayMap: ['open', 'high', 'low', 'close'],
1883
2192
  toYData: function(point) { // return a plain array for speedy calculation
1884
2193
  return [point.open, point.high, point.low, point.close];
1885
2194
  },
@@ -1922,20 +2231,29 @@
1922
2231
  var series = this,
1923
2232
  yAxis = series.yAxis,
1924
2233
  hasModifyValue = !!series.modifyValue,
1925
- translated = ['plotOpen', 'plotHigh', 'plotLow', 'plotClose', 'yBottom']; // translate OHLC for
2234
+ translated = [
2235
+ 'plotOpen',
2236
+ 'plotHigh',
2237
+ 'plotLow',
2238
+ 'plotClose',
2239
+ 'yBottom'
2240
+ ]; // translate OHLC for
1926
2241
 
1927
2242
  seriesTypes.column.prototype.translate.apply(series);
1928
2243
 
1929
2244
  // Do the translation
1930
2245
  each(series.points, function(point) {
1931
- each([point.open, point.high, point.low, point.close, point.low], function(value, i) {
1932
- if (value !== null) {
1933
- if (hasModifyValue) {
1934
- value = series.modifyValue(value);
2246
+ each(
2247
+ [point.open, point.high, point.low, point.close, point.low],
2248
+ function(value, i) {
2249
+ if (value !== null) {
2250
+ if (hasModifyValue) {
2251
+ value = series.modifyValue(value);
2252
+ }
2253
+ point[translated[i]] = yAxis.toPixels(value, true);
1935
2254
  }
1936
- point[translated[i]] = yAxis.toPixels(value, true);
1937
2255
  }
1938
- });
2256
+ );
1939
2257
 
1940
2258
  // Align the tooltip to the high value to avoid covering the point
1941
2259
  point.tooltipPos[1] =
@@ -1971,7 +2289,9 @@
1971
2289
  }
1972
2290
 
1973
2291
 
1974
- graphic.attr(series.pointAttribs(point, point.selected && 'select')); // #3897
2292
+ graphic.attr(
2293
+ series.pointAttribs(point, point.selected && 'select')
2294
+ ); // #3897
1975
2295
 
1976
2296
 
1977
2297
  // crisp vector coordinates
@@ -2037,12 +2357,97 @@
2037
2357
  */
2038
2358
  getClassName: function() {
2039
2359
  return Point.prototype.getClassName.call(this) +
2040
- (this.open < this.close ? ' highcharts-point-up' : ' highcharts-point-down');
2360
+ (
2361
+ this.open < this.close ?
2362
+ ' highcharts-point-up' :
2363
+ ' highcharts-point-down'
2364
+ );
2041
2365
  }
2042
2366
  });
2043
- /* ****************************************************************************
2044
- * End OHLC series code *
2045
- *****************************************************************************/
2367
+
2368
+ /**
2369
+ * A `ohlc` series. If the [type](#series.ohlc.type) option is not
2370
+ * specified, it is inherited from [chart.type](#chart.type).
2371
+ *
2372
+ * For options that apply to multiple series, it is recommended to add
2373
+ * them to the [plotOptions.series](#plotOptions.series) options structure.
2374
+ * To apply to all series of this specific type, apply it to [plotOptions.
2375
+ * ohlc](#plotOptions.ohlc).
2376
+ *
2377
+ * @type {Object}
2378
+ * @extends series,plotOptions.ohlc
2379
+ * @excluding dataParser,dataURL
2380
+ * @product highstock
2381
+ * @apioption series.ohlc
2382
+ */
2383
+
2384
+ /**
2385
+ * An array of data points for the series. For the `ohlc` series type,
2386
+ * points can be given in the following ways:
2387
+ *
2388
+ * 1. An array of arrays with 5 or 4 values. In this case, the values
2389
+ * correspond to `x,open,high,low,close`. If the first value is a string,
2390
+ * it is applied as the name of the point, and the `x` value is inferred.
2391
+ * The `x` value can also be omitted, in which case the inner arrays
2392
+ * should be of length 4\. Then the `x` value is automatically calculated,
2393
+ * either starting at 0 and incremented by 1, or from `pointStart`
2394
+ * and `pointInterval` given in the series options.
2395
+ *
2396
+ * ```js
2397
+ * data: [
2398
+ * [0, 6, 5, 6, 7],
2399
+ * [1, 9, 4, 8, 2],
2400
+ * [2, 6, 3, 4, 10]
2401
+ * ]
2402
+ * ```
2403
+ *
2404
+ * 2. An array of objects with named values. The objects are point
2405
+ * configuration objects as seen below. If the total number of data
2406
+ * points exceeds the series' [turboThreshold](#series.ohlc.turboThreshold),
2407
+ * this option is not available.
2408
+ *
2409
+ * ```js
2410
+ * data: [{
2411
+ * x: 1,
2412
+ * open: 3,
2413
+ * high: 4,
2414
+ * low: 5,
2415
+ * close: 2,
2416
+ * name: "Point2",
2417
+ * color: "#00FF00"
2418
+ * }, {
2419
+ * x: 1,
2420
+ * open: 4,
2421
+ * high: 3,
2422
+ * low: 6,
2423
+ * close: 7,
2424
+ * name: "Point1",
2425
+ * color: "#FF00FF"
2426
+ * }]
2427
+ * ```
2428
+ *
2429
+ * @type {Array<Object|Array>}
2430
+ * @extends series.arearange.data
2431
+ * @excluding y,marker
2432
+ * @product highstock
2433
+ * @apioption series.ohlc.data
2434
+ */
2435
+
2436
+ /**
2437
+ * The closing value of each data point.
2438
+ *
2439
+ * @type {Number}
2440
+ * @product highstock
2441
+ * @apioption series.ohlc.data.close
2442
+ */
2443
+
2444
+ /**
2445
+ * The opening value of each data point.
2446
+ *
2447
+ * @type {Number}
2448
+ * @product highstock
2449
+ * @apioption series.ohlc.data.open
2450
+ */
2046
2451
 
2047
2452
  }(Highcharts));
2048
2453
  (function(H) {
@@ -2058,14 +2463,18 @@
2058
2463
  seriesTypes = H.seriesTypes;
2059
2464
 
2060
2465
  /**
2466
+ * A candlestick chart is a style of financial chart used to describe price
2467
+ * movements over time.
2468
+ *
2469
+ * @sample stock/demo/candlestick/ Candlestick chart
2470
+ *
2061
2471
  * @extends {plotOptions.ohlc}
2062
- * @products highstock
2472
+ * @excluding borderColor,borderRadius,borderWidth
2473
+ * @product highstock
2063
2474
  * @optionparent plotOptions.candlestick
2064
2475
  */
2065
2476
  var candlestickOptions = {
2066
2477
 
2067
- /**
2068
- */
2069
2478
  states: {
2070
2479
 
2071
2480
  /**
@@ -2075,8 +2484,7 @@
2075
2484
  hover: {
2076
2485
 
2077
2486
  /**
2078
- * The pixel width of the line/border around the candlestick. Defaults
2079
- * to `2`.
2487
+ * The pixel width of the line/border around the candlestick.
2080
2488
  *
2081
2489
  * @type {Number}
2082
2490
  * @default 2
@@ -2087,24 +2495,23 @@
2087
2495
  },
2088
2496
 
2089
2497
  /**
2498
+ * @extends {plotOptions.ohlc.tooltip}
2090
2499
  */
2091
2500
  tooltip: defaultPlotOptions.ohlc.tooltip,
2092
2501
 
2093
- /**
2094
- */
2095
2502
  threshold: null,
2096
2503
 
2097
2504
 
2098
2505
  /**
2099
2506
  * The color of the line/border of the candlestick.
2100
2507
  *
2101
- * In [styled mode](http://www.highcharts.com/docs/chart-design-and-
2102
- * style/style-by-css), the line stroke can be set with the `.highcharts-
2508
+ * In styled mode, the line stroke can be set with the `.highcharts-
2103
2509
  * candlestick-series .highcahrts-point` rule.
2104
2510
  *
2105
2511
  * @type {Color}
2106
2512
  * @see [upLineColor](#plotOptions.candlestick.upLineColor)
2107
- * @sample {highstock} stock/plotoptions/candlestick-linecolor/ Candlestick line colors
2513
+ * @sample {highstock} stock/plotoptions/candlestick-linecolor/
2514
+ * Candlestick line colors
2108
2515
  * @default #000000
2109
2516
  * @product highstock
2110
2517
  */
@@ -2114,8 +2521,7 @@
2114
2521
  * The pixel width of the candlestick line/border. Defaults to `1`.
2115
2522
  *
2116
2523
  *
2117
- * In [styled mode](http://www.highcharts.com/docs/chart-design-and-
2118
- * style/style-by-css), the line stroke width can be set with the `.
2524
+ * In styled mode, the line stroke width can be set with the `.
2119
2525
  * highcharts-candlestick-series .highcahrts-point` rule.
2120
2526
  *
2121
2527
  * @type {Number}
@@ -2127,8 +2533,7 @@
2127
2533
  /**
2128
2534
  * The fill color of the candlestick when values are rising.
2129
2535
  *
2130
- * In [styled mode](http://www.highcharts.com/docs/chart-design-and-
2131
- * style/style-by-css), the up color can be set with the `.highcharts-
2536
+ * In styled mode, the up color can be set with the `.highcharts-
2132
2537
  * candlestick-series .highcharts-point-up` rule.
2133
2538
  *
2134
2539
  * @type {Color}
@@ -2139,12 +2544,26 @@
2139
2544
  */
2140
2545
  upColor: '#ffffff',
2141
2546
 
2547
+ stickyTracking: true
2548
+
2142
2549
  /**
2550
+ * The specific line color for up candle sticks. The default is to inherit
2551
+ * the general `lineColor` setting.
2552
+ *
2553
+ * @type {Color}
2554
+ * @sample {highstock} stock/plotoptions/candlestick-linecolor/ Candlestick line colors
2555
+ * @default null
2556
+ * @since 1.3.6
2557
+ * @product highstock
2558
+ * @apioption plotOptions.candlestick.upLineColor
2143
2559
  */
2144
- stickyTracking: true
2145
- // upLineColor: null
2146
2560
 
2147
2561
 
2562
+ /**
2563
+ * @default ohlc
2564
+ * @apioption plotOptions.candlestick.dataGrouping.approximation
2565
+ */
2566
+
2148
2567
  };
2149
2568
 
2150
2569
  /**
@@ -2190,7 +2609,7 @@
2190
2609
  * Draw the data points
2191
2610
  */
2192
2611
  drawPoints: function() {
2193
- var series = this, //state = series.state,
2612
+ var series = this,
2194
2613
  points = series.points,
2195
2614
  chart = series.chart;
2196
2615
 
@@ -2274,73 +2693,288 @@
2274
2693
 
2275
2694
  });
2276
2695
 
2277
- /* ****************************************************************************
2278
- * End Candlestick series code *
2279
- *****************************************************************************/
2696
+ /**
2697
+ * A `candlestick` series. If the [type](#series.candlestick.type)
2698
+ * option is not specified, it is inherited from [chart.type](#chart.
2699
+ * type).
2700
+ *
2701
+ * For options that apply to multiple series, it is recommended to add
2702
+ * them to the [plotOptions.series](#plotOptions.series) options structure.
2703
+ * To apply to all series of this specific type, apply it to [plotOptions.
2704
+ * candlestick](#plotOptions.candlestick).
2705
+ *
2706
+ * @type {Object}
2707
+ * @extends series,plotOptions.candlestick
2708
+ * @excluding dataParser,dataURL
2709
+ * @product highstock
2710
+ * @apioption series.candlestick
2711
+ */
2712
+
2713
+ /**
2714
+ * An array of data points for the series. For the `candlestick` series
2715
+ * type, points can be given in the following ways:
2716
+ *
2717
+ * 1. An array of arrays with 5 or 4 values. In this case, the values
2718
+ * correspond to `x,open,high,low,close`. If the first value is a string,
2719
+ * it is applied as the name of the point, and the `x` value is inferred.
2720
+ * The `x` value can also be omitted, in which case the inner arrays
2721
+ * should be of length 4\. Then the `x` value is automatically calculated,
2722
+ * either starting at 0 and incremented by 1, or from `pointStart`
2723
+ * and `pointInterval` given in the series options.
2724
+ *
2725
+ * ```js
2726
+ * data: [
2727
+ * [0, 7, 2, 0, 4],
2728
+ * [1, 1, 4, 2, 8],
2729
+ * [2, 3, 3, 9, 3]
2730
+ * ]
2731
+ * ```
2732
+ *
2733
+ * 2. An array of objects with named values. The objects are point
2734
+ * configuration objects as seen below. If the total number of data
2735
+ * points exceeds the series' [turboThreshold](#series.candlestick.
2736
+ * turboThreshold), this option is not available.
2737
+ *
2738
+ * ```js
2739
+ * data: [{
2740
+ * x: 1,
2741
+ * open: 9,
2742
+ * high: 2,
2743
+ * low: 4,
2744
+ * close: 6,
2745
+ * name: "Point2",
2746
+ * color: "#00FF00"
2747
+ * }, {
2748
+ * x: 1,
2749
+ * open: 1,
2750
+ * high: 4,
2751
+ * low: 7,
2752
+ * close: 7,
2753
+ * name: "Point1",
2754
+ * color: "#FF00FF"
2755
+ * }]
2756
+ * ```
2757
+ *
2758
+ * @type {Array<Object|Array>}
2759
+ * @extends series.ohlc.data
2760
+ * @excluding y
2761
+ * @product highstock
2762
+ * @apioption series.candlestick.data
2763
+ */
2280
2764
 
2281
2765
  }(Highcharts));
2282
- (function(H) {
2766
+ var onSeriesMixin = (function(H) {
2283
2767
  /**
2284
2768
  * (c) 2010-2017 Torstein Honsi
2285
2769
  *
2286
2770
  * License: www.highcharts.com/license
2287
2771
  */
2288
- var addEvent = H.addEvent,
2289
- each = H.each,
2290
- merge = H.merge,
2291
- noop = H.noop,
2292
- Renderer = H.Renderer,
2293
- Series = H.Series,
2294
- seriesType = H.seriesType,
2772
+
2773
+ var each = H.each,
2295
2774
  seriesTypes = H.seriesTypes,
2296
- SVGRenderer = H.SVGRenderer,
2297
- TrackerMixin = H.TrackerMixin,
2298
- VMLRenderer = H.VMLRenderer,
2299
- symbols = SVGRenderer.prototype.symbols,
2300
2775
  stableSort = H.stableSort;
2301
2776
 
2302
- /**
2303
- * The flags series type.
2304
- *
2305
- * @constructor seriesTypes.flags
2306
- * @augments seriesTypes.column
2307
- */
2308
- /**
2309
- * @extends {plotOptions.column}
2310
- * @optionparent plotOptions.flags
2311
- */
2312
- seriesType('flags', 'column', {
2313
-
2777
+ var onSeriesMixin = {
2314
2778
  /**
2779
+ * Extend the translate method by placing the point on the related series
2315
2780
  */
2316
- pointRange: 0, // #673
2317
- //radius: 2,
2781
+ translate: function() {
2318
2782
 
2319
- /**
2320
- * The shape of the marker. Can be one of "flag", "circlepin", "squarepin",
2321
- * or an image on the format `url(/path-to-image.jpg)`. Individual
2322
- * shapes can also be set for each point.
2323
- *
2324
- * @validvalue ["flag", "circlepin", "squarepin"]
2325
- * @type {String}
2326
- * @sample {highstock} stock/plotoptions/flags/ Different shapes
2327
- * @default flag
2328
- * @product highstock
2329
- */
2330
- shape: 'flag',
2783
+ seriesTypes.column.prototype.translate.apply(this);
2331
2784
 
2332
- /**
2333
- * When multiple flags in the same series fall on the same value, this
2334
- * number determines the vertical offset between them.
2335
- *
2336
- * @type {Number}
2337
- * @sample {highstock} stock/plotoptions/flags-stackdistance/ A greater stack distance
2338
- * @default 12
2339
- * @product highstock
2340
- */
2341
- stackDistance: 12,
2785
+ var series = this,
2786
+ options = series.options,
2787
+ chart = series.chart,
2788
+ points = series.points,
2789
+ cursor = points.length - 1,
2790
+ point,
2791
+ lastPoint,
2792
+ optionsOnSeries = options.onSeries,
2793
+ onSeries = optionsOnSeries && chart.get(optionsOnSeries),
2794
+ onKey = options.onKey || 'y',
2795
+ step = onSeries && onSeries.options.step,
2796
+ onData = onSeries && onSeries.points,
2797
+ i = onData && onData.length,
2798
+ xAxis = series.xAxis,
2799
+ yAxis = series.yAxis,
2800
+ xAxisExt = xAxis.getExtremes(),
2801
+ xOffset = 0,
2802
+ leftPoint,
2803
+ lastX,
2804
+ rightPoint,
2805
+ currentDataGrouping;
2342
2806
 
2343
- /**
2807
+ // relate to a master series
2808
+ if (onSeries && onSeries.visible && i) {
2809
+ xOffset = (onSeries.pointXOffset || 0) + (onSeries.barW || 0) / 2;
2810
+ currentDataGrouping = onSeries.currentDataGrouping;
2811
+ lastX = (
2812
+ onData[i - 1].x +
2813
+ (currentDataGrouping ? currentDataGrouping.totalRange : 0)
2814
+ ); // #2374
2815
+
2816
+ // sort the data points
2817
+ stableSort(points, function(a, b) {
2818
+ return (a.x - b.x);
2819
+ });
2820
+
2821
+ onKey = 'plot' + onKey[0].toUpperCase() + onKey.substr(1);
2822
+ while (i-- && points[cursor]) {
2823
+ point = points[cursor];
2824
+ leftPoint = onData[i];
2825
+ if (leftPoint.x <= point.x && leftPoint[onKey] !== undefined) {
2826
+ if (point.x <= lastX) { // #803
2827
+
2828
+ point.plotY = leftPoint[onKey];
2829
+
2830
+ // interpolate between points, #666
2831
+ if (leftPoint.x < point.x && !step) {
2832
+ rightPoint = onData[i + 1];
2833
+ if (rightPoint && rightPoint[onKey] !== undefined) {
2834
+ point.plotY +=
2835
+ // the distance ratio, between 0 and 1
2836
+ (
2837
+ (point.x - leftPoint.x) /
2838
+ (rightPoint.x - leftPoint.x)
2839
+ ) *
2840
+ // the y distance
2841
+ (rightPoint[onKey] - leftPoint[onKey]);
2842
+ }
2843
+ }
2844
+ }
2845
+ cursor--;
2846
+ i++; // check again for points in the same x position
2847
+ if (cursor < 0) {
2848
+ break;
2849
+ }
2850
+ }
2851
+ }
2852
+ }
2853
+
2854
+ // Add plotY position and handle stacking
2855
+ each(points, function(point, i) {
2856
+
2857
+ var stackIndex;
2858
+
2859
+ // Undefined plotY means the point is either on axis, outside series
2860
+ // range or hidden series. If the series is outside the range of the
2861
+ // x axis it should fall through with an undefined plotY, but then
2862
+ // we must remove the shapeArgs (#847).
2863
+ if (point.plotY === undefined) {
2864
+ if (point.x >= xAxisExt.min && point.x <= xAxisExt.max) {
2865
+ // we're inside xAxis range
2866
+ point.plotY = chart.chartHeight - xAxis.bottom -
2867
+ (xAxis.opposite ? xAxis.height : 0) +
2868
+ xAxis.offset - yAxis.top; // #3517
2869
+ } else {
2870
+ point.shapeArgs = {}; // 847
2871
+ }
2872
+ }
2873
+ point.plotX += xOffset; // #2049
2874
+ // if multiple flags appear at the same x, order them into a stack
2875
+ lastPoint = points[i - 1];
2876
+ if (lastPoint && lastPoint.plotX === point.plotX) {
2877
+ if (lastPoint.stackIndex === undefined) {
2878
+ lastPoint.stackIndex = 0;
2879
+ }
2880
+ stackIndex = lastPoint.stackIndex + 1;
2881
+ }
2882
+ point.stackIndex = stackIndex; // #3639
2883
+ });
2884
+
2885
+
2886
+ }
2887
+ };
2888
+ return onSeriesMixin;
2889
+ }(Highcharts));
2890
+ (function(H, onSeriesMixin) {
2891
+ /**
2892
+ * (c) 2010-2017 Torstein Honsi
2893
+ *
2894
+ * License: www.highcharts.com/license
2895
+ */
2896
+ var addEvent = H.addEvent,
2897
+ each = H.each,
2898
+ merge = H.merge,
2899
+ noop = H.noop,
2900
+ Renderer = H.Renderer,
2901
+ Series = H.Series,
2902
+ seriesType = H.seriesType,
2903
+ SVGRenderer = H.SVGRenderer,
2904
+ TrackerMixin = H.TrackerMixin,
2905
+ VMLRenderer = H.VMLRenderer,
2906
+ symbols = SVGRenderer.prototype.symbols;
2907
+
2908
+ /**
2909
+ * The Flags series.
2910
+ * @constructor seriesTypes.flags
2911
+ * @augments seriesTypes.column
2912
+ */
2913
+ /**
2914
+ * Flags are used to mark events in stock charts. They can be added on the
2915
+ * timeline, or attached to a specific series.
2916
+ *
2917
+ * @sample stock/demo/flags-general/ Flags on a line series
2918
+ * @extends {plotOptions.column}
2919
+ * @excluding animation,borderColor,borderRadius,borderWidth,colorByPoint,dataGrouping,pointPadding,pointWidth,turboThreshold
2920
+ * @product highstock
2921
+ * @optionparent plotOptions.flags
2922
+ */
2923
+ seriesType('flags', 'column', {
2924
+
2925
+ /**
2926
+ * In case the flag is placed on a series, on what point key to place
2927
+ * it. Line and columns have one key, `y`. In range or OHLC-type series,
2928
+ * however, the flag can optionally be placed on the `open`, `high`,
2929
+ * `low` or `close` key.
2930
+ *
2931
+ * @validvalue ["y", "open", "high", "low", "close"]
2932
+ * @type {String}
2933
+ * @sample {highstock} stock/plotoptions/flags-onkey/ Range series, flag on high
2934
+ * @default y
2935
+ * @since 4.2.2
2936
+ * @product highstock
2937
+ * @apioption plotOptions.flags.onKey
2938
+ */
2939
+
2940
+ /**
2941
+ * The id of the series that the flags should be drawn on. If no id
2942
+ * is given, the flags are drawn on the x axis.
2943
+ *
2944
+ * @type {String}
2945
+ * @sample {highstock} stock/plotoptions/flags/ Flags on series and on x axis
2946
+ * @default undefined
2947
+ * @product highstock
2948
+ * @apioption plotOptions.flags.onSeries
2949
+ */
2950
+
2951
+ pointRange: 0, // #673
2952
+
2953
+ /**
2954
+ * The shape of the marker. Can be one of "flag", "circlepin", "squarepin",
2955
+ * or an image on the format `url(/path-to-image.jpg)`. Individual
2956
+ * shapes can also be set for each point.
2957
+ *
2958
+ * @validvalue ["flag", "circlepin", "squarepin"]
2959
+ * @type {String}
2960
+ * @sample {highstock} stock/plotoptions/flags/ Different shapes
2961
+ * @default flag
2962
+ * @product highstock
2963
+ */
2964
+ shape: 'flag',
2965
+
2966
+ /**
2967
+ * When multiple flags in the same series fall on the same value, this
2968
+ * number determines the vertical offset between them.
2969
+ *
2970
+ * @type {Number}
2971
+ * @sample {highstock} stock/plotoptions/flags-stackdistance/ A greater stack distance
2972
+ * @default 12
2973
+ * @product highstock
2974
+ */
2975
+ stackDistance: 12,
2976
+
2977
+ /**
2344
2978
  * Text alignment for the text inside the flag.
2345
2979
  *
2346
2980
  * @validvalue ["left", "center", "right"]
@@ -2363,15 +2997,20 @@
2363
2997
  * @product highstock
2364
2998
  */
2365
2999
  tooltip: {
2366
-
2367
- /**
2368
- */
2369
3000
  pointFormat: '{point.text}<br/>'
2370
3001
  },
2371
3002
 
3003
+ threshold: null,
3004
+
2372
3005
  /**
3006
+ * The text to display on each flag. This can be defined on series level,
3007
+ * or individually for each point. Defaults to `"A"`.
3008
+ *
3009
+ * @type {String}
3010
+ * @default "A"
3011
+ * @product highstock
3012
+ * @apioption plotOptions.flags.title
2373
3013
  */
2374
- threshold: null,
2375
3014
 
2376
3015
  /**
2377
3016
  * The y position of the top left corner of the flag relative to either
@@ -2384,14 +3023,40 @@
2384
3023
  */
2385
3024
  y: -30,
2386
3025
 
3026
+ /**
3027
+ * Whether to use HTML to render the flag texts. Using HTML allows for
3028
+ * advanced formatting, images and reliable bi-directional text rendering.
3029
+ * Note that exported images won't respect the HTML, and that HTML
3030
+ * won't respect Z-index settings.
3031
+ *
3032
+ * @type {Boolean}
3033
+ * @default false
3034
+ * @since 1.3
3035
+ * @product highstock
3036
+ * @apioption plotOptions.flags.useHTML
3037
+ */
3038
+
3039
+
2387
3040
 
2388
3041
  /**
3042
+ * The fill color for the flags.
2389
3043
  */
2390
3044
  fillColor: '#ffffff',
2391
- // lineColor: color,
2392
3045
 
2393
3046
  /**
2394
- * The pixel width of the candlestick line/border. Defaults to `1`.
3047
+ * The color of the line/border of the flag.
3048
+ *
3049
+ * In styled mode, the stroke is set in the `.highcharts-flag-series
3050
+ * .highcharts-point` rule.
3051
+ *
3052
+ * @type {Color}
3053
+ * @default #000000
3054
+ * @product highstock
3055
+ * @apioption plotOptions.flags.lineColor
3056
+ */
3057
+
3058
+ /**
3059
+ * The pixel width of the flag's line/border.
2395
3060
  *
2396
3061
  * @type {Number}
2397
3062
  * @default 1
@@ -2399,8 +3064,6 @@
2399
3064
  */
2400
3065
  lineWidth: 1,
2401
3066
 
2402
- /**
2403
- */
2404
3067
  states: {
2405
3068
 
2406
3069
  /**
@@ -2410,7 +3073,7 @@
2410
3073
  hover: {
2411
3074
 
2412
3075
  /**
2413
- * The color of the line/border of the flag Defaults to `"black"`.
3076
+ * The color of the line/border of the flag.
2414
3077
  *
2415
3078
  * @type {String}
2416
3079
  * @default "black"
@@ -2419,7 +3082,7 @@
2419
3082
  lineColor: '#000000',
2420
3083
 
2421
3084
  /**
2422
- * The fill or background color of the flag Defaults to `"#FCFFC5"`.
3085
+ * The fill or background color of the flag.
2423
3086
  *
2424
3087
  * @type {String}
2425
3088
  * @default "#FCFFC5"
@@ -2432,8 +3095,7 @@
2432
3095
  /**
2433
3096
  * The text styles of the flag.
2434
3097
  *
2435
- * In [styled mode](http://www.highcharts.com/docs/chart-design-and-
2436
- * style/style-by-css), the styles are set in the `.highcharts-flag-
3098
+ * In styled mode, the styles are set in the `.highcharts-flag-
2437
3099
  * series .highcharts-point` rule.
2438
3100
  *
2439
3101
  * @type {CSSObject}
@@ -2441,13 +3103,7 @@
2441
3103
  * @product highstock
2442
3104
  */
2443
3105
  style: {
2444
-
2445
- /**
2446
- */
2447
3106
  fontSize: '11px',
2448
-
2449
- /**
2450
- */
2451
3107
  fontWeight: 'bold'
2452
3108
  }
2453
3109
 
@@ -2489,107 +3145,7 @@
2489
3145
  },
2490
3146
 
2491
3147
 
2492
- /**
2493
- * Extend the translate method by placing the point on the related series
2494
- */
2495
- translate: function() {
2496
-
2497
- seriesTypes.column.prototype.translate.apply(this);
2498
-
2499
- var series = this,
2500
- options = series.options,
2501
- chart = series.chart,
2502
- points = series.points,
2503
- cursor = points.length - 1,
2504
- point,
2505
- lastPoint,
2506
- optionsOnSeries = options.onSeries,
2507
- onSeries = optionsOnSeries && chart.get(optionsOnSeries),
2508
- onKey = options.onKey || 'y',
2509
- step = onSeries && onSeries.options.step,
2510
- onData = onSeries && onSeries.points,
2511
- i = onData && onData.length,
2512
- xAxis = series.xAxis,
2513
- yAxis = series.yAxis,
2514
- xAxisExt = xAxis.getExtremes(),
2515
- xOffset = 0,
2516
- leftPoint,
2517
- lastX,
2518
- rightPoint,
2519
- currentDataGrouping;
2520
-
2521
- // relate to a master series
2522
- if (onSeries && onSeries.visible && i) {
2523
- xOffset = (onSeries.pointXOffset || 0) + (onSeries.barW || 0) / 2;
2524
- currentDataGrouping = onSeries.currentDataGrouping;
2525
- lastX = onData[i - 1].x + (currentDataGrouping ? currentDataGrouping.totalRange : 0); // #2374
2526
-
2527
- // sort the data points
2528
- stableSort(points, function(a, b) {
2529
- return (a.x - b.x);
2530
- });
2531
-
2532
- onKey = 'plot' + onKey[0].toUpperCase() + onKey.substr(1);
2533
- while (i-- && points[cursor]) {
2534
- point = points[cursor];
2535
- leftPoint = onData[i];
2536
- if (leftPoint.x <= point.x && leftPoint[onKey] !== undefined) {
2537
- if (point.x <= lastX) { // #803
2538
-
2539
- point.plotY = leftPoint[onKey];
2540
-
2541
- // interpolate between points, #666
2542
- if (leftPoint.x < point.x && !step) {
2543
- rightPoint = onData[i + 1];
2544
- if (rightPoint && rightPoint[onKey] !== undefined) {
2545
- point.plotY +=
2546
- ((point.x - leftPoint.x) / (rightPoint.x - leftPoint.x)) * // the distance ratio, between 0 and 1
2547
- (rightPoint[onKey] - leftPoint[onKey]); // the y distance
2548
- }
2549
- }
2550
- }
2551
- cursor--;
2552
- i++; // check again for points in the same x position
2553
- if (cursor < 0) {
2554
- break;
2555
- }
2556
- }
2557
- }
2558
- }
2559
-
2560
- // Add plotY position and handle stacking
2561
- each(points, function(point, i) {
2562
-
2563
- var stackIndex;
2564
-
2565
- // Undefined plotY means the point is either on axis, outside series
2566
- // range or hidden series. If the series is outside the range of the
2567
- // x axis it should fall through with an undefined plotY, but then
2568
- // we must remove the shapeArgs (#847).
2569
- if (point.plotY === undefined) {
2570
- if (point.x >= xAxisExt.min && point.x <= xAxisExt.max) {
2571
- // we're inside xAxis range
2572
- point.plotY = chart.chartHeight - xAxis.bottom -
2573
- (xAxis.opposite ? xAxis.height : 0) +
2574
- xAxis.offset - yAxis.top; // #3517
2575
- } else {
2576
- point.shapeArgs = {}; // 847
2577
- }
2578
- }
2579
- point.plotX += xOffset; // #2049
2580
- // if multiple flags appear at the same x, order them into a stack
2581
- lastPoint = points[i - 1];
2582
- if (lastPoint && lastPoint.plotX === point.plotX) {
2583
- if (lastPoint.stackIndex === undefined) {
2584
- lastPoint.stackIndex = 0;
2585
- }
2586
- stackIndex = lastPoint.stackIndex + 1;
2587
- }
2588
- point.stackIndex = stackIndex; // #3639
2589
- });
2590
-
2591
-
2592
- },
3148
+ translate: onSeriesMixin.translate,
2593
3149
 
2594
3150
  /**
2595
3151
  * Draw the markers
@@ -2799,11 +3355,77 @@
2799
3355
  });
2800
3356
  }
2801
3357
 
2802
- /* ****************************************************************************
2803
- * End Flags series code *
2804
- *****************************************************************************/
2805
3358
 
2806
- }(Highcharts));
3359
+ /**
3360
+ * A `flags` series. If the [type](#series.flags.type) option is not
3361
+ * specified, it is inherited from [chart.type](#chart.type).
3362
+ *
3363
+ * For options that apply to multiple series, it is recommended to add
3364
+ * them to the [plotOptions.series](#plotOptions.series) options structure.
3365
+ * To apply to all series of this specific type, apply it to [plotOptions.
3366
+ * flags](#plotOptions.flags).
3367
+ *
3368
+ * @type {Object}
3369
+ * @extends series,plotOptions.flags
3370
+ * @excluding dataParser,dataURL
3371
+ * @product highstock
3372
+ * @apioption series.flags
3373
+ */
3374
+
3375
+ /**
3376
+ * An array of data points for the series. For the `flags` series type,
3377
+ * points can be given in the following ways:
3378
+ *
3379
+ * 1. An array of objects with named values. The objects are point
3380
+ * configuration objects as seen below. If the total number of data
3381
+ * points exceeds the series' [turboThreshold](#series.flags.turboThreshold),
3382
+ * this option is not available.
3383
+ *
3384
+ * ```js
3385
+ * data: [{
3386
+ * x: 1,
3387
+ * title: "A",
3388
+ * text: "First event"
3389
+ * }, {
3390
+ * x: 1,
3391
+ * title: "B",
3392
+ * text: "Second event"
3393
+ * }]</pre>
3394
+ *
3395
+ * @type {Array<Object>}
3396
+ * @extends series.line.data
3397
+ * @excluding y,dataLabels,marker,name
3398
+ * @product highstock
3399
+ * @apioption series.flags.data
3400
+ */
3401
+
3402
+ /**
3403
+ * The fill color of an individual flag. By default it inherits from
3404
+ * the series color.
3405
+ *
3406
+ * @type {Color}
3407
+ * @product highstock
3408
+ * @apioption series.flags.data.fillColor
3409
+ */
3410
+
3411
+ /**
3412
+ * The longer text to be shown in the flag's tooltip.
3413
+ *
3414
+ * @type {String}
3415
+ * @product highstock
3416
+ * @apioption series.flags.data.text
3417
+ */
3418
+
3419
+ /**
3420
+ * The short text to be shown on the flag.
3421
+ *
3422
+ * @type {String}
3423
+ * @product highstock
3424
+ * @apioption series.flags.data.title
3425
+ */
3426
+
3427
+
3428
+ }(Highcharts, onSeriesMixin));
2807
3429
  (function(H) {
2808
3430
  /**
2809
3431
  * (c) 2010-2017 Torstein Honsi
@@ -2829,20 +3451,17 @@
2829
3451
 
2830
3452
  /**
2831
3453
  *
2832
- * The scrollbar is a means of panning over the X axis of a chart.
3454
+ * The scrollbar is a means of panning over the X axis of a stock chart.
2833
3455
  *
2834
- * In [styled mode](http://www.highcharts.com/docs/chart-design-
2835
- * and-style/style-by-css), all the presentational options for the
2836
- * scrollbar are replaced by the classes `.highcharts-scrollbar-
2837
- * thumb`, `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-
2838
- * button`, `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-
2839
- * track`.
3456
+ * In styled mode, all the presentational options for the
3457
+ * scrollbar are replaced by the classes `.highcharts-scrollbar-thumb`,
3458
+ * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
3459
+ * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
2840
3460
  *
2841
3461
  * @product highstock
2842
3462
  * @optionparent scrollbar
2843
3463
  */
2844
3464
  var defaultScrollbarOptions = {
2845
- //enabled: true
2846
3465
 
2847
3466
  /**
2848
3467
  * The height of the scrollbar. The height also applies to the width
@@ -2854,7 +3473,6 @@
2854
3473
  * @product highstock
2855
3474
  */
2856
3475
  height: isTouchDevice ? 20 : 14,
2857
- // trackBorderRadius: 0
2858
3476
 
2859
3477
  /**
2860
3478
  * The border rounding radius of the bar.
@@ -2888,6 +3506,8 @@
2888
3506
  liveRedraw: svg && !isTouchDevice,
2889
3507
 
2890
3508
  /**
3509
+ * The margin between the scrollbar and its axis when the scrollbar is
3510
+ * applied directly to an axis.
2891
3511
  */
2892
3512
  margin: 10,
2893
3513
 
@@ -2900,14 +3520,11 @@
2900
3520
  * @product highstock
2901
3521
  */
2902
3522
  minWidth: 6,
2903
- //showFull: true,
2904
- //size: null,
2905
3523
 
2906
- /**
2907
- */
2908
3524
  step: 0.2,
2909
3525
 
2910
3526
  /**
3527
+ * The z index of the scrollbar group.
2911
3528
  */
2912
3529
  zIndex: 3,
2913
3530
 
@@ -3735,9 +4352,38 @@
3735
4352
  *
3736
4353
  * License: www.highcharts.com/license
3737
4354
  */
3738
- /* ****************************************************************************
3739
- * Start Navigator code *
3740
- *****************************************************************************/
4355
+ /* eslint max-len: ["warn", 80, 4] */
4356
+
4357
+ /**
4358
+ * Options for the corresponding navigator series if `showInNavigator`
4359
+ * is `true` for this series. Available options are the same as any
4360
+ * series, documented at [plotOptions](#plotOptions.series) and
4361
+ * [series](#series).
4362
+ *
4363
+ *
4364
+ * These options are merged with options in [navigator.series](#navigator.
4365
+ * series), and will take precedence if the same option is defined both
4366
+ * places.
4367
+ *
4368
+ * @type {Object}
4369
+ * @see [navigator.series](#navigator.series)
4370
+ * @default undefined
4371
+ * @since 5.0.0
4372
+ * @product highstock
4373
+ * @apioption plotOptions.series.navigatorOptions
4374
+ */
4375
+
4376
+ /**
4377
+ * Whether or not to show the series in the navigator. Takes precedence
4378
+ * over [navigator.baseSeries](#navigator.baseSeries) if defined.
4379
+ *
4380
+ * @type {Boolean}
4381
+ * @default undefined
4382
+ * @since 5.0.0
4383
+ * @product highstock
4384
+ * @apioption plotOptions.series.showInNavigator
4385
+ */
4386
+
3741
4387
  var addEvent = H.addEvent,
3742
4388
  Axis = H.Axis,
3743
4389
  Chart = H.Chart,
@@ -3762,14 +4408,13 @@
3762
4408
  Series = H.Series,
3763
4409
  seriesTypes = H.seriesTypes,
3764
4410
  wrap = H.wrap,
3765
- swapXY = H.swapXY,
3766
4411
 
3767
4412
  units = [].concat(defaultDataGroupingUnits), // copy
3768
4413
  defaultSeriesType,
3769
4414
 
3770
- // Finding the min or max of a set of variables where we don't know if they are defined,
3771
- // is a pattern that is repeated several places in Highcharts. Consider making this
3772
- // a global utility method.
4415
+ // Finding the min or max of a set of variables where we don't know if they
4416
+ // are defined, is a pattern that is repeated several places in Highcharts.
4417
+ // Consider making this a global utility method.
3773
4418
  numExt = function(extreme) {
3774
4419
  var numbers = grep(arguments, isNumber);
3775
4420
  if (numbers.length) {
@@ -3781,7 +4426,9 @@
3781
4426
  units[4] = ['day', [1, 2, 3, 4]]; // allow more days
3782
4427
  units[5] = ['week', [1, 2, 3]]; // allow more weeks
3783
4428
 
3784
- defaultSeriesType = seriesTypes.areaspline === undefined ? 'line' : 'areaspline';
4429
+ defaultSeriesType = seriesTypes.areaspline === undefined ?
4430
+ 'line' :
4431
+ 'areaspline';
3785
4432
 
3786
4433
  extend(defaultOptions, {
3787
4434
 
@@ -3790,15 +4437,13 @@
3790
4437
  * a view of the entire data set. It provides tools to zoom in and
3791
4438
  * out on parts of the data as well as panning across the dataset.
3792
4439
  *
3793
- * @optionparent navigator
3794
4440
  * @product highstock
4441
+ * @optionparent navigator
3795
4442
  */
3796
4443
  navigator: {
3797
- //enabled: true,
3798
-
3799
4444
  /**
3800
4445
  * The height of the navigator.
3801
- *
4446
+ *
3802
4447
  * @type {Number}
3803
4448
  * @sample {highstock} stock/navigator/height/ A higher navigator
3804
4449
  * @default 40
@@ -3808,9 +4453,10 @@
3808
4453
 
3809
4454
  /**
3810
4455
  * The distance from the nearest element, the X axis or X axis labels.
3811
- *
4456
+ *
3812
4457
  * @type {Number}
3813
- * @sample {highstock} stock/navigator/margin/ A margin of 2 draws the navigator closer to the X axis labels
4458
+ * @sample {highstock} stock/navigator/margin/
4459
+ * A margin of 2 draws the navigator closer to the X axis labels
3814
4460
  * @default 25
3815
4461
  * @product highstock
3816
4462
  */
@@ -3819,57 +4465,125 @@
3819
4465
  /**
3820
4466
  * Whether the mask should be inside the range marking the zoomed
3821
4467
  * range, or outside. In Highstock 1.x it was always `false`.
3822
- *
4468
+ *
3823
4469
  * @type {Boolean}
3824
- * @sample {highstock} stock/navigator/maskinside-false/ False, mask outside
4470
+ * @sample {highstock} stock/navigator/maskinside-false/
4471
+ * False, mask outside
3825
4472
  * @default true
3826
4473
  * @since 2.0
3827
4474
  * @product highstock
3828
4475
  */
3829
4476
  maskInside: true,
3830
4477
 
3831
-
3832
4478
  /**
3833
- * Options for the handles for dragging the zoomed area. Available
3834
- * options are `backgroundColor` (defaults to `#ebe7e8`) and `borderColor`
3835
- * (defaults to `#b2b1b6`).
3836
- *
4479
+ * Options for the handles for dragging the zoomed area.
4480
+ *
3837
4481
  * @type {Object}
3838
4482
  * @sample {highstock} stock/navigator/handles/ Colored handles
3839
- * @sample {highstock} stock/navigator/handles/ Colored handles
3840
4483
  * @product highstock
3841
4484
  */
3842
4485
  handles: {
4486
+ /**
4487
+ * Width for handles.
4488
+ *
4489
+ * @type {umber}
4490
+ * @default 7
4491
+ * @product highstock
4492
+ * @sample {highstock} stock/navigator/styled-handles/
4493
+ * Styled handles
4494
+ * @since 6.0.0
4495
+ */
4496
+ width: 7,
4497
+
4498
+ /**
4499
+ * Height for handles.
4500
+ *
4501
+ * @type {Number}
4502
+ * @default 15
4503
+ * @product highstock
4504
+ * @sample {highstock} stock/navigator/styled-handles/
4505
+ * Styled handles
4506
+ * @since 6.0.0
4507
+ */
4508
+ height: 15,
4509
+
4510
+ /**
4511
+ * Array to define shapes of handles. 0-index for left, 1-index for
4512
+ * right.
4513
+ *
4514
+ * Additionally, the URL to a graphic can be given on this form:
4515
+ * `url(graphic.png)`. Note that for the image to be applied to
4516
+ * exported charts, its URL needs to be accessible by the export
4517
+ * server.
4518
+ *
4519
+ * Custom callbacks for symbol path generation can also be added to
4520
+ * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
4521
+ * used by its method name, as shown in the demo.
4522
+ *
4523
+ * @type {Array}
4524
+ * @default ['navigator-handle', 'navigator-handle']
4525
+ * @product highstock
4526
+ * @sample {highstock} stock/navigator/styled-handles/
4527
+ * Styled handles
4528
+ * @since 6.0.0
4529
+ */
4530
+ symbols: ['navigator-handle', 'navigator-handle'],
4531
+
4532
+ /**
4533
+ * Allows to enable/disable handles.
4534
+ *
4535
+ * @type {Boolean}
4536
+ * @default true
4537
+ * @product highstock
4538
+ * @since 6.0.0
4539
+ */
4540
+ enabled: true,
4541
+
4542
+
4543
+ /**
4544
+ * The width for the handle border and the stripes inside.
4545
+ *
4546
+ * @type {Number}
4547
+ * @default 7
4548
+ * @product highstock
4549
+ * @sample {highstock} stock/navigator/styled-handles/
4550
+ * Styled handles
4551
+ * @since 6.0.0
4552
+ */
4553
+ lineWidth: 1,
3843
4554
 
3844
4555
  /**
3845
4556
  * The fill for the handle.
3846
- *
4557
+ *
3847
4558
  * @type {Color}
3848
- * @default #f2f2f2
3849
4559
  * @product highstock
3850
4560
  */
3851
4561
  backgroundColor: '#f2f2f2',
3852
4562
 
3853
4563
  /**
3854
4564
  * The stroke for the handle border and the stripes inside.
3855
- *
4565
+ *
3856
4566
  * @type {Color}
3857
- * @default #999999
3858
4567
  * @product highstock
3859
4568
  */
3860
4569
  borderColor: '#999999'
4570
+
4571
+
3861
4572
  },
3862
4573
 
4574
+
4575
+
3863
4576
  /**
3864
4577
  * The color of the mask covering the areas of the navigator series
3865
4578
  * that are currently not visible in the main series. The default
3866
4579
  * color is bluish with an opacity of 0.3 to see the series below.
3867
- *
4580
+ *
3868
4581
  * @type {Color}
3869
- * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and-
3870
- * style/style-by-css), the mask is styled with the `.highcharts-navigator-
3871
- * mask` and `.highcharts-navigator-mask-inside` classes.
3872
- * @sample {highstock} stock/navigator/maskfill/ Blue, semi transparent mask
4582
+ * @see In styled mode, the mask is styled with the
4583
+ * `.highcharts-navigator-mask` and
4584
+ * `.highcharts-navigator-mask-inside` classes.
4585
+ * @sample {highstock} stock/navigator/maskfill/
4586
+ * Blue, semi transparent mask
3873
4587
  * @default rgba(102,133,194,0.3)
3874
4588
  * @product highstock
3875
4589
  */
@@ -3878,7 +4592,7 @@
3878
4592
  /**
3879
4593
  * The color of the line marking the currently zoomed area in the
3880
4594
  * navigator.
3881
- *
4595
+ *
3882
4596
  * @type {Color}
3883
4597
  * @sample {highstock} stock/navigator/outline/ 2px blue outline
3884
4598
  * @default #cccccc
@@ -3889,10 +4603,9 @@
3889
4603
  /**
3890
4604
  * The width of the line marking the currently zoomed area in the
3891
4605
  * navigator.
3892
- *
4606
+ *
3893
4607
  * @type {Number}
3894
- * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and-
3895
- * style/style-by-css), the outline stroke width is set with the `.
4608
+ * @see In styled mode, the outline stroke width is set with the `.
3896
4609
  * highcharts-navigator-outline` class.
3897
4610
  * @sample {highstock} stock/navigator/outline/ 2px blue outline
3898
4611
  * @default 2
@@ -3905,299 +4618,258 @@
3905
4618
  * Options for the navigator series. Available options are the same
3906
4619
  * as any series, documented at [plotOptions](#plotOptions.series)
3907
4620
  * and [series](#series).
3908
- *
4621
+ *
3909
4622
  * Unless data is explicitly defined on navigator.series, the data
3910
4623
  * is borrowed from the first series in the chart.
3911
- *
4624
+ *
3912
4625
  * Default series options for the navigator series are:
3913
- *
4626
+ *
3914
4627
  * <pre>series: {
3915
- * type: 'areaspline',
3916
- * color: '#4572A7',
3917
- * fillOpacity: 0.05,
3918
- * dataGrouping: {
3919
- * smoothed: true
3920
- * },
3921
- * lineWidth: 1,
3922
- * marker: {
3923
- * enabled: false
3924
- * }
4628
+ * type: 'areaspline',
4629
+ * fillOpacity: 0.05,
4630
+ * dataGrouping: {
4631
+ * smoothed: true
4632
+ * },
4633
+ * lineWidth: 1,
4634
+ * marker: {
4635
+ * enabled: false
4636
+ * }
3925
4637
  * }</pre>
3926
- *
4638
+ *
3927
4639
  * @type {Object}
3928
- * @see In [styled mode](http://www.highcharts.com/docs/chart-design-and-
3929
- * style/style-by-css), the navigator series is styled with the `.
4640
+ * @see In styled mode, the navigator series is styled with the `.
3930
4641
  * highcharts-navigator-series` class.
3931
- * @sample {highstock} stock/navigator/series-data/ Using a separate data set for the navigator
3932
- * @sample {highstock} stock/navigator/series/ A green navigator series
4642
+ * @sample {highstock} stock/navigator/series-data/
4643
+ * Using a separate data set for the navigator
4644
+ * @sample {highstock} stock/navigator/series/
4645
+ * A green navigator series
3933
4646
  * @product highstock
3934
4647
  */
3935
4648
  series: {
3936
4649
 
3937
4650
  /**
4651
+ * The type of the navigator series. Defaults to `areaspline` if
4652
+ * defined, otherwise `line`.
4653
+ *
4654
+ * @type {String}
3938
4655
  */
3939
4656
  type: defaultSeriesType,
3940
4657
 
3941
4658
 
3942
- /**
3943
- */
3944
- color: '#335cad',
3945
4659
 
3946
4660
  /**
4661
+ * The fill opacity of the navigator series.
3947
4662
  */
3948
4663
  fillOpacity: 0.05,
3949
4664
 
3950
4665
  /**
4666
+ * The pixel line width of the navigator series.
3951
4667
  */
3952
4668
  lineWidth: 1,
3953
4669
 
3954
4670
 
3955
4671
  /**
4672
+ * @ignore
3956
4673
  */
3957
4674
  compare: null,
3958
4675
 
3959
4676
  /**
4677
+ * Data grouping options for the navigator series.
4678
+ *
4679
+ * @extends {plotOptions.series.dataGrouping}
3960
4680
  */
3961
4681
  dataGrouping: {
3962
-
3963
- /**
3964
- */
3965
4682
  approximation: 'average',
3966
-
3967
- /**
3968
- */
3969
4683
  enabled: true,
3970
-
3971
- /**
3972
- */
3973
4684
  groupPixelWidth: 2,
3974
-
3975
- /**
3976
- */
3977
4685
  smoothed: true,
3978
-
3979
- /**
3980
- */
3981
4686
  units: units
3982
4687
  },
3983
4688
 
3984
4689
  /**
4690
+ * Data label options for the navigator series. Data labels are
4691
+ * disabled by default on the navigator series.
4692
+ *
4693
+ * @extends {plotOptions.series.dataLabels}
3985
4694
  */
3986
4695
  dataLabels: {
3987
-
3988
- /**
3989
- */
3990
4696
  enabled: false,
3991
-
3992
- /**
3993
- */
3994
4697
  zIndex: 2 // #1839
3995
4698
  },
3996
4699
 
3997
- /**
3998
- */
3999
4700
  id: 'highcharts-navigator-series',
4000
-
4001
- /**
4002
- */
4003
4701
  className: 'highcharts-navigator-series',
4004
4702
 
4005
4703
  /**
4704
+ * Line color for the navigator series. Allows setting the color
4705
+ * while disallowing the default candlestick setting.
4706
+ *
4707
+ * @type {Color}
4006
4708
  */
4007
- lineColor: null, // Allow color setting while disallowing default candlestick setting (#4602)
4709
+ lineColor: null, // #4602
4008
4710
 
4009
- /**
4010
- */
4011
4711
  marker: {
4012
-
4013
- /**
4014
- */
4015
4712
  enabled: false
4016
4713
  },
4017
4714
 
4018
- /**
4019
- */
4020
4715
  pointRange: 0,
4021
-
4022
- /**
4023
- */
4024
- shadow: false,
4025
-
4026
4716
  /**
4717
+ * The threshold option. Setting it to 0 will make the default
4718
+ * navigator area series draw its area from the 0 value and up.
4719
+ * @type {Number}
4027
4720
  */
4028
4721
  threshold: null
4029
4722
  },
4030
- //top: undefined,
4031
- //opposite: undefined,
4032
4723
 
4033
4724
  /**
4034
- * Options for the navigator X axis. Available options are the same
4035
- * as any X axis, documented at [xAxis](#xAxis). Default series options
4725
+ * Options for the navigator X axis. Default series options
4036
4726
  * for the navigator xAxis are:
4037
- *
4727
+ *
4038
4728
  * <pre>xAxis: {
4039
- * tickWidth: 0,
4040
- * lineWidth: 0,
4041
- * gridLineWidth: 1,
4042
- * tickPixelInterval: 200,
4043
- * labels: {
4044
- * align: 'left',
4045
- * style: {
4046
- * color: '#888'
4047
- * },
4048
- * x: 3,
4049
- * y: -4
4050
- * }
4729
+ * tickWidth: 0,
4730
+ * lineWidth: 0,
4731
+ * gridLineWidth: 1,
4732
+ * tickPixelInterval: 200,
4733
+ * labels: {
4734
+ * align: 'left',
4735
+ * style: {
4736
+ * color: '#888'
4737
+ * },
4738
+ * x: 3,
4739
+ * y: -4
4740
+ * }
4051
4741
  * }</pre>
4052
- *
4742
+ *
4053
4743
  * @type {Object}
4744
+ * @extends {xAxis}
4745
+ * @excluding linkedTo,maxZoom,minRange,opposite,range,scrollbar,
4746
+ * showEmpty,maxRange
4054
4747
  * @product highstock
4055
4748
  */
4056
4749
  xAxis: {
4057
-
4058
4750
  /**
4751
+ * Additional range on the right side of the xAxis. Works similar to
4752
+ * xAxis.maxPadding, but value is set in milliseconds.
4753
+ * Can be set for both, main xAxis and navigator's xAxis.
4754
+ *
4755
+ * @type {Number}
4756
+ * @default 0
4757
+ * @since 6.0.0
4758
+ * @product highstock
4759
+ * @apioption xAxis.overscroll
4059
4760
  */
4060
- className: 'highcharts-navigator-xaxis',
4761
+ overscroll: 0,
4061
4762
 
4062
- /**
4063
- */
4763
+ className: 'highcharts-navigator-xaxis',
4064
4764
  tickLength: 0,
4065
4765
 
4066
4766
 
4067
- /**
4068
- */
4069
4767
  lineWidth: 0,
4070
-
4071
- /**
4072
- */
4073
4768
  gridLineColor: '#e6e6e6',
4074
-
4075
- /**
4076
- */
4077
4769
  gridLineWidth: 1,
4078
4770
 
4079
4771
 
4080
- /**
4081
- */
4082
4772
  tickPixelInterval: 200,
4083
4773
 
4084
- /**
4085
- */
4086
4774
  labels: {
4087
-
4088
- /**
4089
- */
4090
4775
  align: 'left',
4091
4776
 
4092
4777
 
4093
- /**
4094
- */
4095
4778
  style: {
4096
-
4097
- /**
4098
- */
4099
4779
  color: '#999999'
4100
4780
  },
4101
4781
 
4102
4782
 
4103
- /**
4104
- */
4105
4783
  x: 3,
4106
-
4107
- /**
4108
- */
4109
4784
  y: -4
4110
4785
  },
4111
4786
 
4112
- /**
4113
- */
4114
4787
  crosshair: false
4115
4788
  },
4116
4789
 
4117
4790
  /**
4118
- * Options for the navigator Y axis. Available options are the same
4119
- * as any y axis, documented at [yAxis](#yAxis). Default series options
4791
+ * Options for the navigator Y axis. Default series options
4120
4792
  * for the navigator yAxis are:
4121
- *
4793
+ *
4122
4794
  * <pre>yAxis: {
4123
- * gridLineWidth: 0,
4124
- * startOnTick: false,
4125
- * endOnTick: false,
4126
- * minPadding: 0.1,
4127
- * maxPadding: 0.1,
4128
- * labels: {
4129
- * enabled: false
4130
- * },
4131
- * title: {
4132
- * text: null
4133
- * },
4134
- * tickWidth: 0
4795
+ * gridLineWidth: 0,
4796
+ * startOnTick: false,
4797
+ * endOnTick: false,
4798
+ * minPadding: 0.1,
4799
+ * maxPadding: 0.1,
4800
+ * labels: {
4801
+ * enabled: false
4802
+ * },
4803
+ * title: {
4804
+ * text: null
4805
+ * },
4806
+ * tickWidth: 0
4135
4807
  * }</pre>
4136
- *
4808
+ *
4137
4809
  * @type {Object}
4810
+ * @extends {yAxis}
4811
+ * @excluding height,linkedTo,maxZoom,minRange,ordinal,range,showEmpty,
4812
+ * scrollbar,top,units,maxRange
4138
4813
  * @product highstock
4139
4814
  */
4140
4815
  yAxis: {
4141
4816
 
4142
- /**
4143
- */
4144
4817
  className: 'highcharts-navigator-yaxis',
4145
4818
 
4146
4819
 
4147
- /**
4148
- */
4149
4820
  gridLineWidth: 0,
4150
4821
 
4151
4822
 
4152
- /**
4153
- */
4154
4823
  startOnTick: false,
4155
-
4156
- /**
4157
- */
4158
4824
  endOnTick: false,
4159
-
4160
- /**
4161
- */
4162
4825
  minPadding: 0.1,
4163
-
4164
- /**
4165
- */
4166
4826
  maxPadding: 0.1,
4167
-
4168
- /**
4169
- */
4170
4827
  labels: {
4171
-
4172
- /**
4173
- */
4174
4828
  enabled: false
4175
4829
  },
4176
-
4177
- /**
4178
- */
4179
4830
  crosshair: false,
4180
-
4181
- /**
4182
- */
4183
4831
  title: {
4184
-
4185
- /**
4186
- */
4187
4832
  text: null
4188
4833
  },
4189
-
4190
- /**
4191
- */
4192
4834
  tickLength: 0,
4193
-
4194
- /**
4195
- */
4196
4835
  tickWidth: 0
4197
4836
  }
4198
4837
  }
4199
4838
  });
4200
4839
 
4840
+ /**
4841
+ * Draw one of the handles on the side of the zoomed range in the navigator
4842
+ * @param {Boolean} inverted flag for chart.inverted
4843
+ * @returns {Array} Path to be used in a handle
4844
+ */
4845
+ H.Renderer.prototype.symbols['navigator-handle'] = function(
4846
+ x,
4847
+ y,
4848
+ w,
4849
+ h,
4850
+ options
4851
+ ) {
4852
+ var halfWidth = options.width / 2,
4853
+ markerPosition = Math.round(halfWidth / 3) + 0.5,
4854
+ height = options.height;
4855
+
4856
+ return [
4857
+ 'M', -halfWidth - 1, 0.5,
4858
+ 'L',
4859
+ halfWidth, 0.5,
4860
+ 'L',
4861
+ halfWidth, height + 0.5,
4862
+ 'L', -halfWidth - 1, height + 0.5,
4863
+ 'L', -halfWidth - 1, 0.5,
4864
+ 'M', -markerPosition, 4,
4865
+ 'L', -markerPosition, height - 3,
4866
+ 'M',
4867
+ markerPosition - 1, 4,
4868
+ 'L',
4869
+ markerPosition - 1, height - 3
4870
+ ];
4871
+ };
4872
+
4201
4873
  /**
4202
4874
  * The Navigator class
4203
4875
  * @param {Object} chart - Chart object
@@ -4216,40 +4888,23 @@
4216
4888
  * @param {String} verb use 'animate' or 'attr'
4217
4889
  */
4218
4890
  drawHandle: function(x, index, inverted, verb) {
4219
- var navigator = this;
4891
+ var navigator = this,
4892
+ height = navigator.navigatorOptions.handles.height;
4220
4893
 
4221
4894
  // Place it
4222
4895
  navigator.handles[index][verb](inverted ? {
4223
- translateX: Math.round(navigator.left + navigator.height / 2 - 8),
4224
- translateY: Math.round(navigator.top + parseInt(x, 10) + 0.5)
4896
+ translateX: Math.round(navigator.left + navigator.height / 2),
4897
+ translateY: Math.round(
4898
+ navigator.top + parseInt(x, 10) + 0.5 - height
4899
+ )
4225
4900
  } : {
4226
4901
  translateX: Math.round(navigator.left + parseInt(x, 10)),
4227
- translateY: Math.round(navigator.top + navigator.height / 2 - 8)
4902
+ translateY: Math.round(
4903
+ navigator.top + navigator.height / 2 - height / 2 - 1
4904
+ )
4228
4905
  });
4229
4906
  },
4230
4907
 
4231
- /**
4232
- * Draw one of the handles on the side of the zoomed range in the navigator
4233
- * @param {Boolean} inverted flag for chart.inverted
4234
- * @returns {Array} Path to be used in a handle
4235
- */
4236
- getHandlePath: function(inverted) {
4237
- return swapXY([
4238
- 'M', -4.5, 0.5,
4239
- 'L',
4240
- 3.5, 0.5,
4241
- 'L',
4242
- 3.5, 15.5,
4243
- 'L', -4.5, 15.5,
4244
- 'L', -4.5, 0.5,
4245
- 'M', -1.5, 4,
4246
- 'L', -1.5, 12,
4247
- 'M',
4248
- 0.5, 4,
4249
- 'L',
4250
- 0.5, 12
4251
- ], inverted);
4252
- },
4253
4908
  /**
4254
4909
  * Render outline around the zoomed range
4255
4910
  * @param {Number} zoomedMin in pixels position where zoomed range starts
@@ -4358,7 +5013,7 @@
4358
5013
  x,
4359
5014
  y;
4360
5015
 
4361
- // Determine rectangle position & size
5016
+ // Determine rectangle position & size
4362
5017
  // According to (non)inverted position:
4363
5018
  if (inverted) {
4364
5019
  x = [left, left, left];
@@ -4446,29 +5101,38 @@
4446
5101
  .add(navigatorGroup);
4447
5102
 
4448
5103
  // Create the handlers:
4449
- each([0, 1], function(index) {
4450
- navigator.handles[index] = renderer
4451
- .path(navigator.getHandlePath(inverted))
5104
+ if (navigatorOptions.handles.enabled) {
5105
+ each([0, 1], function(index) {
5106
+ navigatorOptions.handles.inverted = chart.inverted;
5107
+ navigator.handles[index] = renderer.symbol(
5108
+ navigatorOptions.handles.symbols[index], -navigatorOptions.handles.width / 2 - 1,
5109
+ 0,
5110
+ navigatorOptions.handles.width,
5111
+ navigatorOptions.handles.height,
5112
+ navigatorOptions.handles
5113
+ );
4452
5114
  // zIndex = 6 for right handle, 7 for left.
4453
5115
  // Can't be 10, because of the tooltip in inverted chart #2908
4454
- .attr({
4455
- zIndex: 7 - index
4456
- })
4457
- .addClass(
4458
- 'highcharts-navigator-handle highcharts-navigator-handle-' + ['left', 'right'][index]
4459
- ).add(navigatorGroup);
5116
+ navigator.handles[index].attr({
5117
+ zIndex: 7 - index
5118
+ })
5119
+ .addClass(
5120
+ 'highcharts-navigator-handle ' +
5121
+ 'highcharts-navigator-handle-' + ['left', 'right'][index]
5122
+ ).add(navigatorGroup);
4460
5123
 
4461
5124
 
4462
- var handlesOptions = navigatorOptions.handles;
4463
- navigator.handles[index]
4464
- .attr({
4465
- fill: handlesOptions.backgroundColor,
4466
- stroke: handlesOptions.borderColor,
4467
- 'stroke-width': 1
4468
- })
4469
- .css(mouseCursor);
5125
+ var handlesOptions = navigatorOptions.handles;
5126
+ navigator.handles[index]
5127
+ .attr({
5128
+ fill: handlesOptions.backgroundColor,
5129
+ stroke: handlesOptions.borderColor,
5130
+ 'stroke-width': handlesOptions.lineWidth
5131
+ })
5132
+ .css(mouseCursor);
4470
5133
 
4471
- });
5134
+ });
5135
+ }
4472
5136
  },
4473
5137
 
4474
5138
  /**
@@ -4514,7 +5178,9 @@
4514
5178
  verb,
4515
5179
  newMin,
4516
5180
  newMax,
4517
- minRange = chart.xAxis[0].minRange;
5181
+ currentRange,
5182
+ minRange = chart.xAxis[0].minRange,
5183
+ maxRange = chart.xAxis[0].options.maxRange;
4518
5184
 
4519
5185
  // Don't redraw while moving the handles (#4703).
4520
5186
  if (this.hasDragged && !defined(pxMin)) {
@@ -4541,7 +5207,8 @@
4541
5207
 
4542
5208
  navigator.size = zoomedMax = navigatorSize = pick(
4543
5209
  xAxis.len,
4544
- (inverted ? chart.plotHeight : chart.plotWidth) - 2 * scrollbarHeight
5210
+ (inverted ? chart.plotHeight : chart.plotWidth) -
5211
+ 2 * scrollbarHeight
4545
5212
  );
4546
5213
 
4547
5214
  if (inverted) {
@@ -4554,7 +5221,8 @@
4554
5221
  pxMin = pick(pxMin, xAxis.toPixels(min, true));
4555
5222
  pxMax = pick(pxMax, xAxis.toPixels(max, true));
4556
5223
 
4557
- if (!isNumber(pxMin) || Math.abs(pxMin) === Infinity) { // Verify (#1851, #2238)
5224
+ // Verify (#1851, #2238)
5225
+ if (!isNumber(pxMin) || Math.abs(pxMin) === Infinity) {
4558
5226
  pxMin = 0;
4559
5227
  pxMax = navigatorWidth;
4560
5228
  }
@@ -4562,13 +5230,30 @@
4562
5230
  // Are we below the minRange? (#2618, #6191)
4563
5231
  newMin = xAxis.toValue(pxMin, true);
4564
5232
  newMax = xAxis.toValue(pxMax, true);
4565
- if (Math.abs(newMax - newMin) < minRange) {
5233
+ currentRange = Math.abs(H.correctFloat(newMax - newMin));
5234
+ if (currentRange < minRange) {
4566
5235
  if (this.grabbedLeft) {
4567
5236
  pxMin = xAxis.toPixels(newMax - minRange, true);
4568
5237
  } else if (this.grabbedRight) {
4569
5238
  pxMax = xAxis.toPixels(newMin + minRange, true);
4570
- } else {
4571
- return;
5239
+ }
5240
+ } else if (defined(maxRange) && currentRange > maxRange) {
5241
+ /**
5242
+ * Maximum range which can be set using the navigator's handles.
5243
+ * Opposite of [xAxis.minRange](#xAxis.minRange).
5244
+ *
5245
+ * @type {Number}
5246
+ * @default undefined
5247
+ * @product highstock
5248
+ * @sample {highstock} stock/navigator/maxrange/
5249
+ * Defined max and min range
5250
+ * @since 6.0.0
5251
+ * @apioption xAxis.maxRange
5252
+ */
5253
+ if (this.grabbedLeft) {
5254
+ pxMin = xAxis.toPixels(newMax - maxRange, true);
5255
+ } else if (this.grabbedRight) {
5256
+ pxMax = xAxis.toPixels(newMin + maxRange, true);
4572
5257
  }
4573
5258
  }
4574
5259
 
@@ -4598,8 +5283,11 @@
4598
5283
 
4599
5284
  navigator.drawMasks(zoomedMin, zoomedMax, inverted, verb);
4600
5285
  navigator.drawOutline(zoomedMin, zoomedMax, inverted, verb);
4601
- navigator.drawHandle(zoomedMin, 0, inverted, verb);
4602
- navigator.drawHandle(zoomedMax, 1, inverted, verb);
5286
+
5287
+ if (navigator.navigatorOptions.handles.enabled) {
5288
+ navigator.drawHandle(zoomedMin, 0, inverted, verb);
5289
+ navigator.drawHandle(zoomedMax, 1, inverted, verb);
5290
+ }
4603
5291
  }
4604
5292
 
4605
5293
  if (navigator.scrollbar) {
@@ -4627,7 +5315,8 @@
4627
5315
  );
4628
5316
  // Keep scale 0-1
4629
5317
  navigator.scrollbar.setRange(
4630
- // Use real value, not rounded because range can be very small (#1716)
5318
+ // Use real value, not rounded because range can be very small
5319
+ // (#1716)
4631
5320
  navigator.zoomedMin / navigatorSize,
4632
5321
  navigator.zoomedMax / navigatorSize
4633
5322
  );
@@ -4660,7 +5349,8 @@
4660
5349
  // Add shades and handles mousedown events
4661
5350
  eventsToUnbind = navigator.getPartsEvents('mousedown');
4662
5351
  // Add mouse move and mouseup events. These are bind to doc/container,
4663
- // because Navigator.grabbedSomething flags are stored in mousedown events:
5352
+ // because Navigator.grabbedSomething flags are stored in mousedown
5353
+ // events
4664
5354
  eventsToUnbind.push(
4665
5355
  addEvent(container, 'mousemove', mouseMoveHandler),
4666
5356
  addEvent(container.ownerDocument, 'mouseup', mouseUpHandler)
@@ -4680,9 +5370,13 @@
4680
5370
  // Data events
4681
5371
  if (navigator.series && navigator.series[0]) {
4682
5372
  eventsToUnbind.push(
4683
- addEvent(navigator.series[0].xAxis, 'foundExtremes', function() {
4684
- chart.navigator.modifyNavigatorAxisExtremes();
4685
- })
5373
+ addEvent(
5374
+ navigator.series[0].xAxis,
5375
+ 'foundExtremes',
5376
+ function() {
5377
+ chart.navigator.modifyNavigatorAxisExtremes();
5378
+ }
5379
+ )
4686
5380
  );
4687
5381
  }
4688
5382
  },
@@ -4713,7 +5407,7 @@
4713
5407
 
4714
5408
  /**
4715
5409
  * Mousedown on a shaded mask, either:
4716
- * - will be stored for future drag&drop
5410
+ * - will be stored for future drag&drop
4717
5411
  * - will directly shift to a new range
4718
5412
  *
4719
5413
  * @param {Object} e Mouse event
@@ -4818,9 +5512,10 @@
4818
5512
  chartX;
4819
5513
 
4820
5514
 
4821
- // In iOS, a mousemove event with e.pageX === 0 is fired when holding the finger
4822
- // down in the center of the scrollbar. This should be ignored.
4823
- if (!e.touches || e.touches[0].pageX !== 0) { // #4696, scrollbar failed on Android
5515
+ // In iOS, a mousemove event with e.pageX === 0 is fired when holding
5516
+ // the finger down in the center of the scrollbar. This should be
5517
+ // ignored.
5518
+ if (!e.touches || e.touches[0].pageX !== 0) { // #4696
4824
5519
 
4825
5520
  e = chart.pointer.normalize(e);
4826
5521
  chartX = e.chartX;
@@ -4854,7 +5549,8 @@
4854
5549
  navigator.hasDragged = true;
4855
5550
  if (chartX < dragOffset) { // outside left
4856
5551
  chartX = dragOffset;
4857
- } else if (chartX > navigatorSize + dragOffset - range) { // outside right
5552
+ // outside right
5553
+ } else if (chartX > navigatorSize + dragOffset - range) {
4858
5554
  chartX = navigatorSize + dragOffset - range;
4859
5555
  }
4860
5556
 
@@ -4865,8 +5561,12 @@
4865
5561
  chartX - dragOffset + range
4866
5562
  );
4867
5563
  }
4868
- if (navigator.hasDragged && navigator.scrollbar && navigator.scrollbar.options.liveRedraw) {
4869
- e.DOMType = e.type; // DOMType is for IE8 because it can't read type async
5564
+ if (
5565
+ navigator.hasDragged &&
5566
+ navigator.scrollbar &&
5567
+ navigator.scrollbar.options.liveRedraw
5568
+ ) {
5569
+ e.DOMType = e.type; // DOMType is for IE8
4870
5570
  setTimeout(function() {
4871
5571
  navigator.onMouseUp(e);
4872
5572
  }, 0);
@@ -4917,8 +5617,9 @@
4917
5617
  Math.min(ext.min, ext.max),
4918
5618
  Math.max(ext.min, ext.max),
4919
5619
  true,
4920
- navigator.hasDragged ? false : null, // Run animation when clicking buttons, scrollbar track etc, but not when dragging handles or scrollbar
4921
- {
5620
+ // Run animation when clicking buttons, scrollbar track etc,
5621
+ // but not when dragging handles or scrollbar
5622
+ navigator.hasDragged ? false : null, {
4922
5623
  trigger: 'navigator',
4923
5624
  triggerOp: 'navigator-drag',
4924
5625
  DOMEvent: DOMEvent // #1838
@@ -4962,7 +5663,11 @@
4962
5663
 
4963
5664
  // We only listen for extremes-events on the first baseSeries
4964
5665
  if (baseSeries[0].xAxis) {
4965
- removeEvent(baseSeries[0].xAxis, 'foundExtremes', this.modifyBaseAxisExtremes);
5666
+ removeEvent(
5667
+ baseSeries[0].xAxis,
5668
+ 'foundExtremes',
5669
+ this.modifyBaseAxisExtremes
5670
+ );
4966
5671
  }
4967
5672
  }
4968
5673
  },
@@ -4993,21 +5698,30 @@
4993
5698
  this.scrollbarOptions = scrollbarOptions;
4994
5699
  this.outlineHeight = height + scrollbarHeight;
4995
5700
 
4996
- this.opposite = pick(navigatorOptions.opposite, !navigatorEnabled && chart.inverted); // #6262
5701
+ this.opposite = pick(
5702
+ navigatorOptions.opposite, !navigatorEnabled && chart.inverted
5703
+ ); // #6262
4997
5704
 
4998
5705
  var navigator = this,
4999
5706
  baseSeries = navigator.baseSeries,
5000
5707
  xAxisIndex = chart.xAxis.length,
5001
5708
  yAxisIndex = chart.yAxis.length,
5002
- baseXaxis = baseSeries && baseSeries[0] && baseSeries[0].xAxis || chart.xAxis[0];
5709
+ baseXaxis = baseSeries && baseSeries[0] && baseSeries[0].xAxis ||
5710
+ chart.xAxis[0];
5003
5711
 
5004
5712
  // Make room for the navigator, can be placed around the chart:
5005
5713
  chart.extraMargin = {
5006
5714
  type: navigator.opposite ? 'plotTop' : 'marginBottom',
5007
- value: (navigatorEnabled || !chart.inverted ? navigator.outlineHeight : 0) + navigatorOptions.margin
5715
+ value: (
5716
+ navigatorEnabled || !chart.inverted ?
5717
+ navigator.outlineHeight :
5718
+ 0
5719
+ ) + navigatorOptions.margin
5008
5720
  };
5009
5721
  if (chart.inverted) {
5010
- chart.extraMargin.type = navigator.opposite ? 'marginRight' : 'plotLeft';
5722
+ chart.extraMargin.type = navigator.opposite ?
5723
+ 'marginRight' :
5724
+ 'plotLeft';
5011
5725
  }
5012
5726
  chart.isDirtyBox = true;
5013
5727
 
@@ -5080,7 +5794,11 @@
5080
5794
  ext = axis.getExtremes(),
5081
5795
  scrollTrackWidth = axis.len - 2 * scrollbarHeight,
5082
5796
  min = numExt('min', axis.options.min, ext.dataMin),
5083
- valueRange = numExt('max', axis.options.max, ext.dataMax) - min;
5797
+ valueRange = numExt(
5798
+ 'max',
5799
+ axis.options.max,
5800
+ ext.dataMax
5801
+ ) - min;
5084
5802
 
5085
5803
  return reverse ?
5086
5804
  // from pixel to value
@@ -5118,7 +5836,10 @@
5118
5836
  navigator.hasDragged = navigator.scrollbar.hasDragged;
5119
5837
  navigator.render(0, 0, from, to);
5120
5838
 
5121
- if (chart.options.scrollbar.liveRedraw || e.DOMType !== 'mousemove') {
5839
+ if (
5840
+ chart.options.scrollbar.liveRedraw ||
5841
+ e.DOMType !== 'mousemove'
5842
+ ) {
5122
5843
  setTimeout(function() {
5123
5844
  navigator.onMouseUp(e);
5124
5845
  });
@@ -5133,8 +5854,8 @@
5133
5854
  },
5134
5855
 
5135
5856
  /**
5136
- * Get the union data extremes of the chart - the outer data extremes of the base
5137
- * X axis and the navigator axis.
5857
+ * Get the union data extremes of the chart - the outer data extremes of the
5858
+ * base X axis and the navigator axis.
5138
5859
  * @param {boolean} returnFalseOnNoBaseSeries - as the param says.
5139
5860
  */
5140
5861
  getUnionExtremes: function(returnFalseOnNoBaseSeries) {
@@ -5172,20 +5893,30 @@
5172
5893
  },
5173
5894
 
5174
5895
  /**
5175
- * Set the base series and update the navigator series from this. With a bit
5176
- * of modification we should be able to make this an API method to be called
5896
+ * Set the base series and update the navigator series from this. With a bit
5897
+ * of modification we should be able to make this an API method to be called
5177
5898
  * from the outside
5178
- * @param {Object} baseSeriesOptions - additional series options for a navigator
5899
+ * @param {Object} baseSeriesOptions
5900
+ * Additional series options for a navigator
5901
+ * @param {Boolean} [redraw]
5902
+ * Whether to redraw after update.
5179
5903
  */
5180
- setBaseSeries: function(baseSeriesOptions) {
5904
+ setBaseSeries: function(baseSeriesOptions, redraw) {
5181
5905
  var chart = this.chart,
5182
5906
  baseSeries = this.baseSeries = [];
5183
5907
 
5184
- baseSeriesOptions = baseSeriesOptions || chart.options && chart.options.navigator.baseSeries || 0;
5908
+ baseSeriesOptions = (
5909
+ baseSeriesOptions ||
5910
+ chart.options && chart.options.navigator.baseSeries ||
5911
+ 0
5912
+ );
5185
5913
 
5186
- // Iterate through series and add the ones that should be shown in navigator.
5914
+ // Iterate through series and add the ones that should be shown in
5915
+ // navigator.
5187
5916
  each(chart.series || [], function(series, i) {
5188
- if (!series.options.isInternal && // Don't include existing nav series
5917
+ if (
5918
+ // Don't include existing nav series
5919
+ !series.options.isInternal &&
5189
5920
  (
5190
5921
  series.options.showInNavigator ||
5191
5922
  (
@@ -5201,7 +5932,7 @@
5201
5932
 
5202
5933
  // When run after render, this.xAxis already exists
5203
5934
  if (this.xAxis && !this.xAxis.fake) {
5204
- this.updateNavigatorSeries();
5935
+ this.updateNavigatorSeries(redraw);
5205
5936
  }
5206
5937
  },
5207
5938
 
@@ -5209,7 +5940,7 @@
5209
5940
  * Update series in the navigator from baseSeries, adding new if does not
5210
5941
  * exist.
5211
5942
  */
5212
- updateNavigatorSeries: function() {
5943
+ updateNavigatorSeries: function(redraw) {
5213
5944
  var navigator = this,
5214
5945
  chart = navigator.chart,
5215
5946
  baseSeries = navigator.baseSeries,
@@ -5236,8 +5967,8 @@
5236
5967
  function(navSeries) {
5237
5968
  var base = navSeries.baseSeries;
5238
5969
  if (H.inArray(base, baseSeries) < 0) { // Not in array
5239
- // If there is still a base series connected to this series,
5240
- // remove event handler and reference.
5970
+ // If there is still a base series connected to this
5971
+ // series, remove event handler and reference.
5241
5972
  if (base) {
5242
5973
  removeEvent(
5243
5974
  base,
@@ -5254,12 +5985,19 @@
5254
5985
  }
5255
5986
  );
5256
5987
 
5257
- // Go through each base series and merge the options to create new series
5988
+ // Go through each base series and merge the options to create new
5989
+ // series
5258
5990
  if (baseSeries && baseSeries.length) {
5259
- each(baseSeries, function(base, i) {
5991
+ each(baseSeries, function eachBaseSeries(base) {
5260
5992
  var linkedNavSeries = base.navigatorSeries,
5261
- userNavOptions = !isArray(chartNavigatorSeriesOptions) ?
5262
- chartNavigatorSeriesOptions : {};
5993
+ userNavOptions = extend(
5994
+ // Grab color from base as default
5995
+ {
5996
+ color: base.color
5997
+ }, !isArray(chartNavigatorSeriesOptions) ?
5998
+ chartNavigatorSeriesOptions :
5999
+ defaultOptions.navigator.series
6000
+ );
5263
6001
 
5264
6002
  // Don't update if the series exists in nav and we have disabled
5265
6003
  // adaptToUpdatedData.
@@ -5270,7 +6008,7 @@
5270
6008
  return;
5271
6009
  }
5272
6010
 
5273
- navSeriesMixin.name = 'Navigator ' + (i + 1);
6011
+ navSeriesMixin.name = 'Navigator ' + baseSeries.length;
5274
6012
 
5275
6013
  baseOptions = base.options || {};
5276
6014
  baseNavigatorOptions = baseOptions.navigatorOptions || {};
@@ -5281,24 +6019,31 @@
5281
6019
  baseNavigatorOptions
5282
6020
  );
5283
6021
 
5284
- // Merge data separately. Do a slice to avoid mutating the navigator options from base series (#4923).
5285
- var navigatorSeriesData = baseNavigatorOptions.data || userNavOptions.data;
5286
- navigator.hasNavigatorData = navigator.hasNavigatorData || !!navigatorSeriesData;
5287
- mergedNavSeriesOptions.data = navigatorSeriesData || baseOptions.data && baseOptions.data.slice(0);
6022
+ // Merge data separately. Do a slice to avoid mutating the
6023
+ // navigator options from base series (#4923).
6024
+ var navigatorSeriesData =
6025
+ baseNavigatorOptions.data || userNavOptions.data;
6026
+ navigator.hasNavigatorData =
6027
+ navigator.hasNavigatorData || !!navigatorSeriesData;
6028
+ mergedNavSeriesOptions.data =
6029
+ navigatorSeriesData ||
6030
+ baseOptions.data && baseOptions.data.slice(0);
5288
6031
 
5289
6032
  // Update or add the series
5290
- if (linkedNavSeries) {
5291
- linkedNavSeries.update(mergedNavSeriesOptions);
6033
+ if (linkedNavSeries && linkedNavSeries.options) {
6034
+ linkedNavSeries.update(mergedNavSeriesOptions, redraw);
5292
6035
  } else {
5293
- base.navigatorSeries = chart.initSeries(mergedNavSeriesOptions);
6036
+ base.navigatorSeries = chart.initSeries(
6037
+ mergedNavSeriesOptions
6038
+ );
5294
6039
  base.navigatorSeries.baseSeries = base; // Store ref
5295
6040
  navigatorSeries.push(base.navigatorSeries);
5296
6041
  }
5297
6042
  });
5298
6043
  }
5299
6044
 
5300
- // If user has defined data (and no base series) or explicitly defined
5301
- // navigator.series as an array, we create these series on top of any
6045
+ // If user has defined data (and no base series) or explicitly defined
6046
+ // navigator.series as an array, we create these series on top of any
5302
6047
  // base series.
5303
6048
  if (
5304
6049
  chartNavigatorSeriesOptions.data &&
@@ -5309,10 +6054,13 @@
5309
6054
  // Allow navigator.series to be an array
5310
6055
  chartNavigatorSeriesOptions = H.splat(chartNavigatorSeriesOptions);
5311
6056
  each(chartNavigatorSeriesOptions, function(userSeriesOptions, i) {
5312
- mergedNavSeriesOptions = merge({
6057
+ navSeriesMixin.name =
6058
+ 'Navigator ' + (navigatorSeries.length + 1);
6059
+ mergedNavSeriesOptions = merge(
6060
+ defaultOptions.navigator.series, {
5313
6061
  // Since we don't have a base series to pull color from,
5314
6062
  // try to fake it by using color from series with same
5315
- // index. Otherwise pull from the colors array. We need
6063
+ // index. Otherwise pull from the colors array. We need
5316
6064
  // an explicit color as otherwise updates will increment
5317
6065
  // color counter and we'll get a new color for each
5318
6066
  // update of the nav series.
@@ -5322,13 +6070,15 @@
5322
6070
  chart.options.colors[i] ||
5323
6071
  chart.options.colors[0]
5324
6072
  },
5325
- userSeriesOptions,
5326
- navSeriesMixin
6073
+ navSeriesMixin,
6074
+ userSeriesOptions
5327
6075
  );
5328
6076
  mergedNavSeriesOptions.data = userSeriesOptions.data;
5329
6077
  if (mergedNavSeriesOptions.data) {
5330
6078
  navigator.hasNavigatorData = true;
5331
- navigatorSeries.push(chart.initSeries(mergedNavSeriesOptions));
6079
+ navigatorSeries.push(
6080
+ chart.initSeries(mergedNavSeriesOptions)
6081
+ );
5332
6082
  }
5333
6083
  });
5334
6084
  }
@@ -5346,10 +6096,14 @@
5346
6096
 
5347
6097
  // Bind modified extremes event to first base's xAxis only.
5348
6098
  // In event of > 1 base-xAxes, the navigator will ignore those.
5349
- // Adding this multiple times to the same axis is no problem, as
6099
+ // Adding this multiple times to the same axis is no problem, as
5350
6100
  // duplicates should be discarded by the browser.
5351
6101
  if (baseSeries[0] && baseSeries[0].xAxis) {
5352
- addEvent(baseSeries[0].xAxis, 'foundExtremes', this.modifyBaseAxisExtremes);
6102
+ addEvent(
6103
+ baseSeries[0].xAxis,
6104
+ 'foundExtremes',
6105
+ this.modifyBaseAxisExtremes
6106
+ );
5353
6107
  }
5354
6108
 
5355
6109
  each(baseSeries, function(base) {
@@ -5365,7 +6119,7 @@
5365
6119
  }
5366
6120
  });
5367
6121
 
5368
- // Respond to updated data in the base series, unless explicitily
6122
+ // Respond to updated data in the base series, unless explicitily
5369
6123
  // not adapting to data changes.
5370
6124
  if (this.navigatorOptions.adaptToUpdatedData !== false) {
5371
6125
  if (base.xAxis) {
@@ -5385,9 +6139,9 @@
5385
6139
  },
5386
6140
 
5387
6141
  /**
5388
- * Set the navigator x axis extremes to reflect the total. The navigator extremes
5389
- * should always be the extremes of the union of all series in the chart as
5390
- * well as the navigator series.
6142
+ * Set the navigator x axis extremes to reflect the total. The navigator
6143
+ * extremes should always be the extremes of the union of all series in the
6144
+ * chart as well as the navigator series.
5391
6145
  */
5392
6146
  modifyNavigatorAxisExtremes: function() {
5393
6147
  var xAxis = this.xAxis,
@@ -5395,7 +6149,13 @@
5395
6149
 
5396
6150
  if (xAxis.getExtremes) {
5397
6151
  unionExtremes = this.getUnionExtremes(true);
5398
- if (unionExtremes && (unionExtremes.dataMin !== xAxis.min || unionExtremes.dataMax !== xAxis.max)) {
6152
+ if (
6153
+ unionExtremes &&
6154
+ (
6155
+ unionExtremes.dataMin !== xAxis.min ||
6156
+ unionExtremes.dataMax !== xAxis.max
6157
+ )
6158
+ ) {
5399
6159
  xAxis.min = unionExtremes.dataMin;
5400
6160
  xAxis.max = unionExtremes.dataMax;
5401
6161
  }
@@ -5416,29 +6176,34 @@
5416
6176
  range = baseMax - baseMin,
5417
6177
  stickToMin = navigator.stickToMin,
5418
6178
  stickToMax = navigator.stickToMax,
6179
+ overscroll = baseXAxis.options.overscroll,
5419
6180
  newMax,
5420
6181
  newMin,
5421
6182
  navigatorSeries = navigator.series && navigator.series[0],
5422
6183
  hasSetExtremes = !!baseXAxis.setExtremes,
5423
6184
 
5424
- // When the extremes have been set by range selector button, don't stick to min or max.
5425
- // The range selector buttons will handle the extremes. (#5489)
5426
- unmutable = baseXAxis.eventArgs && baseXAxis.eventArgs.trigger === 'rangeSelectorButton';
6185
+ // When the extremes have been set by range selector button, don't
6186
+ // stick to min or max. The range selector buttons will handle the
6187
+ // extremes. (#5489)
6188
+ unmutable = baseXAxis.eventArgs &&
6189
+ baseXAxis.eventArgs.trigger === 'rangeSelectorButton';
5427
6190
 
5428
6191
  if (!unmutable) {
5429
6192
 
5430
- // If the zoomed range is already at the min, move it to the right as new data
5431
- // comes in
6193
+ // If the zoomed range is already at the min, move it to the right
6194
+ // as new data comes in
5432
6195
  if (stickToMin) {
5433
6196
  newMin = baseDataMin;
5434
6197
  newMax = newMin + range;
5435
6198
  }
5436
6199
 
5437
- // If the zoomed range is already at the max, move it to the right as new data
5438
- // comes in
6200
+ // If the zoomed range is already at the max, move it to the right
6201
+ // as new data comes in
5439
6202
  if (stickToMax) {
5440
- newMax = baseDataMax;
5441
- if (!stickToMin) { // if stickToMin is true, the new min value is set above
6203
+ newMax = baseDataMax + overscroll;
6204
+
6205
+ // if stickToMin is true, the new min value is set above
6206
+ if (!stickToMin) {
5442
6207
  newMin = Math.max(
5443
6208
  newMax - range,
5444
6209
  navigatorSeries && navigatorSeries.xData ?
@@ -5461,21 +6226,23 @@
5461
6226
  },
5462
6227
 
5463
6228
  /**
5464
- * Handler for updated data on the base series. When data is modified, the navigator series
5465
- * must reflect it. This is called from the Chart.redraw function before axis and series
5466
- * extremes are computed.
6229
+ * Handler for updated data on the base series. When data is modified, the
6230
+ * navigator series must reflect it. This is called from the Chart.redraw
6231
+ * function before axis and series extremes are computed.
5467
6232
  */
5468
6233
  updatedDataHandler: function() {
5469
6234
  var navigator = this.chart.navigator,
5470
6235
  baseSeries = this,
5471
6236
  navigatorSeries = this.navigatorSeries;
5472
6237
 
5473
- // If the scrollbar is scrolled all the way to the right, keep right as new data
5474
- // comes in.
5475
- navigator.stickToMax = Math.round(navigator.zoomedMax) >= Math.round(navigator.size);
6238
+ // If the scrollbar is scrolled all the way to the right, keep right as
6239
+ // new data comes in.
6240
+ navigator.stickToMax =
6241
+ Math.round(navigator.zoomedMax) >= Math.round(navigator.size);
5476
6242
 
5477
- // Detect whether the zoomed area should stick to the minimum or maximum. If the current
5478
- // axis minimum falls outside the new updated dataset, we must adjust.
6243
+ // Detect whether the zoomed area should stick to the minimum or
6244
+ // maximum. If the current axis minimum falls outside the new updated
6245
+ // dataset, we must adjust.
5479
6246
  navigator.stickToMin = isNumber(baseSeries.xAxis.min) &&
5480
6247
  (baseSeries.xAxis.min <= baseSeries.xData[0]) &&
5481
6248
  (!this.chart.fixedRange || !navigator.stickToMax);
@@ -5483,7 +6250,12 @@
5483
6250
  // Set the navigator series data to the new data of the base series
5484
6251
  if (navigatorSeries && !navigator.hasNavigatorData) {
5485
6252
  navigatorSeries.options.pointStart = baseSeries.xData[0];
5486
- navigatorSeries.setData(baseSeries.options.data, false, null, false); // #5414
6253
+ navigatorSeries.setData(
6254
+ baseSeries.options.data,
6255
+ false,
6256
+ null,
6257
+ false
6258
+ ); // #5414
5487
6259
  }
5488
6260
  },
5489
6261
 
@@ -5492,7 +6264,8 @@
5492
6264
  */
5493
6265
  addChartEvents: function() {
5494
6266
  addEvent(this.chart, 'redraw', function() {
5495
- // Move the scrollbar after redraw, like after data updata even if axes don't redraw
6267
+ // Move the scrollbar after redraw, like after data updata even if
6268
+ // axes don't redraw
5496
6269
  var navigator = this.navigator,
5497
6270
  xAxis = navigator && (
5498
6271
  navigator.baseSeries &&
@@ -5552,8 +6325,9 @@
5552
6325
  H.Navigator = Navigator;
5553
6326
 
5554
6327
  /**
5555
- * For Stock charts, override selection zooming with some special features because
5556
- * X axis zooming is already allowed by the Navigator and Range selector.
6328
+ * For Stock charts, override selection zooming with some special features
6329
+ * because X axis zooming is already allowed by the Navigator and Range
6330
+ * selector.
5557
6331
  */
5558
6332
  wrap(Axis.prototype, 'zoom', function(proceed, newMin, newMax) {
5559
6333
  var chart = this.chart,
@@ -5567,8 +6341,8 @@
5567
6341
  if (this.isXAxis && ((navigator && navigator.enabled) ||
5568
6342
  (rangeSelector && rangeSelector.enabled))) {
5569
6343
 
5570
- // For x only zooming, fool the chart.zoom method not to create the zoom button
5571
- // because the property already exists
6344
+ // For x only zooming, fool the chart.zoom method not to create the zoom
6345
+ // button because the property already exists
5572
6346
  if (zoomType === 'x') {
5573
6347
  chart.resetZoomButton = 'blocked';
5574
6348
 
@@ -5576,8 +6350,8 @@
5576
6350
  } else if (zoomType === 'y') {
5577
6351
  ret = false;
5578
6352
 
5579
- // For xy zooming, record the state of the zoom before zoom selection, then when
5580
- // the reset button is pressed, revert to this state
6353
+ // For xy zooming, record the state of the zoom before zoom selection,
6354
+ // then when the reset button is pressed, revert to this state
5581
6355
  } else if (zoomType === 'xy') {
5582
6356
  previousZoom = this.previousZoom;
5583
6357
  if (defined(newMin)) {
@@ -5608,9 +6382,10 @@
5608
6382
  });
5609
6383
 
5610
6384
  /**
5611
- * For stock charts, extend the Chart.setChartSize method so that we can set the final top position
5612
- * of the navigator once the height of the chart, including the legend, is determined. #367.
5613
- * We can't use Chart.getMargins, because labels offsets are not calculated yet.
6385
+ * For stock charts, extend the Chart.setChartSize method so that we can set the
6386
+ * final top position of the navigator once the height of the chart, including
6387
+ * the legend, is determined. #367. We can't use Chart.getMargins, because
6388
+ * labels offsets are not calculated yet.
5614
6389
  */
5615
6390
  wrap(Chart.prototype, 'setChartSize', function(proceed) {
5616
6391
 
@@ -5624,7 +6399,7 @@
5624
6399
  proceed.apply(this, [].slice.call(arguments, 1));
5625
6400
 
5626
6401
  if (navigator) {
5627
- legendOptions = legend.options;
6402
+ legendOptions = legend && legend.options;
5628
6403
  xAxis = navigator.xAxis;
5629
6404
  yAxis = navigator.yAxis;
5630
6405
  scrollbarHeight = navigator.scrollbarHeight;
@@ -5638,9 +6413,25 @@
5638
6413
  } else {
5639
6414
  navigator.left = this.plotLeft + scrollbarHeight;
5640
6415
  navigator.top = navigator.navigatorOptions.top ||
5641
- this.chartHeight - navigator.height - scrollbarHeight - this.spacing[2] -
5642
- (legendOptions.verticalAlign === 'bottom' && legendOptions.enabled && !legendOptions.floating ?
5643
- legend.legendHeight + pick(legendOptions.margin, 10) : 0);
6416
+ this.chartHeight -
6417
+ navigator.height -
6418
+ scrollbarHeight -
6419
+ this.spacing[2] -
6420
+ (
6421
+ this.rangeSelector && this.extraBottomMargin ?
6422
+ this.rangeSelector.getHeight() :
6423
+ 0
6424
+ ) -
6425
+ (
6426
+ (
6427
+ legendOptions &&
6428
+ legendOptions.verticalAlign === 'bottom' &&
6429
+ legendOptions.enabled &&
6430
+ !legendOptions.floating
6431
+ ) ?
6432
+ legend.legendHeight + pick(legendOptions.margin, 10) :
6433
+ 0
6434
+ );
5644
6435
  }
5645
6436
 
5646
6437
  if (xAxis && yAxis) { // false if navigator is disabled (#904)
@@ -5658,19 +6449,36 @@
5658
6449
  });
5659
6450
 
5660
6451
  // Pick up badly formatted point options to addPoint
5661
- wrap(Series.prototype, 'addPoint', function(proceed, options, redraw, shift, animation) {
6452
+ wrap(Series.prototype, 'addPoint', function(
6453
+ proceed,
6454
+ options,
6455
+ redraw,
6456
+ shift,
6457
+ animation
6458
+ ) {
5662
6459
  var turboThreshold = this.options.turboThreshold;
5663
- if (turboThreshold && this.xData.length > turboThreshold && isObject(options, true) && this.chart.navigator) {
6460
+ if (
6461
+ turboThreshold &&
6462
+ this.xData.length > turboThreshold &&
6463
+ isObject(options, true) &&
6464
+ this.chart.navigator
6465
+ ) {
5664
6466
  error(20, true);
5665
6467
  }
5666
6468
  proceed.call(this, options, redraw, shift, animation);
5667
6469
  });
5668
6470
 
5669
6471
  // Handle adding new series
5670
- wrap(Chart.prototype, 'addSeries', function(proceed, options, redraw, animation) {
6472
+ wrap(Chart.prototype, 'addSeries', function(
6473
+ proceed,
6474
+ options,
6475
+ redraw,
6476
+ animation
6477
+ ) {
5671
6478
  var series = proceed.call(this, options, false, animation);
5672
6479
  if (this.navigator) {
5673
- this.navigator.setBaseSeries(); // Recompute which series should be shown in navigator, and add them
6480
+ // Recompute which series should be shown in navigator, and add them
6481
+ this.navigator.setBaseSeries(null, false);
5674
6482
  }
5675
6483
  if (pick(redraw, true)) {
5676
6484
  this.redraw();
@@ -5682,7 +6490,7 @@
5682
6490
  wrap(Series.prototype, 'update', function(proceed, newOptions, redraw) {
5683
6491
  proceed.call(this, newOptions, false);
5684
6492
  if (this.chart.navigator && !this.options.isInternal) {
5685
- this.chart.navigator.setBaseSeries();
6493
+ this.chart.navigator.setBaseSeries(null, false);
5686
6494
  }
5687
6495
  if (pick(redraw, true)) {
5688
6496
  this.chart.redraw();
@@ -5700,9 +6508,6 @@
5700
6508
  }
5701
6509
  });
5702
6510
 
5703
- /* ****************************************************************************
5704
- * End Navigator code *
5705
- *****************************************************************************/
5706
6511
 
5707
6512
  }(Highcharts));
5708
6513
  (function(H) {
@@ -5744,8 +6549,8 @@
5744
6549
  * the chart, like 1 day, 1 week, 1 month etc. It also provides input
5745
6550
  * boxes where min and max dates can be manually input.
5746
6551
  *
5747
- * @optionparent rangeSelector
5748
6552
  * @product highstock
6553
+ * @optionparent rangeSelector
5749
6554
  */
5750
6555
  rangeSelector: {
5751
6556
  // allButtonsEnabled: false,
@@ -5753,6 +6558,18 @@
5753
6558
  // buttons: {Object}
5754
6559
  // buttonSpacing: 0,
5755
6560
 
6561
+ /**
6562
+ * The vertical alignment of the rangeselector box. Allowed properties are `top`,
6563
+ * `middle`, `bottom`.
6564
+ *
6565
+ * @since 6.0.0
6566
+ *
6567
+ * @sample {highstock} stock/rangeselector/vertical-align-middle/ Middle
6568
+ *
6569
+ * @sample {highstock} stock/rangeselector/vertical-align-bottom/ Bottom
6570
+ */
6571
+ verticalAlign: 'top',
6572
+
5756
6573
  /**
5757
6574
  * A collection of attributes for the buttons. The object takes SVG
5758
6575
  * attributes like `fill`, `stroke`, `stroke-width`, as well as `style`,
@@ -5763,8 +6580,7 @@
5763
6580
  *
5764
6581
  * CSS styles for the text label.
5765
6582
  *
5766
- * In [styled mode](http://www.highcharts.com/docs/chart-design-and-
5767
- * style/style-by-css), the buttons are styled by the `.highcharts-
6583
+ * In styled mode, the buttons are styled by the `.highcharts-
5768
6584
  * range-selector-buttons .highcharts-button` rule with its different
5769
6585
  * states.
5770
6586
  *
@@ -5773,53 +6589,103 @@
5773
6589
  * @product highstock
5774
6590
  */
5775
6591
  buttonTheme: {
5776
-
5777
- /**
5778
- */
5779
6592
  'stroke-width': 0,
5780
-
5781
- /**
5782
- */
5783
6593
  width: 28,
5784
-
5785
- /**
5786
- */
5787
6594
  height: 18,
5788
-
5789
- /**
5790
- */
5791
6595
  padding: 2,
5792
-
5793
- /**
5794
- */
5795
6596
  zIndex: 7 // #484, #852
5796
6597
  },
5797
6598
 
5798
6599
  /**
5799
- * The height of the range selector, used to reserve space for buttons
5800
- * and input.
6600
+ * When the rangeselector is floating, the plot area does not reserve
6601
+ * space for it. This opens for positioning anywhere on the chart.
6602
+ *
6603
+ * @sample {highstock} stock/rangeselector/floating/
6604
+ * Placing the range selector between the plot area and the
6605
+ * navigator
6606
+ * @since 6.0.0
6607
+ * @product highstock
6608
+ */
6609
+ floating: false,
6610
+
6611
+ /**
6612
+ * The x offset of the range selector relative to its horizontal
6613
+ * alignment within `chart.spacingLeft` and `chart.spacingRight`.
6614
+ *
6615
+ * @since 6.0.0
6616
+ * @product highstock
6617
+ */
6618
+ x: 0,
6619
+
6620
+ /**
6621
+ * The y offset of the range selector relative to its horizontal
6622
+ * alignment within `chart.spacingLeft` and `chart.spacingRight`.
6623
+ *
6624
+ * @since 6.0.0
6625
+ * @product highstock
6626
+ */
6627
+ y: 0,
6628
+
6629
+ /**
6630
+ * Deprecated. The height of the range selector. Currently it is
6631
+ * calculated dynamically.
5801
6632
  *
5802
6633
  * @type {Number}
5803
- * @default 35
6634
+ * @default undefined
5804
6635
  * @since 2.1.9
5805
6636
  * @product highstock
6637
+ * @deprecated true
5806
6638
  */
5807
- height: 35, // reserved space for buttons and input
6639
+ height: undefined, // reserved space for buttons and input
5808
6640
 
5809
6641
  /**
5810
6642
  * Positioning for the input boxes. Allowed properties are `align`,
5811
- * `verticalAlign`, `x` and `y`.
6643
+ * `x` and `y`.
5812
6644
  *
5813
6645
  * @type {Object}
5814
6646
  * @default { align: "right" }
5815
- * @since 1.2.5
6647
+ * @since 1.2.4
5816
6648
  * @product highstock
5817
6649
  */
5818
6650
  inputPosition: {
6651
+ /**
6652
+ * The alignment of the input box. Allowed properties are `left`,
6653
+ * `center`, `right`.
6654
+ * @validvalue ["left", "center", "right"]
6655
+ * @sample {highstock} stock/rangeselector/input-button-position/
6656
+ * Alignment
6657
+ * @since 6.0.0
6658
+ */
6659
+ align: 'right',
6660
+ x: 0,
6661
+ y: 0
6662
+ },
5819
6663
 
6664
+ /**
6665
+ * Positioning for the button row.
6666
+ *
6667
+ * @since 1.2.4
6668
+ * @product highstock
6669
+ */
6670
+ buttonPosition: {
6671
+ /**
6672
+ * The alignment of the input box. Allowed properties are `left`,
6673
+ * `center`, `right`.
6674
+ *
6675
+ * @validvalue ["left", "center", "right"]
6676
+ * @sample {highstock} stock/rangeselector/input-button-position/
6677
+ * Alignment
6678
+ * @since 6.0.0
6679
+ */
6680
+ align: 'left',
5820
6681
  /**
6682
+ * X offset of the button row.
5821
6683
  */
5822
- align: 'right'
6684
+ x: 0,
6685
+ /**
6686
+ * Y offset of the button row.
6687
+ */
6688
+ y: 0
5823
6689
  },
5824
6690
  // inputDateFormat: '%b %e, %Y',
5825
6691
  // inputEditDateFormat: '%Y-%m-%d',
@@ -5831,18 +6697,13 @@
5831
6697
  /**
5832
6698
  * CSS styles for the labels - the Zoom, From and To texts.
5833
6699
  *
5834
- * In [styled mode](http://www.highcharts.com/docs/chart-design-and-
5835
- * style/style-by-css), the labels are styled by the `.highcharts-
5836
- * range-label` class.
6700
+ * In styled mode, the labels are styled by the `.highcharts-range-label` class.
5837
6701
  *
5838
6702
  * @type {CSSObject}
5839
6703
  * @sample {highstock} stock/rangeselector/styling/ Styling the buttons and inputs
5840
6704
  * @product highstock
5841
6705
  */
5842
6706
  labelStyle: {
5843
-
5844
- /**
5845
- */
5846
6707
  color: '#666666'
5847
6708
  }
5848
6709
 
@@ -5857,13 +6718,17 @@
5857
6718
  * set it before any chart is initialized.
5858
6719
  *
5859
6720
  * <pre>Highcharts.setOptions({
5860
- * lang: {
5861
- * months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
5862
- * 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
5863
- *
5864
- * weekdays: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi',
5865
- * 'Samedi']
5866
- * }
6721
+ * lang: {
6722
+ * months: [
6723
+ * 'Janvier', 'Février', 'Mars', 'Avril',
6724
+ * 'Mai', 'Juin', 'Juillet', 'Août',
6725
+ * 'Septembre', 'Octobre', 'Novembre', 'Décembre'
6726
+ * ],
6727
+ * weekdays: [
6728
+ * 'Dimanche', 'Lundi', 'Mardi', 'Mercredi',
6729
+ * 'Jeudi', 'Vendredi', 'Samedi'
6730
+ * ]
6731
+ * }
5867
6732
  * });</pre>
5868
6733
  *
5869
6734
  * @optionparent lang
@@ -6013,6 +6878,10 @@
6013
6878
  newMin = dataMin;
6014
6879
  newMax = dataMax;
6015
6880
  }
6881
+
6882
+ newMin += rangeOptions._offsetMin;
6883
+ newMax += rangeOptions._offsetMax;
6884
+
6016
6885
  rangeSelector.setSelected(i);
6017
6886
 
6018
6887
  // Update the chart
@@ -6089,11 +6958,11 @@
6089
6958
  blurInputs = function() {
6090
6959
  var minInput = rangeSelector.minInput,
6091
6960
  maxInput = rangeSelector.maxInput;
6092
- if (minInput && minInput.blur) { //#3274 in some case blur is not defined
6093
- fireEvent(minInput, 'blur'); //#3274
6961
+ if (minInput && minInput.blur) { // #3274 in some case blur is not defined
6962
+ fireEvent(minInput, 'blur'); // #3274
6094
6963
  }
6095
- if (maxInput && maxInput.blur) { //#3274 in some case blur is not defined
6096
- fireEvent(maxInput, 'blur'); //#3274
6964
+ if (maxInput && maxInput.blur) { // #3274 in some case blur is not defined
6965
+ fireEvent(maxInput, 'blur'); // #3274
6097
6966
  }
6098
6967
  };
6099
6968
 
@@ -6156,6 +7025,7 @@
6156
7025
  state = 0,
6157
7026
  disable,
6158
7027
  select,
7028
+ offsetRange = rangeOptions._offsetMax - rangeOptions._offsetMin,
6159
7029
  isSelected = i === selected,
6160
7030
  // Disable buttons where the range exceeds what is allowed in the current view
6161
7031
  isTooGreatRange = range > dataMax - dataMin,
@@ -6172,15 +7042,15 @@
6172
7042
  (actualRange >= {
6173
7043
  month: 28,
6174
7044
  year: 365
6175
- }[type] * day * count) &&
7045
+ }[type] * day * count + offsetRange) &&
6176
7046
  (actualRange <= {
6177
7047
  month: 31,
6178
7048
  year: 366
6179
- }[type] * day * count)
7049
+ }[type] * day * count + offsetRange)
6180
7050
  ) {
6181
7051
  isSameRange = true;
6182
7052
  } else if (type === 'ytd') {
6183
- isSameRange = (ytdMax - ytdMin) === actualRange;
7053
+ isSameRange = (ytdMax - ytdMin + offsetRange) === actualRange;
6184
7054
  isYTDButNotSelected = !isSelected;
6185
7055
  } else if (type === 'all') {
6186
7056
  isSameRange = baseAxis.max - baseAxis.min >= dataMax - dataMin;
@@ -6243,6 +7113,10 @@
6243
7113
  year: 365
6244
7114
  }[type] * 24 * 36e5 * count;
6245
7115
  }
7116
+
7117
+ rangeOptions._offsetMin = pick(rangeOptions.offsetMin, 0);
7118
+ rangeOptions._offsetMax = pick(rangeOptions.offsetMax, 0);
7119
+ rangeOptions._range += rangeOptions._offsetMax - rangeOptions._offsetMin;
6246
7120
  },
6247
7121
 
6248
7122
  /**
@@ -6448,11 +7322,11 @@
6448
7322
  getPosition: function() {
6449
7323
  var chart = this.chart,
6450
7324
  options = chart.options.rangeSelector,
6451
- buttonTop = pick((options.buttonPosition || {}).y, chart.plotTop - chart.axisOffset[0] - options.height);
7325
+ top = (options.verticalAlign) === 'top' ? chart.plotTop - chart.axisOffset[0] : 0; // set offset only for varticalAlign top
6452
7326
 
6453
7327
  return {
6454
- buttonTop: buttonTop,
6455
- inputTop: buttonTop - 10
7328
+ buttonTop: top + options.buttonPosition.y,
7329
+ inputTop: top + options.inputPosition.y - 10
6456
7330
  };
6457
7331
  },
6458
7332
  /**
@@ -6493,21 +7367,36 @@
6493
7367
  chartOptions = chart.options,
6494
7368
  navButtonOptions = chartOptions.exporting && chartOptions.exporting.enabled !== false &&
6495
7369
  chartOptions.navigation && chartOptions.navigation.buttonOptions,
6496
- options = chartOptions.rangeSelector,
6497
- buttons = rangeSelector.buttons,
6498
7370
  lang = defaultOptions.lang,
6499
7371
  div = rangeSelector.div,
7372
+ options = chartOptions.rangeSelector,
7373
+ floating = options.floating,
7374
+ buttons = rangeSelector.buttons,
6500
7375
  inputGroup = rangeSelector.inputGroup,
6501
7376
  buttonTheme = options.buttonTheme,
6502
- buttonPosition = options.buttonPosition || {},
7377
+ buttonPosition = options.buttonPosition,
7378
+ inputPosition = options.inputPosition,
6503
7379
  inputEnabled = options.inputEnabled,
6504
7380
  states = buttonTheme && buttonTheme.states,
6505
7381
  plotLeft = chart.plotLeft,
6506
7382
  buttonLeft,
6507
7383
  pos = this.getPosition(),
6508
- buttonGroup = rangeSelector.group,
6509
- buttonBBox,
6510
- rendered = rangeSelector.rendered;
7384
+ buttonGroup = rangeSelector.buttonGroup,
7385
+ group,
7386
+ groupHeight,
7387
+ rendered = rangeSelector.rendered,
7388
+ verticalAlign = rangeSelector.options.verticalAlign,
7389
+ legend = chart.legend,
7390
+ legendOptions = legend && legend.options,
7391
+ buttonPositionY = buttonPosition.y,
7392
+ inputPositionY = inputPosition.y,
7393
+ exportingX = 0,
7394
+ alignTranslateY,
7395
+ legendHeight,
7396
+ minPosition,
7397
+ translateY,
7398
+ translateX,
7399
+ groupOffsetY;
6511
7400
 
6512
7401
  if (options.enabled === false) {
6513
7402
  return;
@@ -6516,22 +7405,41 @@
6516
7405
  // create the elements
6517
7406
  if (!rendered) {
6518
7407
 
6519
- rangeSelector.group = buttonGroup = renderer.g('range-selector-buttons').add();
7408
+ rangeSelector.group = group = renderer.g('range-selector-group')
7409
+ .attr({
7410
+ zIndex: 7
7411
+ })
7412
+ .add();
7413
+
7414
+ rangeSelector.buttonGroup = buttonGroup = renderer.g('range-selector-buttons').add(group);
6520
7415
 
6521
- rangeSelector.zoomText = renderer.text(lang.rangeSelectorZoom, pick(buttonPosition.x, plotLeft), 15)
7416
+ rangeSelector.zoomText = renderer.text(lang.rangeSelectorZoom, pick(plotLeft + buttonPosition.x, plotLeft), 15)
6522
7417
  .css(options.labelStyle)
6523
7418
  .add(buttonGroup);
6524
7419
 
6525
- // button starting position
6526
- buttonLeft = pick(buttonPosition.x, plotLeft) + rangeSelector.zoomText.getBBox().width + 5;
7420
+ // button start position
7421
+ buttonLeft = pick(plotLeft + buttonPosition.x, plotLeft) + rangeSelector.zoomText.getBBox().width + 5;
6527
7422
 
6528
7423
  each(rangeSelector.buttonOptions, function(rangeOptions, i) {
7424
+
6529
7425
  buttons[i] = renderer.button(
6530
7426
  rangeOptions.text,
6531
7427
  buttonLeft,
6532
7428
  0,
6533
7429
  function() {
6534
- rangeSelector.clickButton(i);
7430
+
7431
+ // extract events from button object and call
7432
+ var buttonEvents = rangeOptions.events && rangeOptions.events.click,
7433
+ callDefaultEvent;
7434
+
7435
+ if (buttonEvents) {
7436
+ callDefaultEvent = buttonEvents.call(rangeOptions);
7437
+ }
7438
+
7439
+ if (callDefaultEvent !== false) {
7440
+ rangeSelector.clickButton(i);
7441
+ }
7442
+
6535
7443
  rangeSelector.isActive = true;
6536
7444
  },
6537
7445
  buttonTheme,
@@ -6561,53 +7469,263 @@
6561
7469
 
6562
7470
  // Create the group to keep the inputs
6563
7471
  rangeSelector.inputGroup = inputGroup = renderer.g('input-group')
6564
- .add();
7472
+ .add(group);
6565
7473
  inputGroup.offset = 0;
6566
7474
 
6567
7475
  rangeSelector.drawInput('min');
6568
7476
  rangeSelector.drawInput('max');
6569
7477
  }
6570
7478
  }
7479
+
7480
+ plotLeft = chart.plotLeft - chart.spacing[3];
7481
+
6571
7482
  rangeSelector.updateButtonStates();
6572
7483
 
6573
- // Set or update the group position
6574
- buttonGroup[rendered ? 'animate' : 'attr']({
6575
- translateY: pos.buttonTop
7484
+ // detect collisiton with exporting
7485
+ if (
7486
+ navButtonOptions &&
7487
+ this.titleCollision(chart) &&
7488
+ verticalAlign === 'top' &&
7489
+ buttonPosition.align === 'right' &&
7490
+ (
7491
+ (buttonPosition.y + buttonGroup.getBBox().height - 12) <
7492
+ ((navButtonOptions.y || 0) + navButtonOptions.height - chart.spacing[0])
7493
+ )
7494
+ ) {
7495
+ exportingX = -40;
7496
+ }
7497
+
7498
+ // align button group
7499
+ buttonGroup.align(extend({
7500
+ y: pos.buttonTop,
7501
+ width: buttonGroup.getBBox().width,
7502
+ x: exportingX
7503
+ }, buttonPosition), true, chart.spacingBox);
7504
+
7505
+ translateX = buttonGroup.alignAttr.translateX + exportingX;
7506
+
7507
+ // detect left offset (axis title) or margin
7508
+ if (buttonPosition.align === 'left') {
7509
+ translateX += ((plotLeft < 0) || (H.isNumber(chart.margin[3])) ? 0 : plotLeft) - chart.spacing[3];
7510
+ } else if (buttonPosition.align === 'right') {
7511
+ translateX -= chart.spacing[1] + (H.isNumber(chart.margin[3]) ? plotLeft : 0);
7512
+ }
7513
+
7514
+ // Set / update the group position
7515
+ buttonGroup.attr({
7516
+ translateY: pos.buttonTop,
7517
+ translateX: translateX
6576
7518
  });
6577
7519
 
7520
+ // skip animation
7521
+ rangeSelector.group.placed = false;
7522
+ rangeSelector.buttonGroup.placed = false;
7523
+
6578
7524
  if (inputEnabled !== false) {
6579
7525
 
7526
+ var inputGroupX,
7527
+ inputGroupWidth,
7528
+ buttonGroupX,
7529
+ buttonGroupWidth;
7530
+
7531
+ // detect collision with exporting
7532
+ if (
7533
+ navButtonOptions &&
7534
+ this.titleCollision(chart) &&
7535
+ verticalAlign === 'top' &&
7536
+ inputPosition.align === 'right' &&
7537
+ (
7538
+ (pos.inputTop - inputGroup.getBBox().height - 12) <
7539
+ ((navButtonOptions.y || 0) + navButtonOptions.height + chart.spacing[0])
7540
+ )
7541
+ ) {
7542
+ exportingX = -40;
7543
+ } else {
7544
+ exportingX = 0;
7545
+ }
7546
+
6580
7547
  // Update the alignment to the updated spacing box
6581
7548
  inputGroup.align(extend({
6582
7549
  y: pos.inputTop,
6583
- width: inputGroup.offset,
6584
- // Detect collision with the exporting buttons
6585
- x: navButtonOptions && (pos.inputTop < (navButtonOptions.y || 0) + navButtonOptions.height - chart.spacing[0]) ?
6586
- -40 : 0
6587
- }, options.inputPosition), true, chart.spacingBox);
6588
-
6589
- // Hide if overlapping - inputEnabled is null or undefined
6590
- if (!defined(inputEnabled)) {
6591
- buttonBBox = buttonGroup.getBBox();
6592
- inputGroup[inputGroup.alignAttr.translateX < buttonBBox.x + buttonBBox.width + 10 ? 'hide' : 'show']();
7550
+ width: inputGroup.getBBox().width
7551
+ }, inputPosition), true, chart.spacingBox);
7552
+
7553
+ translateX = inputGroup.alignAttr.translateX + exportingX;
7554
+
7555
+ if (inputPosition.align === 'left') {
7556
+ translateX += plotLeft;
7557
+ } else if (
7558
+ inputPosition.align === 'right'
7559
+ ) {
7560
+ translateX = translateX - chart.axisOffset[1]; // yAxis offset
7561
+ }
7562
+
7563
+ // add y from user options
7564
+ inputGroup.attr({
7565
+ translateY: pos.inputTop + 10,
7566
+ translateX: translateX - (inputPosition.align === 'right' ? 2 : 0) // fix wrong getBBox() value on right align
7567
+ });
7568
+
7569
+ // detect collision
7570
+ inputGroupX = inputGroup.translateX + inputGroup.alignOptions.x -
7571
+ exportingX + inputGroup.getBBox().x + 2; // getBBox for detecing left margin, 2px padding to not overlap input and label
7572
+
7573
+ inputGroupWidth = inputGroup.alignOptions.width;
7574
+
7575
+ buttonGroupX = buttonGroup.translateX + buttonGroup.getBBox().x;
7576
+ buttonGroupWidth = buttonGroup.getBBox().width + 20; // 20 is minimal spacing between elements
7577
+
7578
+ if (
7579
+ (inputPosition.align === buttonPosition.align) ||
7580
+ (
7581
+ (buttonGroupX + buttonGroupWidth > inputGroupX) &&
7582
+ (inputGroupX + inputGroupWidth > buttonGroupX) &&
7583
+ (buttonPositionY < (inputPositionY + inputGroup.getBBox().height))
7584
+ )
7585
+ ) {
7586
+
7587
+ // move the element to the second line
7588
+ inputGroup.attr({
7589
+ translateX: inputGroup.translateX,
7590
+ translateY: inputGroup.translateY + buttonGroup.getBBox().height + 10
7591
+ });
6593
7592
  }
6594
7593
 
6595
7594
  // Set or reset the input values
6596
7595
  rangeSelector.setInputValue('min', min);
6597
7596
  rangeSelector.setInputValue('max', max);
7597
+
7598
+ // skip animation
7599
+ rangeSelector.inputGroup.placed = false;
7600
+ }
7601
+
7602
+ // vertical align
7603
+ rangeSelector.group.align({
7604
+ verticalAlign: verticalAlign
7605
+ }, true, chart.spacingBox);
7606
+
7607
+ // set position
7608
+ groupHeight = rangeSelector.group.getBBox().height + 20; // # 20 padding
7609
+
7610
+ // calculate bottom position
7611
+ if (verticalAlign === 'bottom') {
7612
+ legendHeight = legendOptions && legendOptions.verticalAlign === 'bottom' && legendOptions.enabled &&
7613
+ !legendOptions.floating ? legend.legendHeight + pick(legendOptions.margin, 10) : 0;
7614
+
7615
+ groupHeight = groupHeight + legendHeight - 20;
7616
+ }
7617
+
7618
+ groupOffsetY = Math[verticalAlign === 'middle' ? 'max' : 'min'](inputPositionY, buttonPositionY);
7619
+
7620
+ if (inputGroup && (inputPositionY < buttonPositionY) && verticalAlign === 'bottom') {
7621
+ groupOffsetY += inputGroup.getBBox().height;
7622
+ }
7623
+
7624
+ // fix the position
7625
+ alignTranslateY = rangeSelector.group.alignAttr.translateY;
7626
+ minPosition = (inputPositionY < 0 && buttonPositionY < 0) ? 0 : groupOffsetY;
7627
+ translateY = Math.floor(alignTranslateY - groupHeight - minPosition);
7628
+
7629
+ if (verticalAlign === 'top') {
7630
+ if (floating) {
7631
+ translateY = 0;
7632
+ } else if (chart.spacing[0] !== chart.options.chart.spacing[0]) { // detect if spacing is customised
7633
+ translateY -= (chart.spacing[0] - chart.options.chart.spacing[0]);
7634
+ }
7635
+ } else if (verticalAlign === 'middle') {
7636
+ if (inputPositionY === buttonPositionY) {
7637
+ if (inputPositionY < 0) {
7638
+ translateY = alignTranslateY + minPosition;
7639
+ } else {
7640
+ translateY = alignTranslateY;
7641
+ }
7642
+ } else if (inputPositionY || buttonPositionY) {
7643
+ if (inputPositionY < 0 || buttonPositionY < 0) {
7644
+ translateY -= Math.min(inputPositionY, buttonPositionY);
7645
+ } else {
7646
+ translateY = alignTranslateY - groupHeight + minPosition;
7647
+ }
7648
+ }
7649
+ }
7650
+
7651
+ translateY = Math.floor(translateY);
7652
+
7653
+ if (floating) {
7654
+ translateY += options.y;
7655
+ }
7656
+
7657
+ rangeSelector.group.translate(0 + options.x, translateY - 3); // floor to avoid crisp edges, 3px to keep back compatibility
7658
+
7659
+ // translate HTML inputs
7660
+ if (inputEnabled !== false) {
7661
+ rangeSelector.minInput.style.marginTop = rangeSelector.group.translateY + 'px';
7662
+ rangeSelector.maxInput.style.marginTop = rangeSelector.group.translateY + 'px';
6598
7663
  }
6599
7664
 
6600
7665
  rangeSelector.rendered = true;
6601
7666
  },
6602
7667
 
7668
+ /**
7669
+ * Extracts height of range selector
7670
+ * @return {Number} Returns rangeSelector height
7671
+ */
7672
+ getHeight: function() {
7673
+ var rangeSelector = this,
7674
+ options = rangeSelector.options,
7675
+ inputPosition = options.inputPosition,
7676
+ buttonPosition = options.buttonPosition,
7677
+ yPosition = options.y,
7678
+ rangeSelectorGroup = rangeSelector.group,
7679
+ buttonPositionY = buttonPosition.y,
7680
+ inputPositionY = inputPosition.y,
7681
+ rangeSelectorHeight = 0,
7682
+ minPosition;
7683
+
7684
+ rangeSelectorHeight = rangeSelectorGroup ? (rangeSelectorGroup.getBBox(true).height) + 13 + yPosition : 0; // 13px to keep back compatibility
7685
+ minPosition = Math.min(inputPositionY, buttonPositionY);
7686
+
7687
+ if (
7688
+ (inputPositionY < 0 && buttonPositionY < 0) ||
7689
+ (inputPositionY > 0 && buttonPositionY > 0)
7690
+ ) {
7691
+ rangeSelectorHeight += Math.abs(minPosition);
7692
+ }
7693
+
7694
+ return rangeSelectorHeight;
7695
+ },
7696
+
7697
+ /**
7698
+ * Detect collision with title or subtitle
7699
+ * @param {object} chart
7700
+ * @return {Boolean} Returns collision status
7701
+ */
7702
+ titleCollision: function(chart) {
7703
+ var status = false;
7704
+
7705
+ if (
7706
+ (!H.isObject(chart.title) ||
7707
+ (chart.title && chart.title.getBBox().y > chart.plotTop)
7708
+ ) && (!H.isObject(chart.subtitle) ||
7709
+ (chart.subtitle && chart.subtitle.getBBox().y > chart.plotTop)
7710
+ )
7711
+ ) {
7712
+ status = true;
7713
+ }
7714
+
7715
+ return status;
7716
+ },
7717
+
6603
7718
  /**
6604
7719
  * Update the range selector with new options
7720
+ * @param {object} options
6605
7721
  */
6606
7722
  update: function(options) {
6607
7723
  var chart = this.chart;
7724
+
6608
7725
  merge(true, chart.options.rangeSelector, options);
6609
7726
  this.destroy();
6610
7727
  this.init(chart);
7728
+ chart.rangeSelector.render();
6611
7729
  },
6612
7730
 
6613
7731
  /**
@@ -6740,7 +7858,7 @@
6740
7858
 
6741
7859
  };
6742
7860
 
6743
- // Initialize scroller for stock charts
7861
+ // Initialize rangeselector for stock charts
6744
7862
  wrap(Chart.prototype, 'init', function(proceed, options, callback) {
6745
7863
 
6746
7864
  addEvent(this, 'init', function() {
@@ -6753,6 +7871,103 @@
6753
7871
 
6754
7872
  });
6755
7873
 
7874
+ wrap(Chart.prototype, 'render', function(proceed, options, callback) {
7875
+
7876
+ var chart = this,
7877
+ rangeSelector = chart.rangeSelector,
7878
+ verticalAlign;
7879
+
7880
+ if (rangeSelector) {
7881
+
7882
+ rangeSelector.render();
7883
+ verticalAlign = rangeSelector.options.verticalAlign;
7884
+
7885
+ if (!rangeSelector.options.floating) {
7886
+ if (verticalAlign === 'bottom') {
7887
+ this.extraBottomMargin = true;
7888
+ } else if (verticalAlign !== 'middle') {
7889
+ this.extraTopMargin = true;
7890
+ }
7891
+ }
7892
+ }
7893
+
7894
+ proceed.call(this, options, callback);
7895
+
7896
+ });
7897
+
7898
+ wrap(Chart.prototype, 'update', function(proceed, options, redraw, oneToOne) {
7899
+
7900
+ var chart = this,
7901
+ rangeSelector = chart.rangeSelector,
7902
+ verticalAlign;
7903
+
7904
+ this.extraBottomMargin = false;
7905
+ this.extraTopMargin = false;
7906
+
7907
+ if (rangeSelector) {
7908
+
7909
+ rangeSelector.render();
7910
+
7911
+ verticalAlign = (options.rangeSelector && options.rangeSelector.verticalAlign) ||
7912
+ (rangeSelector.options && rangeSelector.options.verticalAlign);
7913
+
7914
+ if (!rangeSelector.options.floating) {
7915
+ if (verticalAlign === 'bottom') {
7916
+ this.extraBottomMargin = true;
7917
+ } else if (verticalAlign !== 'middle') {
7918
+ this.extraTopMargin = true;
7919
+ }
7920
+ }
7921
+ }
7922
+
7923
+ proceed.call(this, H.merge(true, options, {
7924
+ chart: {
7925
+ marginBottom: pick(options.chart && options.chart.marginBottom, chart.margin.bottom),
7926
+ spacingBottom: pick(options.chart && options.chart.spacingBottom, chart.spacing.bottom)
7927
+ }
7928
+ }), redraw, oneToOne);
7929
+
7930
+ });
7931
+
7932
+ wrap(Chart.prototype, 'redraw', function(proceed, options, callback) {
7933
+ var chart = this,
7934
+ rangeSelector = chart.rangeSelector,
7935
+ verticalAlign;
7936
+
7937
+ if (rangeSelector && !rangeSelector.options.floating) {
7938
+
7939
+ rangeSelector.render();
7940
+ verticalAlign = rangeSelector.options.verticalAlign;
7941
+
7942
+ if (verticalAlign === 'bottom') {
7943
+ this.extraBottomMargin = true;
7944
+ } else if (verticalAlign !== 'middle') {
7945
+ this.extraTopMargin = true;
7946
+ }
7947
+ }
7948
+
7949
+ proceed.call(this, options, callback);
7950
+ });
7951
+
7952
+ Chart.prototype.adjustPlotArea = function() {
7953
+ var chart = this,
7954
+ rangeSelector = chart.rangeSelector,
7955
+ rangeSelectorHeight;
7956
+
7957
+ if (this.rangeSelector) {
7958
+
7959
+ rangeSelectorHeight = rangeSelector.getHeight();
7960
+
7961
+ if (this.extraTopMargin) {
7962
+ this.plotTop += rangeSelectorHeight;
7963
+ }
7964
+
7965
+ if (this.extraBottomMargin) {
7966
+ this.marginBottom += rangeSelectorHeight;
7967
+ }
7968
+ }
7969
+ };
7970
+
6756
7971
  Chart.prototype.callbacks.push(function(chart) {
6757
7972
  var extremes,
6758
7973
  rangeSelector = chart.rangeSelector,
@@ -6796,7 +8011,7 @@
6796
8011
  H.RangeSelector = RangeSelector;
6797
8012
 
6798
8013
  /* ****************************************************************************
6799
- * End Range Selector code *
8014
+ * End Range Selector code *
6800
8015
  *****************************************************************************/
6801
8016
 
6802
8017
  }(Highcharts));
@@ -6835,6 +8050,53 @@
6835
8050
  seriesProcessData = seriesProto.processData,
6836
8051
  pointTooltipFormatter = Point.prototype.tooltipFormatter;
6837
8052
 
8053
+
8054
+ /**
8055
+ * Compare the values of the series against the first non-null, non-
8056
+ * zero value in the visible range. The y axis will show percentage
8057
+ * or absolute change depending on whether `compare` is set to `"percent"`
8058
+ * or `"value"`. When this is applied to multiple series, it allows
8059
+ * comparing the development of the series against each other.
8060
+ *
8061
+ * @type {String}
8062
+ * @see [compareBase](#plotOptions.series.compareBase), [Axis.setCompare()](#Axis.
8063
+ * setCompare())
8064
+ * @sample {highstock} stock/plotoptions/series-compare-percent/ Percent
8065
+ * @sample {highstock} stock/plotoptions/series-compare-value/ Value
8066
+ * @default undefined
8067
+ * @since 1.0.1
8068
+ * @product highstock
8069
+ * @apioption plotOptions.series.compare
8070
+ */
8071
+
8072
+ /**
8073
+ * Defines if comparisson should start from the first point within the visible
8074
+ * range or should start from the first point <b>before</b> the range.
8075
+ * In other words, this flag determines if first point within the visible range
8076
+ * will have 0% (base) or should have been already calculated according to the
8077
+ * previous point.
8078
+ *
8079
+ * @type {Boolean}
8080
+ * @sample {highstock} stock/plotoptions/series-comparestart/ Calculate compare within visible range
8081
+ * @default undefined
8082
+ * @since 6.0.0
8083
+ * @product highstock
8084
+ * @apioption plotOptions.series.compareStart
8085
+ */
8086
+
8087
+ /**
8088
+ * When [compare](#plotOptions.series.compare) is `percent`, this option
8089
+ * dictates whether to use 0 or 100 as the base of comparison.
8090
+ *
8091
+ * @validvalue [0, 100]
8092
+ * @type {Number}
8093
+ * @sample {highstock} / Compare base is 100
8094
+ * @default 0
8095
+ * @since 5.0.6
8096
+ * @product highstock
8097
+ * @apioption plotOptions.series.compareBase
8098
+ */
8099
+
6838
8100
  /**
6839
8101
  * Factory function for creating new stock charts. Creates a new {@link Chart|
6840
8102
  * Chart} object with different default options than the basic Chart.
@@ -6905,6 +8167,7 @@
6905
8167
  return merge({ // defaults
6906
8168
  minPadding: 0,
6907
8169
  maxPadding: 0,
8170
+ overscroll: 0,
6908
8171
  ordinal: true,
6909
8172
  title: {
6910
8173
  text: null
@@ -6964,7 +8227,7 @@
6964
8227
  text: null
6965
8228
  },
6966
8229
  tooltip: {
6967
- shared: true,
8230
+ split: true,
6968
8231
  crosshairs: true
6969
8232
  },
6970
8233
  legend: {
@@ -7049,7 +8312,7 @@
7049
8312
  x2,
7050
8313
  y2,
7051
8314
  result = [],
7052
- axes = [], //#3416 need a default array
8315
+ axes = [], // #3416 need a default array
7053
8316
  axes2,
7054
8317
  uniqueAxes,
7055
8318
  transVal;
@@ -7102,7 +8365,7 @@
7102
8365
  // Remove duplicates in the axes array. If there are no axes in the axes array,
7103
8366
  // we are adding an axis without data, so we need to populate this with grid
7104
8367
  // lines (#2796).
7105
- uniqueAxes = axes.length ? [] : [axis.isXAxis ? chart.yAxis[0] : chart.xAxis[0]]; //#3742
8368
+ uniqueAxes = axes.length ? [] : [axis.isXAxis ? chart.yAxis[0] : chart.xAxis[0]]; // #3742
7106
8369
  each(axes, function(axis2) {
7107
8370
  if (
7108
8371
  inArray(axis2, uniqueAxes) === -1 &&
@@ -7159,7 +8422,7 @@
7159
8422
  }
7160
8423
  return result.length > 0 ?
7161
8424
  renderer.crispPolyLine(result, lineWidth || 1) :
7162
- null; //#3557 getPlotLinePath in regular Highcharts also returns null
8425
+ null; // #3557 getPlotLinePath in regular Highcharts also returns null
7163
8426
  });
7164
8427
 
7165
8428
  // Override getPlotBandPath to allow for multipane charts
@@ -7442,6 +8705,7 @@
7442
8705
  keyIndex = -1,
7443
8706
  processedXData,
7444
8707
  processedYData,
8708
+ compareStart = series.options.compareStart === true ? 0 : 1,
7445
8709
  length,
7446
8710
  compareValue;
7447
8711
 
@@ -7466,11 +8730,15 @@
7466
8730
  }
7467
8731
 
7468
8732
  // find the first value for comparison
7469
- for (i = 0; i < length - 1; i++) {
8733
+ for (i = 0; i < length - compareStart; i++) {
7470
8734
  compareValue = processedYData[i] && keyIndex > -1 ?
7471
8735
  processedYData[i][keyIndex] :
7472
8736
  processedYData[i];
7473
- if (isNumber(compareValue) && processedXData[i + 1] >= series.xAxis.min && compareValue !== 0) {
8737
+ if (
8738
+ isNumber(compareValue) &&
8739
+ processedXData[i + compareStart] >= series.xAxis.min &&
8740
+ compareValue !== 0
8741
+ ) {
7474
8742
  series.compareValue = compareValue;
7475
8743
  break;
7476
8744
  }