SplineSeries.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* *
  2. *
  3. * (c) 2010-2020 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. import U from '../Core/Utilities.js';
  12. var pick = U.pick, seriesType = U.seriesType;
  13. import '../Core/Options.js';
  14. import '../Core/Series/Series.js';
  15. /**
  16. * Spline series type.
  17. *
  18. * @private
  19. * @class
  20. * @name Highcharts.seriesTypes.spline
  21. *
  22. * @augments Highcarts.Series
  23. */
  24. seriesType('spline', 'line',
  25. /**
  26. * A spline series is a special type of line series, where the segments
  27. * between the data points are smoothed.
  28. *
  29. * @sample {highcharts} highcharts/demo/spline-irregular-time/
  30. * Spline chart
  31. * @sample {highstock} stock/demo/spline/
  32. * Spline chart
  33. *
  34. * @extends plotOptions.series
  35. * @excluding step, boostThreshold, boostBlending
  36. * @product highcharts highstock
  37. * @optionparent plotOptions.spline
  38. */
  39. {},
  40. /**
  41. * @lends seriesTypes.spline.prototype
  42. */
  43. {
  44. /* eslint-disable valid-jsdoc */
  45. /**
  46. * Get the spline segment from a given point's previous neighbour to the
  47. * given point.
  48. *
  49. * @private
  50. * @function Highcharts.seriesTypes.spline#getPointSpline
  51. *
  52. * @param {Array<Highcharts.Point>}
  53. *
  54. * @param {Highcharts.Point} point
  55. *
  56. * @param {number} i
  57. *
  58. * @return {Highcharts.SVGPathArray}
  59. */
  60. getPointSpline: function (points, point, i) {
  61. var
  62. // 1 means control points midway between points, 2 means 1/3
  63. // from the point, 3 is 1/4 etc
  64. smoothing = 1.5, denom = smoothing + 1, plotX = point.plotX || 0, plotY = point.plotY || 0, lastPoint = points[i - 1], nextPoint = points[i + 1], leftContX, leftContY, rightContX, rightContY, ret;
  65. /**
  66. * @private
  67. */
  68. function doCurve(otherPoint) {
  69. return otherPoint &&
  70. !otherPoint.isNull &&
  71. otherPoint.doCurve !== false &&
  72. // #6387, area splines next to null:
  73. !point.isCliff;
  74. }
  75. // Find control points
  76. if (doCurve(lastPoint) && doCurve(nextPoint)) {
  77. var lastX = lastPoint.plotX || 0, lastY = lastPoint.plotY || 0, nextX = nextPoint.plotX || 0, nextY = nextPoint.plotY || 0, correction = 0;
  78. leftContX = (smoothing * plotX + lastX) / denom;
  79. leftContY = (smoothing * plotY + lastY) / denom;
  80. rightContX = (smoothing * plotX + nextX) / denom;
  81. rightContY = (smoothing * plotY + nextY) / denom;
  82. // Have the two control points make a straight line through main
  83. // point
  84. if (rightContX !== leftContX) { // #5016, division by zero
  85. correction = (((rightContY - leftContY) *
  86. (rightContX - plotX)) /
  87. (rightContX - leftContX) + plotY - rightContY);
  88. }
  89. leftContY += correction;
  90. rightContY += correction;
  91. // to prevent false extremes, check that control points are
  92. // between neighbouring points' y values
  93. if (leftContY > lastY && leftContY > plotY) {
  94. leftContY = Math.max(lastY, plotY);
  95. // mirror of left control point
  96. rightContY = 2 * plotY - leftContY;
  97. }
  98. else if (leftContY < lastY && leftContY < plotY) {
  99. leftContY = Math.min(lastY, plotY);
  100. rightContY = 2 * plotY - leftContY;
  101. }
  102. if (rightContY > nextY && rightContY > plotY) {
  103. rightContY = Math.max(nextY, plotY);
  104. leftContY = 2 * plotY - rightContY;
  105. }
  106. else if (rightContY < nextY && rightContY < plotY) {
  107. rightContY = Math.min(nextY, plotY);
  108. leftContY = 2 * plotY - rightContY;
  109. }
  110. // record for drawing in next point
  111. point.rightContX = rightContX;
  112. point.rightContY = rightContY;
  113. }
  114. // Visualize control points for debugging
  115. /*
  116. if (leftContX) {
  117. this.chart.renderer.circle(
  118. leftContX + this.chart.plotLeft,
  119. leftContY + this.chart.plotTop,
  120. 2
  121. )
  122. .attr({
  123. stroke: 'red',
  124. 'stroke-width': 2,
  125. fill: 'none',
  126. zIndex: 9
  127. })
  128. .add();
  129. this.chart.renderer.path(['M', leftContX + this.chart.plotLeft,
  130. leftContY + this.chart.plotTop,
  131. 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
  132. .attr({
  133. stroke: 'red',
  134. 'stroke-width': 2,
  135. zIndex: 9
  136. })
  137. .add();
  138. }
  139. if (rightContX) {
  140. this.chart.renderer.circle(
  141. rightContX + this.chart.plotLeft,
  142. rightContY + this.chart.plotTop,
  143. 2
  144. )
  145. .attr({
  146. stroke: 'green',
  147. 'stroke-width': 2,
  148. fill: 'none',
  149. zIndex: 9
  150. })
  151. .add();
  152. this.chart.renderer.path(['M', rightContX + this.chart.plotLeft,
  153. rightContY + this.chart.plotTop,
  154. 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
  155. .attr({
  156. stroke: 'green',
  157. 'stroke-width': 2,
  158. zIndex: 9
  159. })
  160. .add();
  161. }
  162. // */
  163. ret = [
  164. 'C',
  165. pick(lastPoint.rightContX, lastPoint.plotX, 0),
  166. pick(lastPoint.rightContY, lastPoint.plotY, 0),
  167. pick(leftContX, plotX, 0),
  168. pick(leftContY, plotY, 0),
  169. plotX,
  170. plotY
  171. ];
  172. // reset for updating series later
  173. lastPoint.rightContX = lastPoint.rightContY = void 0;
  174. return ret;
  175. }
  176. /* eslint-enable valid-jsdoc */
  177. });
  178. /**
  179. * A `spline` series. If the [type](#series.spline.type) option is
  180. * not specified, it is inherited from [chart.type](#chart.type).
  181. *
  182. * @extends series,plotOptions.spline
  183. * @excluding dataParser, dataURL, step, boostThreshold, boostBlending
  184. * @product highcharts highstock
  185. * @apioption series.spline
  186. */
  187. /**
  188. * An array of data points for the series. For the `spline` series type,
  189. * points can be given in the following ways:
  190. *
  191. * 1. An array of numerical values. In this case, the numerical values will be
  192. * interpreted as `y` options. The `x` values will be automatically
  193. * calculated, either starting at 0 and incremented by 1, or from
  194. * `pointStart` and `pointInterval` given in the series options. If the axis
  195. * has categories, these will be used. Example:
  196. * ```js
  197. * data: [0, 5, 3, 5]
  198. * ```
  199. *
  200. * 2. An array of arrays with 2 values. In this case, the values correspond to
  201. * `x,y`. If the first value is a string, it is applied as the name of the
  202. * point, and the `x` value is inferred.
  203. * ```js
  204. * data: [
  205. * [0, 9],
  206. * [1, 2],
  207. * [2, 8]
  208. * ]
  209. * ```
  210. *
  211. * 3. An array of objects with named values. The following snippet shows only a
  212. * few settings, see the complete options set below. If the total number of
  213. * data points exceeds the series'
  214. * [turboThreshold](#series.spline.turboThreshold),
  215. * this option is not available.
  216. * ```js
  217. * data: [{
  218. * x: 1,
  219. * y: 9,
  220. * name: "Point2",
  221. * color: "#00FF00"
  222. * }, {
  223. * x: 1,
  224. * y: 0,
  225. * name: "Point1",
  226. * color: "#FF00FF"
  227. * }]
  228. * ```
  229. *
  230. * @sample {highcharts} highcharts/chart/reflow-true/
  231. * Numerical values
  232. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  233. * Arrays of numeric x and y
  234. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  235. * Arrays of datetime x and y
  236. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  237. * Arrays of point.name and y
  238. * @sample {highcharts} highcharts/series/data-array-of-objects/
  239. * Config objects
  240. *
  241. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  242. * @extends series.line.data
  243. * @product highcharts highstock
  244. * @apioption series.spline.data
  245. */
  246. ''; // adds doclets above intro transpilat