variwide.src.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /**
  2. * @license Highcharts JS v6.1.0 (2018-04-13)
  3. * Highcharts variwide module
  4. *
  5. * (c) 2010-2017 Torstein Honsi
  6. *
  7. * License: www.highcharts.com/license
  8. */
  9. 'use strict';
  10. (function (factory) {
  11. if (typeof module === 'object' && module.exports) {
  12. module.exports = factory;
  13. } else {
  14. factory(Highcharts);
  15. }
  16. }(function (Highcharts) {
  17. (function (H) {
  18. /**
  19. * Highcharts variwide module
  20. *
  21. * (c) 2010-2017 Torstein Honsi
  22. *
  23. * License: www.highcharts.com/license
  24. */
  25. /**
  26. * To do:
  27. * - When X axis is not categorized, the scale should reflect how the z values
  28. * increase, like a horizontal stack. But then the actual X values aren't
  29. * reflected the the axis.. Should we introduce a Z axis too?
  30. */
  31. var addEvent = H.addEvent,
  32. seriesType = H.seriesType,
  33. seriesTypes = H.seriesTypes,
  34. each = H.each,
  35. pick = H.pick;
  36. /**
  37. * A variwide chart (related to marimekko chart) is a column chart with a
  38. * variable width expressing a third dimension.
  39. *
  40. * @extends {plotOptions.column}
  41. * @excluding boostThreshold,crisp,depth,edgeColor,edgeWidth,groupZPadding
  42. * @product highcharts
  43. * @sample {highcharts} highcharts/demo/variwide/
  44. * Variwide chart
  45. * @since 6.0.0
  46. * @optionparent plotOptions.variwide
  47. */
  48. seriesType('variwide', 'column', {
  49. /**
  50. * In a variwide chart, the point padding is 0 in order to express the
  51. * horizontal stacking of items.
  52. */
  53. pointPadding: 0,
  54. /**
  55. * In a variwide chart, the group padding is 0 in order to express the
  56. * horizontal stacking of items.
  57. */
  58. groupPadding: 0
  59. }, {
  60. pointArrayMap: ['y', 'z'],
  61. parallelArrays: ['x', 'y', 'z'],
  62. processData: function () {
  63. var series = this;
  64. this.totalZ = 0;
  65. this.relZ = [];
  66. seriesTypes.column.prototype.processData.call(this);
  67. each(this.zData, function (z, i) {
  68. series.relZ[i] = series.totalZ;
  69. series.totalZ += z;
  70. });
  71. if (this.xAxis.categories) {
  72. this.xAxis.variwide = true;
  73. }
  74. },
  75. /**
  76. * Translate an x value inside a given category index into the distorted
  77. * axis translation.
  78. * @param {Number} index The category index
  79. * @param {Number} x The X pixel position in undistorted axis pixels
  80. * @return {Number} Distorted X position
  81. */
  82. postTranslate: function (index, x) {
  83. var axis = this.xAxis,
  84. relZ = this.relZ,
  85. i = index,
  86. len = axis.len,
  87. totalZ = this.totalZ,
  88. linearSlotLeft = i / relZ.length * len,
  89. linearSlotRight = (i + 1) / relZ.length * len,
  90. slotLeft = (pick(relZ[i], totalZ) / totalZ) * len,
  91. slotRight = (pick(relZ[i + 1], totalZ) / totalZ) * len,
  92. xInsideLinearSlot = x - linearSlotLeft,
  93. ret;
  94. ret = slotLeft +
  95. xInsideLinearSlot * (slotRight - slotLeft) /
  96. (linearSlotRight - linearSlotLeft);
  97. return ret;
  98. },
  99. /**
  100. * Extend translation by distoring X position based on Z.
  101. */
  102. translate: function () {
  103. // Temporarily disable crisping when computing original shapeArgs
  104. var crispOption = this.options.crisp;
  105. this.options.crisp = false;
  106. seriesTypes.column.prototype.translate.call(this);
  107. // Reset option
  108. this.options.crisp = crispOption;
  109. var inverted = this.chart.inverted,
  110. crisp = this.borderWidth % 2 / 2;
  111. // Distort the points to reflect z dimension
  112. each(this.points, function (point, i) {
  113. var left = this.postTranslate(
  114. i,
  115. point.shapeArgs.x
  116. ),
  117. right = this.postTranslate(
  118. i,
  119. point.shapeArgs.x + point.shapeArgs.width
  120. );
  121. if (this.options.crisp) {
  122. left = Math.round(left) - crisp;
  123. right = Math.round(right) - crisp;
  124. }
  125. point.shapeArgs.x = left;
  126. point.shapeArgs.width = right - left;
  127. // Crosshair position (#8083)
  128. point.plotX = (left + right) / 2;
  129. point.crosshairWidth = right - left;
  130. point.tooltipPos[inverted ? 1 : 0] = this.postTranslate(
  131. i,
  132. point.tooltipPos[inverted ? 1 : 0]
  133. );
  134. }, this);
  135. }
  136. // Point functions
  137. }, {
  138. isValid: function () {
  139. return H.isNumber(this.y, true) && H.isNumber(this.z, true);
  140. }
  141. });
  142. H.Tick.prototype.postTranslate = function (xy, xOrY, index) {
  143. xy[xOrY] = this.axis.pos +
  144. this.axis.series[0].postTranslate(index, xy[xOrY] - this.axis.pos);
  145. };
  146. // Same width as the point itself (#8083)
  147. addEvent(H.Axis, 'afterDrawCrosshair', function (e) {
  148. if (this.variwide) {
  149. this.cross.attr('stroke-width', e.point && e.point.shapeArgs.width);
  150. }
  151. });
  152. addEvent(H.Tick, 'afterGetPosition', function (e) {
  153. var axis = this.axis,
  154. xOrY = axis.horiz ? 'x' : 'y';
  155. if (axis.categories && axis.variwide) {
  156. this[xOrY + 'Orig'] = e.pos[xOrY];
  157. this.postTranslate(e.pos, xOrY, this.pos);
  158. }
  159. });
  160. H.wrap(H.Tick.prototype, 'getLabelPosition', function (
  161. proceed,
  162. x,
  163. y,
  164. label,
  165. horiz,
  166. labelOptions,
  167. tickmarkOffset,
  168. index
  169. ) {
  170. var args = Array.prototype.slice.call(arguments, 1),
  171. xy,
  172. xOrY = horiz ? 'x' : 'y';
  173. // Replace the x with the original x
  174. if (this.axis.variwide && typeof this[xOrY + 'Orig'] === 'number') {
  175. args[horiz ? 0 : 1] = this[xOrY + 'Orig'];
  176. }
  177. xy = proceed.apply(this, args);
  178. // Post-translate
  179. if (this.axis.variwide && this.axis.categories) {
  180. this.postTranslate(xy, xOrY, index);
  181. }
  182. return xy;
  183. });
  184. /**
  185. * A `variwide` series. If the [type](#series.variwide.type) option is
  186. * not specified, it is inherited from [chart.type](#chart.type).
  187. *
  188. * @type {Object}
  189. * @extends series,plotOptions.variwide
  190. * @product highcharts
  191. * @apioption series.variwide
  192. */
  193. /**
  194. * An array of data points for the series. For the `variwide` series type,
  195. * points can be given in the following ways:
  196. *
  197. * 1. An array of arrays with 3 or 2 values. In this case, the values
  198. * correspond to `x,y,z`. If the first value is a string, it is applied
  199. * as the name of the point, and the `x` value is inferred. The `x`
  200. * value can also be omitted, in which case the inner arrays should
  201. * be of length 2\. Then the `x` value is automatically calculated,
  202. * either starting at 0 and incremented by 1, or from `pointStart` and
  203. * `pointInterval` given in the series options.
  204. *
  205. * ```js
  206. * data: [
  207. * [0, 1, 2],
  208. * [1, 5, 5],
  209. * [2, 0, 2]
  210. * ]
  211. * ```
  212. *
  213. * 2. An array of objects with named values. The objects are point
  214. * configuration objects as seen below. If the total number of data
  215. * points exceeds the series' [turboThreshold](#series.variwide.turboThreshold),
  216. * this option is not available.
  217. *
  218. * ```js
  219. * data: [{
  220. * x: 1,
  221. * y: 1,
  222. * z: 1,
  223. * name: "Point2",
  224. * color: "#00FF00"
  225. * }, {
  226. * x: 1,
  227. * y: 5,
  228. * z: 4,
  229. * name: "Point1",
  230. * color: "#FF00FF"
  231. * }]
  232. * ```
  233. *
  234. * @type {Array<Object|Array>}
  235. * @extends series.line.data
  236. * @excluding marker
  237. * @sample {highcharts} highcharts/chart/reflow-true/
  238. * Numerical values
  239. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  240. * Arrays of numeric x and y
  241. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  242. * Arrays of datetime x and y
  243. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  244. * Arrays of point.name and y
  245. * @sample {highcharts} highcharts/series/data-array-of-objects/
  246. * Config objects
  247. * @product highcharts
  248. * @apioption series.variwide.data
  249. */
  250. /**
  251. * The relative width for each column. The widths are distributed so they sum
  252. * up to the X axis length.
  253. *
  254. * @type {Number}
  255. * @product highcharts
  256. * @apioption series.variwide.data.z
  257. */
  258. }(Highcharts));
  259. }));