SplineSeries.js 8.2 KB

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