variwide.src.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /**
  2. * @license Highcharts JS v7.0.2 (2019-01-17)
  3. * Highcharts variwide module
  4. *
  5. * (c) 2010-2019 Torstein Honsi
  6. *
  7. * License: www.highcharts.com/license
  8. */
  9. 'use strict';
  10. (function (factory) {
  11. if (typeof module === 'object' && module.exports) {
  12. factory['default'] = factory;
  13. module.exports = factory;
  14. } else if (typeof define === 'function' && define.amd) {
  15. define(function () {
  16. return factory;
  17. });
  18. } else {
  19. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  20. }
  21. }(function (Highcharts) {
  22. (function (H) {
  23. /* *
  24. * Highcharts variwide module
  25. *
  26. * (c) 2010-2019 Torstein Honsi
  27. *
  28. * License: www.highcharts.com/license
  29. */
  30. var addEvent = H.addEvent,
  31. seriesType = H.seriesType,
  32. seriesTypes = H.seriesTypes,
  33. pick = H.pick;
  34. /**
  35. * @private
  36. * @class
  37. * @name Highcharts.seriesTypes.variwide
  38. *
  39. * @augments Highcharts.Series
  40. */
  41. seriesType('variwide', 'column'
  42. /**
  43. * A variwide chart (related to marimekko chart) is a column chart with a
  44. * variable width expressing a third dimension.
  45. *
  46. * @sample {highcharts} highcharts/demo/variwide/
  47. * Variwide chart
  48. * @sample {highcharts} highcharts/series-variwide/inverted/
  49. * Inverted variwide chart
  50. * @sample {highcharts} highcharts/series-variwide/datetime/
  51. * Variwide columns on a datetime axis
  52. *
  53. * @extends plotOptions.column
  54. * @since 6.0.0
  55. * @product highcharts
  56. * @excluding boostThreshold, crisp, depth, edgeColor, edgeWidth,
  57. * groupZPadding
  58. * @optionparent plotOptions.variwide
  59. */
  60. , {
  61. /**
  62. * In a variwide chart, the point padding is 0 in order to express the
  63. * horizontal stacking of items.
  64. */
  65. pointPadding: 0,
  66. /**
  67. * In a variwide chart, the group padding is 0 in order to express the
  68. * horizontal stacking of items.
  69. */
  70. groupPadding: 0
  71. }, {
  72. pointArrayMap: ['y', 'z'],
  73. parallelArrays: ['x', 'y', 'z'],
  74. processData: function (force) {
  75. this.totalZ = 0;
  76. this.relZ = [];
  77. seriesTypes.column.prototype.processData.call(this, force);
  78. (this.xAxis.reversed ?
  79. this.zData.slice().reverse() :
  80. this.zData).forEach(
  81. function (z, i) {
  82. this.relZ[i] = this.totalZ;
  83. this.totalZ += z;
  84. },
  85. this
  86. );
  87. if (this.xAxis.categories) {
  88. this.xAxis.variwide = true;
  89. this.xAxis.zData = this.zData; // Used for label rank
  90. }
  91. },
  92. /**
  93. * Translate an x value inside a given category index into the distorted
  94. * axis translation.
  95. *
  96. * @private
  97. * @function Highcharts.Series#postTranslate
  98. *
  99. * @param {number} index
  100. * The category index
  101. *
  102. * @param {number} x
  103. * The X pixel position in undistorted axis pixels
  104. *
  105. * @return {number}
  106. * Distorted X position
  107. */
  108. postTranslate: function (index, x, point) {
  109. var axis = this.xAxis,
  110. relZ = this.relZ,
  111. i = axis.reversed ? relZ.length - index : index,
  112. goRight = axis.reversed ? -1 : 1,
  113. len = axis.len,
  114. totalZ = this.totalZ,
  115. linearSlotLeft = i / relZ.length * len,
  116. linearSlotRight = (i + goRight) / relZ.length * len,
  117. slotLeft = (pick(relZ[i], totalZ) / totalZ) * len,
  118. slotRight = (pick(relZ[i + goRight], totalZ) / totalZ) * len,
  119. xInsideLinearSlot = x - linearSlotLeft,
  120. ret;
  121. // Set crosshairWidth for every point (#8173)
  122. if (point) {
  123. point.crosshairWidth = slotRight - slotLeft;
  124. }
  125. ret = slotLeft +
  126. xInsideLinearSlot * (slotRight - slotLeft) /
  127. (linearSlotRight - linearSlotLeft);
  128. return ret;
  129. },
  130. // Extend translation by distoring X position based on Z.
  131. translate: function () {
  132. // Temporarily disable crisping when computing original shapeArgs
  133. var crispOption = this.options.crisp,
  134. xAxis = this.xAxis;
  135. this.options.crisp = false;
  136. seriesTypes.column.prototype.translate.call(this);
  137. // Reset option
  138. this.options.crisp = crispOption;
  139. var inverted = this.chart.inverted,
  140. crisp = this.borderWidth % 2 / 2;
  141. // Distort the points to reflect z dimension
  142. this.points.forEach(function (point, i) {
  143. var left, right;
  144. if (xAxis.variwide) {
  145. left = this.postTranslate(
  146. i,
  147. point.shapeArgs.x,
  148. point
  149. );
  150. right = this.postTranslate(
  151. i,
  152. point.shapeArgs.x + point.shapeArgs.width
  153. );
  154. // For linear or datetime axes, the variwide column should
  155. // start with X and extend Z units, without modifying the
  156. // axis.
  157. } else {
  158. left = point.plotX;
  159. right = xAxis.translate(
  160. point.x + point.z,
  161. 0,
  162. 0,
  163. 0,
  164. 1
  165. );
  166. }
  167. if (this.options.crisp) {
  168. left = Math.round(left) - crisp;
  169. right = Math.round(right) - crisp;
  170. }
  171. point.shapeArgs.x = left;
  172. point.shapeArgs.width = right - left;
  173. // Crosshair position (#8083)
  174. point.plotX = (left + right) / 2;
  175. // Adjust the tooltip position
  176. if (!inverted) {
  177. point.tooltipPos[0] =
  178. point.shapeArgs.x + point.shapeArgs.width / 2;
  179. } else {
  180. point.tooltipPos[1] =
  181. xAxis.len - point.shapeArgs.x - point.shapeArgs.width / 2;
  182. }
  183. }, this);
  184. }
  185. // Point functions
  186. }, {
  187. isValid: function () {
  188. return H.isNumber(this.y, true) && H.isNumber(this.z, true);
  189. }
  190. });
  191. H.Tick.prototype.postTranslate = function (xy, xOrY, index) {
  192. var axis = this.axis,
  193. pos = xy[xOrY] - axis.pos;
  194. if (!axis.horiz) {
  195. pos = axis.len - pos;
  196. }
  197. pos = axis.series[0].postTranslate(index, pos);
  198. if (!axis.horiz) {
  199. pos = axis.len - pos;
  200. }
  201. xy[xOrY] = axis.pos + pos;
  202. };
  203. // Same width as the category (#8083)
  204. addEvent(H.Axis, 'afterDrawCrosshair', function (e) {
  205. if (this.variwide && this.cross) {
  206. this.cross.attr('stroke-width', e.point && e.point.crosshairWidth);
  207. }
  208. });
  209. // On a vertical axis, apply anti-collision logic to the labels.
  210. addEvent(H.Axis, 'afterRender', function () {
  211. var axis = this;
  212. if (!this.horiz && this.variwide) {
  213. this.chart.labelCollectors.push(function () {
  214. return axis.tickPositions.map(function (pos, i) {
  215. var label = axis.ticks[pos].label;
  216. label.labelrank = axis.zData[i];
  217. return label;
  218. });
  219. });
  220. }
  221. });
  222. addEvent(H.Tick, 'afterGetPosition', function (e) {
  223. var axis = this.axis,
  224. xOrY = axis.horiz ? 'x' : 'y';
  225. if (axis.variwide) {
  226. this[xOrY + 'Orig'] = e.pos[xOrY];
  227. this.postTranslate(e.pos, xOrY, this.pos);
  228. }
  229. });
  230. H.wrap(H.Tick.prototype, 'getLabelPosition', function (
  231. proceed,
  232. x,
  233. y,
  234. label,
  235. horiz,
  236. labelOptions,
  237. tickmarkOffset,
  238. index
  239. ) {
  240. var args = Array.prototype.slice.call(arguments, 1),
  241. xy,
  242. xOrY = horiz ? 'x' : 'y';
  243. // Replace the x with the original x
  244. if (this.axis.variwide && typeof this[xOrY + 'Orig'] === 'number') {
  245. args[horiz ? 0 : 1] = this[xOrY + 'Orig'];
  246. }
  247. xy = proceed.apply(this, args);
  248. // Post-translate
  249. if (this.axis.variwide && this.axis.categories) {
  250. this.postTranslate(xy, xOrY, index);
  251. }
  252. return xy;
  253. });
  254. /**
  255. * A `variwide` series. If the [type](#series.variwide.type) option is not
  256. * specified, it is inherited from [chart.type](#chart.type).
  257. *
  258. * @extends series,plotOptions.variwide
  259. * @product highcharts
  260. * @apioption series.variwide
  261. */
  262. /**
  263. * An array of data points for the series. For the `variwide` series type,
  264. * points can be given in the following ways:
  265. *
  266. * 1. An array of arrays with 3 or 2 values. In this case, the values correspond
  267. * to `x,y,z`. If the first value is a string, it is applied as the name of
  268. * the point, and the `x` value is inferred. The `x` value can also be
  269. * omitted, in which case the inner arrays should be of length 2. Then the
  270. * `x` value is automatically calculated, either starting at 0 and
  271. * incremented by 1, or from `pointStart` and `pointInterval` given in the
  272. * series options.
  273. * ```js
  274. * data: [
  275. * [0, 1, 2],
  276. * [1, 5, 5],
  277. * [2, 0, 2]
  278. * ]
  279. * ```
  280. *
  281. * 2. An array of objects with named values. The following snippet shows only a
  282. * few settings, see the complete options set below. If the total number of
  283. * data points exceeds the series'
  284. * [turboThreshold](#series.variwide.turboThreshold), this option is not
  285. * available.
  286. * ```js
  287. * data: [{
  288. * x: 1,
  289. * y: 1,
  290. * z: 1,
  291. * name: "Point2",
  292. * color: "#00FF00"
  293. * }, {
  294. * x: 1,
  295. * y: 5,
  296. * z: 4,
  297. * name: "Point1",
  298. * color: "#FF00FF"
  299. * }]
  300. * ```
  301. *
  302. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  303. * Arrays of numeric x and y
  304. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  305. * Arrays of datetime x and y
  306. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  307. * Arrays of point.name and y
  308. * @sample {highcharts} highcharts/series/data-array-of-objects/
  309. * Config objects
  310. *
  311. * @type {Array<Array<(number|string),number>|Array<(number|string),number,number>|*>}
  312. * @extends series.line.data
  313. * @excluding marker
  314. * @product highcharts
  315. * @apioption series.variwide.data
  316. */
  317. /**
  318. * The relative width for each column. On a category axis, the widths are
  319. * distributed so they sum up to the X axis length. On linear and datetime axes,
  320. * the columns will be laid out from the X value and Z units along the axis.
  321. *
  322. * @type {number}
  323. * @product highcharts
  324. * @apioption series.variwide.data.z
  325. */
  326. }(Highcharts));
  327. return (function () {
  328. }());
  329. }));