AreaSeries.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /* *
  2. *
  3. * (c) 2010-2021 Torstein Honsi
  4. *
  5. * License: www.highcharts.com/license
  6. *
  7. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8. *
  9. * */
  10. 'use strict';
  11. var __extends = (this && this.__extends) || (function () {
  12. var extendStatics = function (d, b) {
  13. extendStatics = Object.setPrototypeOf ||
  14. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  15. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  16. return extendStatics(d, b);
  17. };
  18. return function (d, b) {
  19. extendStatics(d, b);
  20. function __() { this.constructor = d; }
  21. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  22. };
  23. })();
  24. import Color from '../../Core/Color/Color.js';
  25. var color = Color.parse;
  26. import LegendSymbolMixin from '../../Mixins/LegendSymbol.js';
  27. import SeriesRegistry from '../../Core/Series/SeriesRegistry.js';
  28. var LineSeries = SeriesRegistry.seriesTypes.line;
  29. import U from '../../Core/Utilities.js';
  30. var extend = U.extend, merge = U.merge, objectEach = U.objectEach, pick = U.pick;
  31. /* *
  32. *
  33. * Class
  34. *
  35. * */
  36. /**
  37. * Area series type.
  38. *
  39. * @private
  40. * @class
  41. * @name AreaSeries
  42. *
  43. * @augments LineSeries
  44. */
  45. var AreaSeries = /** @class */ (function (_super) {
  46. __extends(AreaSeries, _super);
  47. function AreaSeries() {
  48. /* *
  49. *
  50. * Static Properties
  51. *
  52. * */
  53. var _this = _super !== null && _super.apply(this, arguments) || this;
  54. _this.data = void 0;
  55. _this.options = void 0;
  56. _this.points = void 0;
  57. return _this;
  58. /* eslint-enable valid-jsdoc */
  59. }
  60. /* *
  61. *
  62. * Functions
  63. *
  64. * */
  65. /* eslint-disable valid-jsdoc */
  66. /**
  67. * Draw the graph and the underlying area. This method calls the Series
  68. * base function and adds the area. The areaPath is calculated in the
  69. * getSegmentPath method called from Series.prototype.drawGraph.
  70. * @private
  71. */
  72. AreaSeries.prototype.drawGraph = function () {
  73. // Define or reset areaPath
  74. this.areaPath = [];
  75. // Call the base method
  76. _super.prototype.drawGraph.apply(this);
  77. // Define local variables
  78. var series = this, areaPath = this.areaPath, options = this.options, zones = this.zones, props = [[
  79. 'area',
  80. 'highcharts-area',
  81. this.color,
  82. options.fillColor
  83. ]]; // area name, main color, fill color
  84. zones.forEach(function (zone, i) {
  85. props.push([
  86. 'zone-area-' + i,
  87. 'highcharts-area highcharts-zone-area-' + i + ' ' +
  88. zone.className,
  89. zone.color || series.color,
  90. zone.fillColor || options.fillColor
  91. ]);
  92. });
  93. props.forEach(function (prop) {
  94. var areaKey = prop[0], area = series[areaKey], verb = area ? 'animate' : 'attr', attribs = {};
  95. // Create or update the area
  96. if (area) { // update
  97. area.endX = series.preventGraphAnimation ?
  98. null :
  99. areaPath.xMap;
  100. area.animate({ d: areaPath });
  101. }
  102. else { // create
  103. attribs.zIndex = 0; // #1069
  104. area = series[areaKey] = series.chart.renderer
  105. .path(areaPath)
  106. .addClass(prop[1])
  107. .add(series.group);
  108. area.isArea = true;
  109. }
  110. if (!series.chart.styledMode) {
  111. attribs.fill = pick(prop[3], color(prop[2])
  112. .setOpacity(pick(options.fillOpacity, 0.75))
  113. .get());
  114. }
  115. area[verb](attribs);
  116. area.startX = areaPath.xMap;
  117. area.shiftUnit = options.step ? 2 : 1;
  118. });
  119. };
  120. /**
  121. * @private
  122. */
  123. AreaSeries.prototype.getGraphPath = function (points) {
  124. var getGraphPath = LineSeries.prototype.getGraphPath, graphPath, options = this.options, stacking = options.stacking, yAxis = this.yAxis, topPath, bottomPath, bottomPoints = [], graphPoints = [], seriesIndex = this.index, i, areaPath, plotX, stacks = yAxis.stacking.stacks[this.stackKey], threshold = options.threshold, translatedThreshold = Math.round(// #10909
  125. yAxis.getThreshold(options.threshold)), isNull, yBottom, connectNulls = pick(// #10574
  126. options.connectNulls, stacking === 'percent'),
  127. // To display null points in underlying stacked series, this
  128. // series graph must be broken, and the area also fall down to
  129. // fill the gap left by the null point. #2069
  130. addDummyPoints = function (i, otherI, side) {
  131. var point = points[i], stackedValues = stacking &&
  132. stacks[point.x].points[seriesIndex], nullVal = point[side + 'Null'] || 0, cliffVal = point[side + 'Cliff'] || 0, top, bottom, isNull = true;
  133. if (cliffVal || nullVal) {
  134. top = (nullVal ?
  135. stackedValues[0] :
  136. stackedValues[1]) + cliffVal;
  137. bottom = stackedValues[0] + cliffVal;
  138. isNull = !!nullVal;
  139. }
  140. else if (!stacking &&
  141. points[otherI] &&
  142. points[otherI].isNull) {
  143. top = bottom = threshold;
  144. }
  145. // Add to the top and bottom line of the area
  146. if (typeof top !== 'undefined') {
  147. graphPoints.push({
  148. plotX: plotX,
  149. plotY: top === null ?
  150. translatedThreshold :
  151. yAxis.getThreshold(top),
  152. isNull: isNull,
  153. isCliff: true
  154. });
  155. bottomPoints.push({
  156. plotX: plotX,
  157. plotY: bottom === null ?
  158. translatedThreshold :
  159. yAxis.getThreshold(bottom),
  160. doCurve: false // #1041, gaps in areaspline areas
  161. });
  162. }
  163. };
  164. // Find what points to use
  165. points = points || this.points;
  166. // Fill in missing points
  167. if (stacking) {
  168. points = this.getStackPoints(points);
  169. }
  170. for (i = 0; i < points.length; i++) {
  171. // Reset after series.update of stacking property (#12033)
  172. if (!stacking) {
  173. points[i].leftCliff = points[i].rightCliff =
  174. points[i].leftNull = points[i].rightNull = void 0;
  175. }
  176. isNull = points[i].isNull;
  177. plotX = pick(points[i].rectPlotX, points[i].plotX);
  178. yBottom = stacking ? pick(points[i].yBottom, translatedThreshold) : translatedThreshold;
  179. if (!isNull || connectNulls) {
  180. if (!connectNulls) {
  181. addDummyPoints(i, i - 1, 'left');
  182. }
  183. // Skip null point when stacking is false and connectNulls
  184. // true
  185. if (!(isNull && !stacking && connectNulls)) {
  186. graphPoints.push(points[i]);
  187. bottomPoints.push({
  188. x: i,
  189. plotX: plotX,
  190. plotY: yBottom
  191. });
  192. }
  193. if (!connectNulls) {
  194. addDummyPoints(i, i + 1, 'right');
  195. }
  196. }
  197. }
  198. topPath = getGraphPath.call(this, graphPoints, true, true);
  199. bottomPoints.reversed = true;
  200. bottomPath = getGraphPath.call(this, bottomPoints, true, true);
  201. var firstBottomPoint = bottomPath[0];
  202. if (firstBottomPoint && firstBottomPoint[0] === 'M') {
  203. bottomPath[0] = ['L', firstBottomPoint[1], firstBottomPoint[2]];
  204. }
  205. areaPath = topPath.concat(bottomPath);
  206. if (areaPath.length) {
  207. areaPath.push(['Z']);
  208. }
  209. // TODO: don't set leftCliff and rightCliff when connectNulls?
  210. graphPath = getGraphPath
  211. .call(this, graphPoints, false, connectNulls);
  212. areaPath.xMap = topPath.xMap;
  213. this.areaPath = areaPath;
  214. return graphPath;
  215. };
  216. /**
  217. * Return an array of stacked points, where null and missing points are
  218. * replaced by dummy points in order for gaps to be drawn correctly in
  219. * stacks.
  220. * @private
  221. */
  222. AreaSeries.prototype.getStackPoints = function (points) {
  223. var series = this, segment = [], keys = [], xAxis = this.xAxis, yAxis = this.yAxis, stack = yAxis.stacking.stacks[this.stackKey], pointMap = {}, yAxisSeries = yAxis.series, seriesLength = yAxisSeries.length, upOrDown = yAxis.options.reversedStacks ? 1 : -1, seriesIndex = yAxisSeries.indexOf(series);
  224. points = points || this.points;
  225. if (this.options.stacking) {
  226. for (var i = 0; i < points.length; i++) {
  227. // Reset after point update (#7326)
  228. points[i].leftNull = points[i].rightNull = void 0;
  229. // Create a map where we can quickly look up the points by
  230. // their X values.
  231. pointMap[points[i].x] = points[i];
  232. }
  233. // Sort the keys (#1651)
  234. objectEach(stack, function (stackX, x) {
  235. // nulled after switching between
  236. // grouping and not (#1651, #2336)
  237. if (stackX.total !== null) {
  238. keys.push(x);
  239. }
  240. });
  241. keys.sort(function (a, b) {
  242. return a - b;
  243. });
  244. var visibleSeries_1 = yAxisSeries.map(function (s) { return s.visible; });
  245. keys.forEach(function (x, idx) {
  246. var y = 0, stackPoint, stackedValues;
  247. if (pointMap[x] && !pointMap[x].isNull) {
  248. segment.push(pointMap[x]);
  249. // Find left and right cliff. -1 goes left, 1 goes
  250. // right.
  251. [-1, 1].forEach(function (direction) {
  252. var nullName = direction === 1 ?
  253. 'rightNull' :
  254. 'leftNull', cliffName = direction === 1 ?
  255. 'rightCliff' :
  256. 'leftCliff', cliff = 0, otherStack = stack[keys[idx + direction]];
  257. // If there is a stack next to this one,
  258. // to the left or to the right...
  259. if (otherStack) {
  260. var i = seriesIndex;
  261. // Can go either up or down,
  262. // depending on reversedStacks
  263. while (i >= 0 && i < seriesLength) {
  264. var si = yAxisSeries[i].index;
  265. stackPoint = otherStack.points[si];
  266. if (!stackPoint) {
  267. // If the next point in this series
  268. // is missing, mark the point
  269. // with point.leftNull or
  270. // point.rightNull = true.
  271. if (si === series.index) {
  272. pointMap[x][nullName] = true;
  273. // If there are missing points in
  274. // the next stack in any of the
  275. // series below this one, we need
  276. // to substract the missing values
  277. // and add a hiatus to the left or
  278. // right.
  279. }
  280. else if (visibleSeries_1[i]) {
  281. stackedValues =
  282. stack[x].points[si];
  283. if (stackedValues) {
  284. cliff -= stackedValues[1] - stackedValues[0];
  285. }
  286. }
  287. }
  288. // When reversedStacks is true, loop up,
  289. // else loop down
  290. i += upOrDown;
  291. }
  292. }
  293. pointMap[x][cliffName] = cliff;
  294. });
  295. // There is no point for this X value in this series, so we
  296. // insert a dummy point in order for the areas to be drawn
  297. // correctly.
  298. }
  299. else {
  300. // Loop down the stack to find the series below this
  301. // one that has a value (#1991)
  302. var i = seriesIndex;
  303. while (i >= 0 && i < seriesLength) {
  304. var si = yAxisSeries[i].index;
  305. stackPoint = stack[x].points[si];
  306. if (stackPoint) {
  307. y = stackPoint[1];
  308. break;
  309. }
  310. // When reversedStacks is true, loop up, else loop
  311. // down
  312. i += upOrDown;
  313. }
  314. y = pick(y, 0);
  315. y = yAxis.translate(// #6272
  316. y, 0, 1, 0, 1);
  317. segment.push({
  318. isNull: true,
  319. plotX: xAxis.translate(// #6272
  320. x, 0, 0, 0, 1),
  321. x: x,
  322. plotY: y,
  323. yBottom: y
  324. });
  325. }
  326. });
  327. }
  328. return segment;
  329. };
  330. /**
  331. * The area series type.
  332. *
  333. * @sample {highcharts} highcharts/demo/area-basic/
  334. * Area chart
  335. * @sample {highstock} stock/demo/area/
  336. * Area chart
  337. *
  338. * @extends plotOptions.line
  339. * @excluding useOhlcData
  340. * @product highcharts highstock
  341. * @optionparent plotOptions.area
  342. */
  343. AreaSeries.defaultOptions = merge(LineSeries.defaultOptions, {
  344. /**
  345. * @see [fillColor](#plotOptions.area.fillColor)
  346. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  347. *
  348. * @apioption plotOptions.area.color
  349. */
  350. /**
  351. * Fill color or gradient for the area. When `null`, the series' `color`
  352. * is used with the series' `fillOpacity`.
  353. *
  354. * In styled mode, the fill color can be set with the `.highcharts-area`
  355. * class name.
  356. *
  357. * @see [color](#plotOptions.area.color)
  358. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  359. *
  360. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-default/
  361. * Null by default
  362. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-gradient/
  363. * Gradient
  364. *
  365. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  366. * @product highcharts highstock
  367. * @apioption plotOptions.area.fillColor
  368. */
  369. /**
  370. * Fill opacity for the area. When you set an explicit `fillColor`,
  371. * the `fillOpacity` is not applied. Instead, you should define the
  372. * opacity in the `fillColor` with an rgba color definition. The
  373. * `fillOpacity` setting, also the default setting, overrides the alpha
  374. * component of the `color` setting.
  375. *
  376. * In styled mode, the fill opacity can be set with the
  377. * `.highcharts-area` class name.
  378. *
  379. * @see [color](#plotOptions.area.color)
  380. * @see [fillColor](#plotOptions.area.fillColor)
  381. *
  382. * @sample {highcharts} highcharts/plotoptions/area-fillopacity/
  383. * Automatic fill color and fill opacity of 0.1
  384. *
  385. * @type {number}
  386. * @default {highcharts} 0.75
  387. * @default {highstock} 0.75
  388. * @product highcharts highstock
  389. * @apioption plotOptions.area.fillOpacity
  390. */
  391. /**
  392. * A separate color for the graph line. By default the line takes the
  393. * `color` of the series, but the lineColor setting allows setting a
  394. * separate color for the line without altering the `fillColor`.
  395. *
  396. * In styled mode, the line stroke can be set with the
  397. * `.highcharts-graph` class name.
  398. *
  399. * @sample {highcharts} highcharts/plotoptions/area-linecolor/
  400. * Dark gray line
  401. *
  402. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  403. * @product highcharts highstock
  404. * @apioption plotOptions.area.lineColor
  405. */
  406. /**
  407. * A separate color for the negative part of the area.
  408. *
  409. * In styled mode, a negative color is set with the
  410. * `.highcharts-negative` class name.
  411. *
  412. * @see [negativeColor](#plotOptions.area.negativeColor)
  413. *
  414. * @sample {highcharts} highcharts/css/series-negative-color/
  415. * Negative color in styled mode
  416. *
  417. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  418. * @since 3.0
  419. * @product highcharts
  420. * @apioption plotOptions.area.negativeFillColor
  421. */
  422. /**
  423. * Whether the whole area or just the line should respond to mouseover
  424. * tooltips and other mouse or touch events.
  425. *
  426. * @sample {highcharts|highstock} highcharts/plotoptions/area-trackbyarea/
  427. * Display the tooltip when the area is hovered
  428. *
  429. * @type {boolean}
  430. * @default false
  431. * @since 1.1.6
  432. * @product highcharts highstock
  433. * @apioption plotOptions.area.trackByArea
  434. */
  435. /**
  436. * The Y axis value to serve as the base for the area, for
  437. * distinguishing between values above and below a threshold. The area
  438. * between the graph and the threshold is filled.
  439. *
  440. * * If a number is given, the Y axis will scale to the threshold.
  441. * * If `null`, the scaling behaves like a line series with fill between
  442. * the graph and the Y axis minimum.
  443. * * If `Infinity` or `-Infinity`, the area between the graph and the
  444. * corresponding Y axis extreme is filled (since v6.1.0).
  445. *
  446. * @sample {highcharts} highcharts/plotoptions/area-threshold/
  447. * A threshold of 100
  448. * @sample {highcharts} highcharts/plotoptions/area-threshold-infinity/
  449. * A threshold of Infinity
  450. *
  451. * @type {number|null}
  452. * @since 2.0
  453. * @product highcharts highstock
  454. */
  455. threshold: 0
  456. });
  457. return AreaSeries;
  458. }(LineSeries));
  459. extend(AreaSeries.prototype, {
  460. singleStacks: false,
  461. drawLegendSymbol: LegendSymbolMixin.drawRectangle
  462. });
  463. SeriesRegistry.registerSeriesType('area', AreaSeries);
  464. /* *
  465. *
  466. * Default Export
  467. *
  468. * */
  469. export default AreaSeries;
  470. /* *
  471. *
  472. * API Options
  473. *
  474. * */
  475. /**
  476. * A `area` series. If the [type](#series.area.type) option is not
  477. * specified, it is inherited from [chart.type](#chart.type).
  478. *
  479. * @extends series,plotOptions.area
  480. * @excluding dataParser, dataURL, useOhlcData
  481. * @product highcharts highstock
  482. * @apioption series.area
  483. */
  484. /**
  485. * @see [fillColor](#series.area.fillColor)
  486. * @see [fillOpacity](#series.area.fillOpacity)
  487. *
  488. * @apioption series.area.color
  489. */
  490. /**
  491. * An array of data points for the series. For the `area` series type,
  492. * points can be given in the following ways:
  493. *
  494. * 1. An array of numerical values. In this case, the numerical values will be
  495. * interpreted as `y` options. The `x` values will be automatically
  496. * calculated, either starting at 0 and incremented by 1, or from
  497. * `pointStart` * and `pointInterval` given in the series options. If the
  498. * axis has categories, these will be used. Example:
  499. * ```js
  500. * data: [0, 5, 3, 5]
  501. * ```
  502. *
  503. * 2. An array of arrays with 2 values. In this case, the values correspond to
  504. * `x,y`. If the first value is a string, it is applied as the name of the
  505. * point, and the `x` value is inferred.
  506. * ```js
  507. * data: [
  508. * [0, 9],
  509. * [1, 7],
  510. * [2, 6]
  511. * ]
  512. * ```
  513. *
  514. * 3. An array of objects with named values. The following snippet shows only a
  515. * few settings, see the complete options set below. If the total number of
  516. * data points exceeds the series'
  517. * [turboThreshold](#series.area.turboThreshold), this option is not
  518. * available.
  519. * ```js
  520. * data: [{
  521. * x: 1,
  522. * y: 9,
  523. * name: "Point2",
  524. * color: "#00FF00"
  525. * }, {
  526. * x: 1,
  527. * y: 6,
  528. * name: "Point1",
  529. * color: "#FF00FF"
  530. * }]
  531. * ```
  532. *
  533. * @sample {highcharts} highcharts/chart/reflow-true/
  534. * Numerical values
  535. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  536. * Arrays of numeric x and y
  537. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  538. * Arrays of datetime x and y
  539. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  540. * Arrays of point.name and y
  541. * @sample {highcharts} highcharts/series/data-array-of-objects/
  542. * Config objects
  543. *
  544. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  545. * @extends series.line.data
  546. * @product highcharts highstock
  547. * @apioption series.area.data
  548. */
  549. /**
  550. * @see [color](#series.area.color)
  551. * @see [fillOpacity](#series.area.fillOpacity)
  552. *
  553. * @apioption series.area.fillColor
  554. */
  555. /**
  556. * @see [color](#series.area.color)
  557. * @see [fillColor](#series.area.fillColor)
  558. *
  559. * @default {highcharts} 0.75
  560. * @default {highstock} 0.75
  561. * @apioption series.area.fillOpacity
  562. */
  563. ''; // adds doclets above to transpilat