AreaSeries.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  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. // TODO: don't set leftCliff and rightCliff when connectNulls?
  207. graphPath = getGraphPath
  208. .call(this, graphPoints, false, connectNulls);
  209. areaPath.xMap = topPath.xMap;
  210. this.areaPath = areaPath;
  211. return graphPath;
  212. };
  213. /**
  214. * Return an array of stacked points, where null and missing points are
  215. * replaced by dummy points in order for gaps to be drawn correctly in
  216. * stacks.
  217. * @private
  218. */
  219. AreaSeries.prototype.getStackPoints = function (points) {
  220. var series = this, segment = [], keys = [], xAxis = this.xAxis, yAxis = this.yAxis, stack = yAxis.stacking.stacks[this.stackKey], pointMap = {}, seriesIndex = series.index, yAxisSeries = yAxis.series, seriesLength = yAxisSeries.length, visibleSeries, upOrDown = pick(yAxis.options.reversedStacks, true) ? 1 : -1, i;
  221. points = points || this.points;
  222. if (this.options.stacking) {
  223. for (i = 0; i < points.length; i++) {
  224. // Reset after point update (#7326)
  225. points[i].leftNull = points[i].rightNull = void 0;
  226. // Create a map where we can quickly look up the points by
  227. // their X values.
  228. pointMap[points[i].x] = points[i];
  229. }
  230. // Sort the keys (#1651)
  231. objectEach(stack, function (stackX, x) {
  232. // nulled after switching between
  233. // grouping and not (#1651, #2336)
  234. if (stackX.total !== null) {
  235. keys.push(x);
  236. }
  237. });
  238. keys.sort(function (a, b) {
  239. return a - b;
  240. });
  241. visibleSeries = yAxisSeries.map(function (s) {
  242. return s.visible;
  243. });
  244. keys.forEach(function (x, idx) {
  245. var y = 0, stackPoint, stackedValues;
  246. if (pointMap[x] && !pointMap[x].isNull) {
  247. segment.push(pointMap[x]);
  248. // Find left and right cliff. -1 goes left, 1 goes
  249. // right.
  250. [-1, 1].forEach(function (direction) {
  251. var nullName = direction === 1 ?
  252. 'rightNull' :
  253. 'leftNull', cliffName = direction === 1 ?
  254. 'rightCliff' :
  255. 'leftCliff', cliff = 0, otherStack = stack[keys[idx + direction]];
  256. // If there is a stack next to this one,
  257. // to the left or to the right...
  258. if (otherStack) {
  259. i = seriesIndex;
  260. // Can go either up or down,
  261. // depending on reversedStacks
  262. while (i >= 0 && i < seriesLength) {
  263. stackPoint = otherStack.points[i];
  264. if (!stackPoint) {
  265. // If the next point in this series
  266. // is missing, mark the point
  267. // with point.leftNull or
  268. // point.rightNull = true.
  269. if (i === seriesIndex) {
  270. pointMap[x][nullName] =
  271. true;
  272. // If there are missing points in
  273. // the next stack in any of the
  274. // series below this one, we need
  275. // to substract the missing values
  276. // and add a hiatus to the left or
  277. // right.
  278. }
  279. else if (visibleSeries[i]) {
  280. stackedValues =
  281. stack[x].points[i];
  282. if (stackedValues) {
  283. cliff -=
  284. stackedValues[1] -
  285. stackedValues[0];
  286. }
  287. }
  288. }
  289. // When reversedStacks is true, loop up,
  290. // else loop down
  291. i += upOrDown;
  292. }
  293. }
  294. pointMap[x][cliffName] = cliff;
  295. });
  296. // There is no point for this X value in this series, so we
  297. // insert a dummy point in order for the areas to be drawn
  298. // correctly.
  299. }
  300. else {
  301. // Loop down the stack to find the series below this
  302. // one that has a value (#1991)
  303. i = seriesIndex;
  304. while (i >= 0 && i < seriesLength) {
  305. stackPoint = stack[x].points[i];
  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 = yAxis.translate(// #6272
  315. y, 0, 1, 0, 1);
  316. segment.push({
  317. isNull: true,
  318. plotX: xAxis.translate(// #6272
  319. x, 0, 0, 0, 1),
  320. x: x,
  321. plotY: y,
  322. yBottom: y
  323. });
  324. }
  325. });
  326. }
  327. return segment;
  328. };
  329. /**
  330. * The area series type.
  331. *
  332. * @sample {highcharts} highcharts/demo/area-basic/
  333. * Area chart
  334. * @sample {highstock} stock/demo/area/
  335. * Area chart
  336. *
  337. * @extends plotOptions.line
  338. * @excluding useOhlcData
  339. * @product highcharts highstock
  340. * @optionparent plotOptions.area
  341. */
  342. AreaSeries.defaultOptions = merge(LineSeries.defaultOptions, {
  343. /**
  344. * @see [fillColor](#plotOptions.area.fillColor)
  345. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  346. *
  347. * @apioption plotOptions.area.color
  348. */
  349. /**
  350. * Fill color or gradient for the area. When `null`, the series' `color`
  351. * is used with the series' `fillOpacity`.
  352. *
  353. * In styled mode, the fill color can be set with the `.highcharts-area`
  354. * class name.
  355. *
  356. * @see [color](#plotOptions.area.color)
  357. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  358. *
  359. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-default/
  360. * Null by default
  361. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-gradient/
  362. * Gradient
  363. *
  364. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  365. * @product highcharts highstock
  366. * @apioption plotOptions.area.fillColor
  367. */
  368. /**
  369. * Fill opacity for the area. When you set an explicit `fillColor`,
  370. * the `fillOpacity` is not applied. Instead, you should define the
  371. * opacity in the `fillColor` with an rgba color definition. The
  372. * `fillOpacity` setting, also the default setting, overrides the alpha
  373. * component of the `color` setting.
  374. *
  375. * In styled mode, the fill opacity can be set with the
  376. * `.highcharts-area` class name.
  377. *
  378. * @see [color](#plotOptions.area.color)
  379. * @see [fillColor](#plotOptions.area.fillColor)
  380. *
  381. * @sample {highcharts} highcharts/plotoptions/area-fillopacity/
  382. * Automatic fill color and fill opacity of 0.1
  383. *
  384. * @type {number}
  385. * @default {highcharts} 0.75
  386. * @default {highstock} 0.75
  387. * @product highcharts highstock
  388. * @apioption plotOptions.area.fillOpacity
  389. */
  390. /**
  391. * A separate color for the graph line. By default the line takes the
  392. * `color` of the series, but the lineColor setting allows setting a
  393. * separate color for the line without altering the `fillColor`.
  394. *
  395. * In styled mode, the line stroke can be set with the
  396. * `.highcharts-graph` class name.
  397. *
  398. * @sample {highcharts} highcharts/plotoptions/area-linecolor/
  399. * Dark gray line
  400. *
  401. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  402. * @product highcharts highstock
  403. * @apioption plotOptions.area.lineColor
  404. */
  405. /**
  406. * A separate color for the negative part of the area.
  407. *
  408. * In styled mode, a negative color is set with the
  409. * `.highcharts-negative` class name.
  410. *
  411. * @see [negativeColor](#plotOptions.area.negativeColor)
  412. *
  413. * @sample {highcharts} highcharts/css/series-negative-color/
  414. * Negative color in styled mode
  415. *
  416. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  417. * @since 3.0
  418. * @product highcharts
  419. * @apioption plotOptions.area.negativeFillColor
  420. */
  421. /**
  422. * Whether the whole area or just the line should respond to mouseover
  423. * tooltips and other mouse or touch events.
  424. *
  425. * @sample {highcharts|highstock} highcharts/plotoptions/area-trackbyarea/
  426. * Display the tooltip when the area is hovered
  427. *
  428. * @type {boolean}
  429. * @default false
  430. * @since 1.1.6
  431. * @product highcharts highstock
  432. * @apioption plotOptions.area.trackByArea
  433. */
  434. /**
  435. * The Y axis value to serve as the base for the area, for
  436. * distinguishing between values above and below a threshold. The area
  437. * between the graph and the threshold is filled.
  438. *
  439. * * If a number is given, the Y axis will scale to the threshold.
  440. * * If `null`, the scaling behaves like a line series with fill between
  441. * the graph and the Y axis minimum.
  442. * * If `Infinity` or `-Infinity`, the area between the graph and the
  443. * corresponding Y axis extreme is filled (since v6.1.0).
  444. *
  445. * @sample {highcharts} highcharts/plotoptions/area-threshold/
  446. * A threshold of 100
  447. * @sample {highcharts} highcharts/plotoptions/area-threshold-infinity/
  448. * A threshold of Infinity
  449. *
  450. * @type {number|null}
  451. * @since 2.0
  452. * @product highcharts highstock
  453. */
  454. threshold: 0
  455. });
  456. return AreaSeries;
  457. }(LineSeries));
  458. extend(AreaSeries.prototype, {
  459. singleStacks: false,
  460. drawLegendSymbol: LegendSymbolMixin.drawRectangle
  461. });
  462. SeriesRegistry.registerSeriesType('area', AreaSeries);
  463. /* *
  464. *
  465. * Default Export
  466. *
  467. * */
  468. export default AreaSeries;
  469. /* *
  470. *
  471. * API Options
  472. *
  473. * */
  474. /**
  475. * A `area` series. If the [type](#series.area.type) option is not
  476. * specified, it is inherited from [chart.type](#chart.type).
  477. *
  478. * @extends series,plotOptions.area
  479. * @excluding dataParser, dataURL, useOhlcData
  480. * @product highcharts highstock
  481. * @apioption series.area
  482. */
  483. /**
  484. * @see [fillColor](#series.area.fillColor)
  485. * @see [fillOpacity](#series.area.fillOpacity)
  486. *
  487. * @apioption series.area.color
  488. */
  489. /**
  490. * An array of data points for the series. For the `area` series type,
  491. * points can be given in the following ways:
  492. *
  493. * 1. An array of numerical values. In this case, the numerical values will be
  494. * interpreted as `y` options. The `x` values will be automatically
  495. * calculated, either starting at 0 and incremented by 1, or from
  496. * `pointStart` * and `pointInterval` given in the series options. If the
  497. * axis has categories, these will be used. Example:
  498. * ```js
  499. * data: [0, 5, 3, 5]
  500. * ```
  501. *
  502. * 2. An array of arrays with 2 values. In this case, the values correspond to
  503. * `x,y`. If the first value is a string, it is applied as the name of the
  504. * point, and the `x` value is inferred.
  505. * ```js
  506. * data: [
  507. * [0, 9],
  508. * [1, 7],
  509. * [2, 6]
  510. * ]
  511. * ```
  512. *
  513. * 3. An array of objects with named values. The following snippet shows only a
  514. * few settings, see the complete options set below. If the total number of
  515. * data points exceeds the series'
  516. * [turboThreshold](#series.area.turboThreshold), this option is not
  517. * available.
  518. * ```js
  519. * data: [{
  520. * x: 1,
  521. * y: 9,
  522. * name: "Point2",
  523. * color: "#00FF00"
  524. * }, {
  525. * x: 1,
  526. * y: 6,
  527. * name: "Point1",
  528. * color: "#FF00FF"
  529. * }]
  530. * ```
  531. *
  532. * @sample {highcharts} highcharts/chart/reflow-true/
  533. * Numerical values
  534. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  535. * Arrays of numeric x and y
  536. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  537. * Arrays of datetime x and y
  538. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  539. * Arrays of point.name and y
  540. * @sample {highcharts} highcharts/series/data-array-of-objects/
  541. * Config objects
  542. *
  543. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  544. * @extends series.line.data
  545. * @product highcharts highstock
  546. * @apioption series.area.data
  547. */
  548. /**
  549. * @see [color](#series.area.color)
  550. * @see [fillOpacity](#series.area.fillOpacity)
  551. *
  552. * @apioption series.area.fillColor
  553. */
  554. /**
  555. * @see [color](#series.area.color)
  556. * @see [fillColor](#series.area.fillColor)
  557. *
  558. * @default {highcharts} 0.75
  559. * @default {highstock} 0.75
  560. * @apioption series.area.fillOpacity
  561. */
  562. ''; // adds doclets above to transpilat