WaterfallSeries.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. /* *
  2. * (c) 2010-2019 Torstein Honsi
  3. *
  4. * License: www.highcharts.com/license
  5. */
  6. 'use strict';
  7. import H from '../parts/Globals.js';
  8. import '../parts/Utilities.js';
  9. import '../parts/Options.js';
  10. import '../parts/Series.js';
  11. import '../parts/Point.js';
  12. var correctFloat = H.correctFloat,
  13. isNumber = H.isNumber,
  14. pick = H.pick,
  15. objectEach = H.objectEach,
  16. arrayMin = H.arrayMin,
  17. arrayMax = H.arrayMax,
  18. addEvent = H.addEvent,
  19. Axis = H.Axis,
  20. Chart = H.Chart,
  21. Point = H.Point,
  22. Series = H.Series,
  23. seriesType = H.seriesType,
  24. seriesTypes = H.seriesTypes;
  25. addEvent(Axis, 'afterInit', function () {
  26. if (!this.isXAxis) {
  27. this.waterfallStacks = {};
  28. }
  29. });
  30. addEvent(Chart, 'beforeRedraw', function () {
  31. var axes = this.axes,
  32. series = this.series,
  33. i = series.length;
  34. while (i--) {
  35. if (series[i].options.stacking) {
  36. axes.forEach(function (axis) {
  37. if (!axis.isXAxis) {
  38. axis.waterfallStacks = {};
  39. }
  40. });
  41. i = 0;
  42. }
  43. }
  44. });
  45. /**
  46. * A waterfall chart displays sequentially introduced positive or negative
  47. * values in cumulative columns.
  48. *
  49. * @sample highcharts/demo/waterfall/
  50. * Waterfall chart
  51. * @sample highcharts/plotoptions/waterfall-inverted/
  52. * Horizontal (inverted) waterfall
  53. * @sample highcharts/plotoptions/waterfall-stacked/
  54. * Stacked waterfall chart
  55. *
  56. * @extends plotOptions.column
  57. * @product highcharts
  58. * @optionparent plotOptions.waterfall
  59. */
  60. seriesType('waterfall', 'column', {
  61. /**
  62. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  63. * @apioption plotOptions.waterfall.color
  64. */
  65. /**
  66. * The color used specifically for positive point columns. When not
  67. * specified, the general series color is used.
  68. *
  69. * In styled mode, the waterfall colors can be set with the
  70. * `.highcharts-point-negative`, `.highcharts-sum` and
  71. * `.highcharts-intermediate-sum` classes.
  72. *
  73. * @sample {highcharts} highcharts/demo/waterfall/
  74. * Waterfall
  75. *
  76. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  77. * @product highcharts
  78. * @apioption plotOptions.waterfall.upColor
  79. */
  80. dataLabels: {
  81. inside: true
  82. },
  83. /**
  84. * The width of the line connecting waterfall columns.
  85. *
  86. * @product highcharts
  87. */
  88. lineWidth: 1,
  89. /**
  90. * The color of the line that connects columns in a waterfall series.
  91. *
  92. * In styled mode, the stroke can be set with the `.highcharts-graph` class.
  93. *
  94. * @type {Highcharts.ColorString}
  95. * @since 3.0
  96. * @product highcharts
  97. */
  98. lineColor: '#333333',
  99. /**
  100. * A name for the dash style to use for the line connecting the columns
  101. * of the waterfall series. Possible values: Dash, DashDot, Dot, LongDash,
  102. * LongDashDot, LongDashDotDot, ShortDash, ShortDashDot, ShortDashDotDot,
  103. * ShortDot, Solid
  104. *
  105. * In styled mode, the stroke dash-array can be set with the
  106. * `.highcharts-graph` class.
  107. *
  108. * @type {Highcharts.DashStyleType}
  109. * @since 3.0
  110. * @product highcharts
  111. */
  112. dashStyle: 'Dot',
  113. /**
  114. * The color of the border of each waterfall column.
  115. *
  116. * In styled mode, the border stroke can be set with the
  117. * `.highcharts-point` class.
  118. *
  119. * @type {Highcharts.ColorString}
  120. * @since 3.0
  121. * @product highcharts
  122. */
  123. borderColor: '#333333',
  124. states: {
  125. hover: {
  126. lineWidthPlus: 0 // #3126
  127. }
  128. }
  129. // Prototype members
  130. }, {
  131. pointValKey: 'y',
  132. // Property needed to prevent lines between the columns from disappearing
  133. // when negativeColor is used.
  134. showLine: true,
  135. // After generating points, set y-values for all sums.
  136. generatePoints: function () {
  137. var point,
  138. len,
  139. i,
  140. y;
  141. // Parent call:
  142. seriesTypes.column.prototype.generatePoints.apply(this);
  143. for (i = 0, len = this.points.length; i < len; i++) {
  144. point = this.points[i];
  145. y = this.processedYData[i];
  146. // override point value for sums
  147. // #3710 Update point does not propagate to sum
  148. if (point.isIntermediateSum || point.isSum) {
  149. point.y = correctFloat(y);
  150. }
  151. }
  152. },
  153. // Translate data points from raw values
  154. translate: function () {
  155. var series = this,
  156. options = series.options,
  157. yAxis = series.yAxis,
  158. len,
  159. i,
  160. points,
  161. point,
  162. shapeArgs,
  163. y,
  164. yValue,
  165. previousY,
  166. previousIntermediate,
  167. range,
  168. minPointLength = pick(options.minPointLength, 5),
  169. halfMinPointLength = minPointLength / 2,
  170. threshold = options.threshold,
  171. stacking = options.stacking,
  172. tooltipY,
  173. actualStack = yAxis.waterfallStacks[series.stackKey],
  174. actualStackX,
  175. total,
  176. pointY,
  177. yPos,
  178. hPos;
  179. // run column series translate
  180. seriesTypes.column.prototype.translate.apply(series);
  181. previousY = previousIntermediate = threshold;
  182. points = series.points;
  183. for (i = 0, len = points.length; i < len; i++) {
  184. // cache current point object
  185. point = points[i];
  186. yValue = series.processedYData[i];
  187. shapeArgs = point.shapeArgs;
  188. range = [0, yValue];
  189. pointY = point.y;
  190. // code responsible for correct positions of stacked points
  191. // starts here
  192. if (stacking) {
  193. if (actualStack) {
  194. actualStackX = actualStack[i];
  195. if (stacking === 'overlap') {
  196. total = actualStackX.threshold + actualStackX.total;
  197. actualStackX.total -= pointY;
  198. y = pointY >= 0 ? total : total - pointY;
  199. } else {
  200. if (pointY >= 0) {
  201. total = actualStackX.threshold +
  202. actualStackX.posTotal;
  203. actualStackX.posTotal -= pointY;
  204. y = total;
  205. } else {
  206. total = actualStackX.threshold +
  207. actualStackX.negTotal;
  208. actualStackX.negTotal -= pointY;
  209. y = total - pointY;
  210. }
  211. }
  212. if (!point.isSum) {
  213. // the connectorThreshold property is later used in
  214. // getCrispPath function to draw a connector line in a
  215. // correct place
  216. actualStackX.connectorThreshold =
  217. actualStackX.threshold + actualStackX.stackTotal;
  218. }
  219. if (yAxis.reversed) {
  220. yPos = (pointY >= 0) ? (y - pointY) : (y + pointY);
  221. hPos = y;
  222. } else {
  223. yPos = y;
  224. hPos = y - pointY;
  225. }
  226. point.below = yPos <= pick(threshold, 0);
  227. shapeArgs.y = yAxis.translate(yPos, 0, 1, 0, 1);
  228. shapeArgs.height = Math.abs(shapeArgs.y -
  229. yAxis.translate(hPos, 0, 1, 0, 1));
  230. }
  231. } else {
  232. // up points
  233. y = Math.max(previousY, previousY + pointY) + range[0];
  234. shapeArgs.y = yAxis.translate(y, 0, 1, 0, 1);
  235. // sum points
  236. if (point.isSum) {
  237. shapeArgs.y = yAxis.translate(range[1], 0, 1, 0, 1);
  238. shapeArgs.height = Math.min(
  239. yAxis.translate(range[0], 0, 1, 0, 1),
  240. yAxis.len
  241. ) - shapeArgs.y; // #4256
  242. } else if (point.isIntermediateSum) {
  243. if (pointY >= 0) {
  244. yPos = range[1] + previousIntermediate;
  245. hPos = previousIntermediate;
  246. } else {
  247. yPos = previousIntermediate;
  248. hPos = range[1] + previousIntermediate;
  249. }
  250. if (yAxis.reversed) {
  251. // swapping values
  252. yPos ^= hPos;
  253. hPos ^= yPos;
  254. yPos ^= hPos;
  255. }
  256. shapeArgs.y = yAxis.translate(yPos, 0, 1, 0, 1);
  257. shapeArgs.height = Math.abs(shapeArgs.y - Math.min(
  258. yAxis.translate(hPos, 0, 1, 0, 1),
  259. yAxis.len
  260. ));
  261. previousIntermediate += range[1];
  262. // If it's not the sum point, update previous stack end position
  263. // and get shape height (#3886)
  264. } else {
  265. shapeArgs.height = yValue > 0 ?
  266. yAxis.translate(previousY, 0, 1, 0, 1) - shapeArgs.y :
  267. yAxis.translate(previousY, 0, 1, 0, 1) -
  268. yAxis.translate(previousY - yValue, 0, 1, 0, 1);
  269. previousY += yValue;
  270. point.below = previousY < pick(threshold, 0);
  271. }
  272. // #3952 Negative sum or intermediate sum not rendered correctly
  273. if (shapeArgs.height < 0) {
  274. shapeArgs.y += shapeArgs.height;
  275. shapeArgs.height *= -1;
  276. }
  277. }
  278. point.plotY = shapeArgs.y = Math.round(shapeArgs.y) -
  279. (series.borderWidth % 2) / 2;
  280. // #3151
  281. shapeArgs.height = Math.max(Math.round(shapeArgs.height), 0.001);
  282. point.yBottom = shapeArgs.y + shapeArgs.height;
  283. if (shapeArgs.height <= minPointLength && !point.isNull) {
  284. shapeArgs.height = minPointLength;
  285. shapeArgs.y -= halfMinPointLength;
  286. point.plotY = shapeArgs.y;
  287. if (point.y < 0) {
  288. point.minPointLengthOffset = -halfMinPointLength;
  289. } else {
  290. point.minPointLengthOffset = halfMinPointLength;
  291. }
  292. } else {
  293. if (point.isNull) {
  294. shapeArgs.width = 0;
  295. }
  296. point.minPointLengthOffset = 0;
  297. }
  298. // Correct tooltip placement (#3014)
  299. tooltipY = point.plotY + (point.negative ? shapeArgs.height : 0);
  300. if (series.chart.inverted) {
  301. point.tooltipPos[0] = yAxis.len - tooltipY;
  302. } else {
  303. point.tooltipPos[1] = tooltipY;
  304. }
  305. }
  306. },
  307. // Call default processData then override yData to reflect waterfall's
  308. // extremes on yAxis
  309. processData: function (force) {
  310. var series = this,
  311. options = series.options,
  312. yData = series.yData,
  313. // #3710 Update point does not propagate to sum
  314. points = options.data,
  315. point,
  316. dataLength = yData.length,
  317. threshold = options.threshold || 0,
  318. subSum,
  319. sum,
  320. dataMin,
  321. dataMax,
  322. y,
  323. i;
  324. sum = subSum = dataMin = dataMax = 0;
  325. for (i = 0; i < dataLength; i++) {
  326. y = yData[i];
  327. point = points && points[i] ? points[i] : {};
  328. if (y === 'sum' || point.isSum) {
  329. yData[i] = correctFloat(sum);
  330. } else if (y === 'intermediateSum' || point.isIntermediateSum) {
  331. yData[i] = correctFloat(subSum);
  332. subSum = 0;
  333. } else {
  334. sum += y;
  335. subSum += y;
  336. }
  337. dataMin = Math.min(sum, dataMin);
  338. dataMax = Math.max(sum, dataMax);
  339. }
  340. Series.prototype.processData.call(this, force);
  341. // Record extremes only if stacking was not set:
  342. if (!options.stacking) {
  343. series.dataMin = dataMin + threshold;
  344. series.dataMax = dataMax;
  345. }
  346. },
  347. // Return y value or string if point is sum
  348. toYData: function (pt) {
  349. if (pt.isSum) {
  350. // #3245 Error when first element is Sum or Intermediate Sum
  351. return (pt.x === 0 ? null : 'sum');
  352. }
  353. if (pt.isIntermediateSum) {
  354. return (pt.x === 0 ? null : 'intermediateSum'); // #3245
  355. }
  356. return pt.y;
  357. },
  358. // Postprocess mapping between options and SVG attributes
  359. pointAttribs: function (point, state) {
  360. var upColor = this.options.upColor,
  361. attr;
  362. // Set or reset up color (#3710, update to negative)
  363. if (upColor && !point.options.color) {
  364. point.color = point.y > 0 ? upColor : null;
  365. }
  366. attr = seriesTypes.column.prototype.pointAttribs.call(
  367. this,
  368. point,
  369. state
  370. );
  371. // The dashStyle option in waterfall applies to the graph, not
  372. // the points
  373. delete attr.dashstyle;
  374. return attr;
  375. },
  376. // Return an empty path initially, because we need to know the stroke-width
  377. // in order to set the final path.
  378. getGraphPath: function () {
  379. return ['M', 0, 0];
  380. },
  381. // Draw columns' connector lines
  382. getCrispPath: function () {
  383. var data = this.data,
  384. yAxis = this.yAxis,
  385. length = data.length,
  386. graphNormalizer = Math.round(this.graph.strokeWidth()) % 2 / 2,
  387. borderNormalizer = Math.round(this.borderWidth) % 2 / 2,
  388. reversedXAxis = this.xAxis.reversed,
  389. reversedYAxis = this.yAxis.reversed,
  390. stacking = this.options.stacking,
  391. path = [],
  392. connectorThreshold,
  393. prevStack,
  394. prevStackX,
  395. prevPoint,
  396. yPos,
  397. isPos,
  398. prevArgs,
  399. pointArgs,
  400. i,
  401. d;
  402. for (i = 1; i < length; i++) {
  403. pointArgs = data[i].shapeArgs;
  404. prevPoint = data[i - 1];
  405. prevArgs = data[i - 1].shapeArgs;
  406. prevStack = yAxis.waterfallStacks[this.stackKey];
  407. isPos = prevPoint.y > 0 ? -prevArgs.height : 0;
  408. if (prevStack) {
  409. prevStackX = prevStack[i - 1];
  410. // y position of the connector is different when series are
  411. // stacked, yAxis is reversed and it also depends on point's
  412. // value
  413. if (stacking) {
  414. connectorThreshold = prevStackX.connectorThreshold;
  415. yPos = Math.round(
  416. (yAxis.translate(connectorThreshold, 0, 1, 0, 1) +
  417. (reversedYAxis ? isPos : 0))
  418. ) - graphNormalizer;
  419. } else {
  420. yPos = prevArgs.y + prevPoint.minPointLengthOffset +
  421. borderNormalizer - graphNormalizer;
  422. }
  423. d = [
  424. 'M',
  425. prevArgs.x + (reversedXAxis ? 0 : prevArgs.width),
  426. yPos,
  427. 'L',
  428. pointArgs.x + (reversedXAxis ? pointArgs.width : 0),
  429. yPos
  430. ];
  431. }
  432. if (
  433. !stacking &&
  434. (prevPoint.y < 0 && !reversedYAxis) ||
  435. (prevPoint.y > 0 && reversedYAxis)
  436. ) {
  437. d[2] += prevArgs.height;
  438. d[5] += prevArgs.height;
  439. }
  440. path = path.concat(d);
  441. }
  442. return path;
  443. },
  444. // The graph is initially drawn with an empty definition, then updated with
  445. // crisp rendering.
  446. drawGraph: function () {
  447. Series.prototype.drawGraph.call(this);
  448. this.graph.attr({
  449. d: this.getCrispPath()
  450. });
  451. },
  452. // Waterfall has stacking along the x-values too.
  453. setStackedPoints: function () {
  454. var series = this,
  455. options = series.options,
  456. waterfallStacks = series.yAxis.waterfallStacks,
  457. seriesThreshold = options.threshold,
  458. stackThreshold = seriesThreshold || 0,
  459. interSum = seriesThreshold || 0,
  460. stackKey = series.stackKey,
  461. xData = series.xData,
  462. xLength = xData.length,
  463. actualStack,
  464. actualStackX,
  465. posTotal,
  466. negTotal,
  467. xPoint,
  468. yVal,
  469. x;
  470. // code responsible for creating stacks for waterfall series
  471. if (series.visible || !series.chart.options.chart.ignoreHiddenSeries) {
  472. if (!waterfallStacks[stackKey]) {
  473. waterfallStacks[stackKey] = {};
  474. }
  475. actualStack = waterfallStacks[stackKey];
  476. for (var i = 0; i < xLength; i++) {
  477. x = xData[i];
  478. if (!actualStack[x]) {
  479. actualStack[x] = {
  480. negTotal: 0,
  481. posTotal: 0,
  482. total: 0,
  483. stackTotal: 0,
  484. threshold: 0,
  485. stackState: [stackThreshold]
  486. };
  487. }
  488. actualStackX = actualStack[x];
  489. yVal = series.yData[i];
  490. if (yVal >= 0) {
  491. actualStackX.posTotal += yVal;
  492. } else {
  493. actualStackX.negTotal += yVal;
  494. }
  495. // points do not exist yet, so raw data is used
  496. xPoint = options.data[i];
  497. posTotal = actualStackX.posTotal;
  498. negTotal = actualStackX.negTotal;
  499. if (xPoint && xPoint.isIntermediateSum) {
  500. // swapping values
  501. stackThreshold ^= interSum;
  502. interSum ^= stackThreshold;
  503. stackThreshold ^= interSum;
  504. } else if (xPoint && xPoint.isSum) {
  505. stackThreshold = seriesThreshold;
  506. }
  507. actualStackX.stackTotal = posTotal + negTotal;
  508. actualStackX.total = actualStackX.stackTotal;
  509. actualStackX.threshold = stackThreshold;
  510. actualStackX.stackState[0] = stackThreshold;
  511. actualStackX.stackState.push(actualStackX.stackTotal);
  512. stackThreshold += actualStackX.stackTotal;
  513. }
  514. }
  515. },
  516. // Extremes for a non-stacked series are recorded in processData.
  517. // In case of stacking, use Series.stackedYData to calculate extremes.
  518. getExtremes: function () {
  519. var stacking = this.options.stacking,
  520. yAxis,
  521. waterfallStacks,
  522. stackedYNeg,
  523. stackedYPos,
  524. states,
  525. firstState;
  526. if (stacking) {
  527. yAxis = this.yAxis;
  528. waterfallStacks = yAxis.waterfallStacks;
  529. stackedYNeg = this.stackedYNeg = [];
  530. stackedYPos = this.stackedYPos = [];
  531. // the visible y range can be different when stacking is set to
  532. // overlap and different when it's set to normal
  533. if (stacking === 'overlap') {
  534. objectEach(waterfallStacks[this.stackKey], function (stackX) {
  535. states = [];
  536. stackX.stackState.forEach(function (state, stateIndex) {
  537. firstState = stackX.stackState[0];
  538. if (stateIndex) {
  539. states.push(state + firstState);
  540. } else {
  541. states.push(firstState);
  542. }
  543. });
  544. stackedYNeg.push(arrayMin(states));
  545. stackedYPos.push(arrayMax(states));
  546. });
  547. } else {
  548. objectEach(waterfallStacks[this.stackKey], function (stackX) {
  549. stackedYNeg.push(stackX.negTotal + stackX.threshold);
  550. stackedYPos.push(stackX.posTotal + stackX.threshold);
  551. });
  552. }
  553. this.dataMin = arrayMin(stackedYNeg);
  554. this.dataMax = arrayMax(stackedYPos);
  555. }
  556. }
  557. // Point members
  558. }, {
  559. getClassName: function () {
  560. var className = Point.prototype.getClassName.call(this);
  561. if (this.isSum) {
  562. className += ' highcharts-sum';
  563. } else if (this.isIntermediateSum) {
  564. className += ' highcharts-intermediate-sum';
  565. }
  566. return className;
  567. },
  568. // Pass the null test in ColumnSeries.translate.
  569. isValid: function () {
  570. return isNumber(this.y, true) || this.isSum || this.isIntermediateSum;
  571. }
  572. });
  573. /**
  574. * A `waterfall` series. If the [type](#series.waterfall.type) option
  575. * is not specified, it is inherited from [chart.type](#chart.type).
  576. *
  577. * @extends series,plotOptions.waterfall
  578. * @excluding dataParser, dataURL
  579. * @product highcharts
  580. * @apioption series.waterfall
  581. */
  582. /**
  583. * An array of data points for the series. For the `waterfall` series
  584. * type, points can be given in the following ways:
  585. *
  586. * 1. An array of numerical values. In this case, the numerical values will be
  587. * interpreted as `y` options. The `x` values will be automatically
  588. * calculated, either starting at 0 and incremented by 1, or from
  589. * `pointStart` and `pointInterval` given in the series options. If the axis
  590. * has categories, these will be used. Example:
  591. * ```js
  592. * data: [0, 5, 3, 5]
  593. * ```
  594. *
  595. * 2. An array of arrays with 2 values. In this case, the values correspond to
  596. * `x,y`. If the first value is a string, it is applied as the name of the
  597. * point, and the `x` value is inferred.
  598. * ```js
  599. * data: [
  600. * [0, 7],
  601. * [1, 8],
  602. * [2, 3]
  603. * ]
  604. * ```
  605. *
  606. * 3. An array of objects with named values. The following snippet shows only a
  607. * few settings, see the complete options set below. If the total number of
  608. * data points exceeds the series'
  609. * [turboThreshold](#series.waterfall.turboThreshold), this option is not
  610. * available.
  611. * ```js
  612. * data: [{
  613. * x: 1,
  614. * y: 8,
  615. * name: "Point2",
  616. * color: "#00FF00"
  617. * }, {
  618. * x: 1,
  619. * y: 8,
  620. * name: "Point1",
  621. * color: "#FF00FF"
  622. * }]
  623. * ```
  624. *
  625. * @sample {highcharts} highcharts/chart/reflow-true/
  626. * Numerical values
  627. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  628. * Arrays of numeric x and y
  629. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  630. * Arrays of datetime x and y
  631. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  632. * Arrays of point.name and y
  633. * @sample {highcharts} highcharts/series/data-array-of-objects/
  634. * Config objects
  635. *
  636. * @type {Array<number|Array<(number|string),number>|*>}
  637. * @extends series.line.data
  638. * @excluding marker
  639. * @product highcharts
  640. * @apioption series.waterfall.data
  641. */
  642. /**
  643. * When this property is true, the points acts as a summary column for
  644. * the values added or substracted since the last intermediate sum,
  645. * or since the start of the series. The `y` value is ignored.
  646. *
  647. * @sample {highcharts} highcharts/demo/waterfall/
  648. * Waterfall
  649. *
  650. * @type {boolean}
  651. * @default false
  652. * @product highcharts
  653. * @apioption series.waterfall.data.isIntermediateSum
  654. */
  655. /**
  656. * When this property is true, the point display the total sum across
  657. * the entire series. The `y` value is ignored.
  658. *
  659. * @sample {highcharts} highcharts/demo/waterfall/
  660. * Waterfall
  661. *
  662. * @type {boolean}
  663. * @default false
  664. * @product highcharts
  665. * @apioption series.waterfall.data.isSum
  666. */