ColumnPyramidSeries.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /* *
  2. * (c) 2010-2019 Sebastian Bochan
  3. *
  4. * License: www.highcharts.com/license
  5. */
  6. 'use strict';
  7. import H from '../parts/Globals.js';
  8. import '../parts/Utilities.js';
  9. var pick = H.pick,
  10. seriesType = H.seriesType,
  11. seriesTypes = H.seriesTypes;
  12. var colProto = seriesTypes.column.prototype;
  13. /**
  14. * The ColumnPyramidSeries class
  15. *
  16. * @private
  17. * @class
  18. * @name Highcharts.seriesTypes.columnpyramid
  19. *
  20. * @augments Highcharts.Series
  21. */
  22. seriesType('columnpyramid', 'column'
  23. /**
  24. * Column pyramid series display one pyramid per value along an X axis.
  25. * Requires `highcharts-more.js`. To display horizontal pyramids,
  26. * set [chart.inverted](#chart.inverted) to `true`.
  27. *
  28. * @sample {highcharts|highstock} highcharts/demo/column-pyramid/
  29. * Column pyramid
  30. * @sample {highcharts|highstock} highcharts/plotoptions/columnpyramid-stacked/
  31. * Column pyramid stacked
  32. * @sample {highcharts|highstock} highcharts/plotoptions/columnpyramid-inverted/
  33. * Column pyramid inverted
  34. *
  35. * @extends plotOptions.column
  36. * @since 7.0.0
  37. * @product highcharts highstock
  38. * @excluding boostThreshold, borderRadius, crisp, depth, edgeColor,
  39. * edgeWidth, groupZPadding, negativeColor, softThreshold,
  40. * threshold, zoneAxis, zones
  41. * @optionparent plotOptions.columnpyramid
  42. */
  43. , {}, {
  44. // Overrides the column translate method
  45. translate: function () {
  46. var series = this,
  47. chart = series.chart,
  48. options = series.options,
  49. dense = series.dense =
  50. series.closestPointRange * series.xAxis.transA < 2,
  51. borderWidth = series.borderWidth = pick(
  52. options.borderWidth,
  53. dense ? 0 : 1 // #3635
  54. ),
  55. yAxis = series.yAxis,
  56. threshold = options.threshold,
  57. translatedThreshold = series.translatedThreshold =
  58. yAxis.getThreshold(threshold),
  59. minPointLength = pick(options.minPointLength, 5),
  60. metrics = series.getColumnMetrics(),
  61. pointWidth = metrics.width,
  62. // postprocessed for border width
  63. seriesBarW = series.barW =
  64. Math.max(pointWidth, 1 + 2 * borderWidth),
  65. pointXOffset = series.pointXOffset = metrics.offset;
  66. if (chart.inverted) {
  67. translatedThreshold -= 0.5; // #3355
  68. }
  69. // When the pointPadding is 0,
  70. // we want the pyramids to be packed tightly,
  71. // so we allow individual pyramids to have individual sizes.
  72. // When pointPadding is greater,
  73. // we strive for equal-width columns (#2694).
  74. if (options.pointPadding) {
  75. seriesBarW = Math.ceil(seriesBarW);
  76. }
  77. colProto.translate.apply(series);
  78. // Record the new values
  79. series.points.forEach(function (point) {
  80. var yBottom = pick(point.yBottom, translatedThreshold),
  81. safeDistance = 999 + Math.abs(yBottom),
  82. plotY = Math.min(
  83. Math.max(-safeDistance, point.plotY),
  84. yAxis.len + safeDistance
  85. ),
  86. // Don't draw too far outside plot area
  87. // (#1303, #2241, #4264)
  88. barX = point.plotX + pointXOffset,
  89. barW = seriesBarW / 2,
  90. barY = Math.min(plotY, yBottom),
  91. barH = Math.max(plotY, yBottom) - barY,
  92. stackTotal, stackHeight, topPointY, topXwidth, bottomXwidth,
  93. invBarPos,
  94. x1, x2, x3, x4, y1, y2;
  95. point.barX = barX;
  96. point.pointWidth = pointWidth;
  97. // Fix the tooltip on center of grouped pyramids
  98. // (#1216, #424, #3648)
  99. point.tooltipPos = chart.inverted ? [
  100. yAxis.len + yAxis.pos - chart.plotLeft - plotY,
  101. series.xAxis.len - barX - barW, barH
  102. ] : [barX + barW, plotY + yAxis.pos - chart.plotTop, barH];
  103. stackTotal = threshold + (point.total || point.y);
  104. // overwrite stacktotal (always 100 / -100)
  105. if (options.stacking === 'percent') {
  106. stackTotal = threshold + (point.y < 0) ? -100 : 100;
  107. }
  108. // get the highest point (if stack, extract from total)
  109. topPointY = yAxis.toPixels((stackTotal), true);
  110. // calculate height of stack (in pixels)
  111. stackHeight = chart.plotHeight - topPointY -
  112. (chart.plotHeight - translatedThreshold);
  113. // topXwidth and bottomXwidth = width of lines from the center
  114. // calculated from tanges proportion.
  115. topXwidth = (barW * (barY - topPointY)) / stackHeight;
  116. // like topXwidth, but with height of point
  117. bottomXwidth = (barW * (barY + barH - topPointY)) / stackHeight;
  118. /*
  119. /\
  120. / \
  121. x1,y1,------ x2,y1
  122. / \
  123. ----------
  124. x4,y2 x3,y2
  125. */
  126. x1 = barX - topXwidth + barW;
  127. x2 = barX + topXwidth + barW;
  128. x3 = barX + bottomXwidth + barW;
  129. x4 = barX - bottomXwidth + barW;
  130. y1 = barY - minPointLength;
  131. y2 = barY + barH;
  132. if (point.y < 0) {
  133. y1 = barY;
  134. y2 = barY + barH + minPointLength;
  135. }
  136. // inverted chart
  137. if (chart.inverted) {
  138. invBarPos = chart.plotWidth - barY;
  139. stackHeight = (topPointY -
  140. (chart.plotWidth - translatedThreshold));
  141. // proportion tanges
  142. topXwidth = (barW *
  143. (topPointY - invBarPos)) / stackHeight;
  144. bottomXwidth = (barW *
  145. (topPointY - (invBarPos - barH))) / stackHeight;
  146. x1 = barX + barW + topXwidth; // top bottom
  147. x2 = x1 - 2 * topXwidth; // top top
  148. x3 = barX - bottomXwidth + barW; // bottom top
  149. x4 = barX + bottomXwidth + barW; // bottom bottom
  150. y1 = barY;
  151. y2 = barY + barH - minPointLength;
  152. if (point.y < 0) {
  153. y2 = barY + barH + minPointLength;
  154. }
  155. }
  156. // Register shape type and arguments to be used in drawPoints
  157. point.shapeType = 'path';
  158. point.shapeArgs = {
  159. // args for datalabels positioning
  160. x: x1,
  161. y: y1,
  162. width: x2 - x1,
  163. height: barH,
  164. // path of pyramid
  165. d: ['M',
  166. x1, y1,
  167. 'L',
  168. x2, y1,
  169. x3, y2,
  170. x4, y2,
  171. 'Z'
  172. ]
  173. };
  174. });
  175. }
  176. });
  177. /**
  178. * A `columnpyramid` series. If the [type](#series.columnpyramid.type) option is
  179. * not specified, it is inherited from [chart.type](#chart.type).
  180. *
  181. * @extends series,plotOptions.columnpyramid
  182. * @excluding connectEnds, connectNulls, dashStyle, dataParser, dataURL,
  183. * gapSize, gapUnit, linecap, lineWidth, marker, step
  184. * @product highcharts highstock
  185. * @apioption series.columnpyramid
  186. */
  187. /**
  188. * @excluding halo, lineWidth, lineWidthPlus, marker
  189. * @product highcharts highstock
  190. * @apioption series.columnpyramid.states.hover
  191. */
  192. /**
  193. * @excluding halo, lineWidth, lineWidthPlus, marker
  194. * @product highcharts highstock
  195. * @apioption series.columnpyramid.states.select
  196. */
  197. /**
  198. * An array of data points for the series. For the `columnpyramid` series type,
  199. * points can be given in the following ways:
  200. *
  201. * 1. An array of numerical values. In this case, the numerical values will be
  202. * interpreted as `y` options. The `x` values will be automatically
  203. * calculated, either starting at 0 and incremented by 1, or from
  204. * `pointStart` and `pointInterval` given in the series options. If the axis
  205. * has categories, these will be used. Example:
  206. * ```js
  207. * data: [0, 5, 3, 5]
  208. * ```
  209. *
  210. * 2. An array of arrays with 2 values. In this case, the values correspond to
  211. * `x,y`. If the first value is a string, it is applied as the name of the
  212. * point, and the `x` value is inferred.
  213. * ```js
  214. * data: [
  215. * [0, 6],
  216. * [1, 2],
  217. * [2, 6]
  218. * ]
  219. * ```
  220. *
  221. * 3. An array of objects with named values. The objects are point configuration
  222. * objects as seen below. If the total number of data points exceeds the
  223. * series' [turboThreshold](#series.columnpyramid.turboThreshold), this
  224. * 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: 6,
  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>|*>}
  251. * @extends series.line.data
  252. * @excluding marker
  253. * @product highcharts highstock
  254. * @apioption series.columnpyramid.data
  255. */