highcharts-rails 5.0.14 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +60 -0
  3. data/Rakefile +54 -5
  4. data/app/assets/images/highcharts/earth.svg +432 -0
  5. data/app/assets/javascripts/highcharts.js +5103 -3147
  6. data/app/assets/javascripts/highcharts/highcharts-3d.js +930 -277
  7. data/app/assets/javascripts/highcharts/highcharts-more.js +1374 -249
  8. data/app/assets/javascripts/highcharts/lib/canvg.js +3073 -0
  9. data/app/assets/javascripts/highcharts/lib/jspdf.js +16624 -0
  10. data/app/assets/javascripts/highcharts/lib/rgbcolor.js +299 -0
  11. data/app/assets/javascripts/highcharts/lib/svg2pdf.js +3488 -0
  12. data/app/assets/javascripts/highcharts/modules/accessibility.js +654 -212
  13. data/app/assets/javascripts/highcharts/modules/annotations.js +1552 -274
  14. data/app/assets/javascripts/highcharts/modules/boost-canvas.js +773 -0
  15. data/app/assets/javascripts/highcharts/modules/boost.js +636 -210
  16. data/app/assets/javascripts/highcharts/modules/broken-axis.js +2 -2
  17. data/app/assets/javascripts/highcharts/modules/bullet.js +364 -0
  18. data/app/assets/javascripts/highcharts/modules/data.js +766 -38
  19. data/app/assets/javascripts/highcharts/modules/drag-panes.js +588 -0
  20. data/app/assets/javascripts/highcharts/modules/drilldown.js +106 -36
  21. data/app/assets/javascripts/highcharts/modules/export-data.js +597 -0
  22. data/app/assets/javascripts/highcharts/modules/exporting.js +424 -162
  23. data/app/assets/javascripts/highcharts/modules/funnel.js +144 -22
  24. data/app/assets/javascripts/highcharts/modules/gantt.js +1154 -0
  25. data/app/assets/javascripts/highcharts/modules/grid-axis.js +1 -1
  26. data/app/assets/javascripts/highcharts/modules/heatmap.js +406 -80
  27. data/app/assets/javascripts/highcharts/modules/histogram-bellcurve.js +513 -0
  28. data/app/assets/javascripts/highcharts/modules/item-series.js +126 -0
  29. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +31 -13
  30. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +179 -57
  31. data/app/assets/javascripts/highcharts/modules/oldie.js +1378 -0
  32. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +8 -6
  33. data/app/assets/javascripts/highcharts/modules/parallel-coordinates.js +494 -0
  34. data/app/assets/javascripts/highcharts/modules/pareto.js +275 -0
  35. data/app/assets/javascripts/highcharts/modules/sankey.js +641 -0
  36. data/app/assets/javascripts/highcharts/modules/series-label.js +355 -145
  37. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +122 -1
  38. data/app/assets/javascripts/highcharts/modules/static-scale.js +64 -0
  39. data/app/assets/javascripts/highcharts/modules/stock.js +1944 -676
  40. data/app/assets/javascripts/highcharts/modules/streamgraph.js +139 -0
  41. data/app/assets/javascripts/highcharts/modules/sunburst.js +2403 -0
  42. data/app/assets/javascripts/highcharts/modules/tilemap.js +1199 -0
  43. data/app/assets/javascripts/highcharts/modules/treemap.js +538 -134
  44. data/app/assets/javascripts/highcharts/modules/variable-pie.js +490 -0
  45. data/app/assets/javascripts/highcharts/modules/variwide.js +283 -0
  46. data/app/assets/javascripts/highcharts/modules/vector.js +294 -0
  47. data/app/assets/javascripts/highcharts/modules/windbarb.js +490 -0
  48. data/app/assets/javascripts/highcharts/modules/wordcloud.js +681 -0
  49. data/app/assets/javascripts/highcharts/modules/xrange.js +615 -0
  50. data/app/assets/javascripts/highcharts/themes/avocado.js +54 -0
  51. data/app/assets/javascripts/highcharts/themes/dark-blue.js +6 -6
  52. data/app/assets/javascripts/highcharts/themes/dark-green.js +6 -6
  53. data/app/assets/javascripts/highcharts/themes/dark-unica.js +6 -6
  54. data/app/assets/javascripts/highcharts/themes/gray.js +14 -10
  55. data/app/assets/javascripts/highcharts/themes/grid-light.js +6 -6
  56. data/app/assets/javascripts/highcharts/themes/grid.js +7 -5
  57. data/app/assets/javascripts/highcharts/themes/sand-signika.js +8 -7
  58. data/app/assets/javascripts/highcharts/themes/skies.js +15 -9
  59. data/app/assets/javascripts/highcharts/themes/sunset.js +53 -0
  60. data/app/assets/stylesheets/highcharts/highcharts.css +802 -0
  61. data/app/assets/stylesheets/highcharts/highcharts.scss +665 -0
  62. data/lib/highcharts/version.rb +1 -1
  63. metadata +31 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.14 (2017-07-28)
2
+ * @license Highcharts JS v6.0.0 (2017-10-04)
3
3
  * 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
  }