ColumnSeries.js 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  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 H from '../Core/Globals.js';
  12. /**
  13. * Adjusted width and x offset of the columns for grouping.
  14. *
  15. * @private
  16. * @interface Highcharts.ColumnMetricsObject
  17. */ /**
  18. * Width of the columns.
  19. * @name Highcharts.ColumnMetricsObject#width
  20. * @type {number}
  21. */ /**
  22. * Offset of the columns.
  23. * @name Highcharts.ColumnMetricsObject#offset
  24. * @type {number}
  25. */
  26. ''; // detach doclets above
  27. import Color from '../Core/Color.js';
  28. var color = Color.parse;
  29. import LegendSymbolMixin from '../Mixins/LegendSymbol.js';
  30. import U from '../Core/Utilities.js';
  31. var animObject = U.animObject, clamp = U.clamp, defined = U.defined, extend = U.extend, isNumber = U.isNumber, merge = U.merge, pick = U.pick, seriesType = U.seriesType, objectEach = U.objectEach;
  32. import '../Core/Series/Series.js';
  33. import '../Core/Options.js';
  34. var noop = H.noop, Series = H.Series, svg = H.svg;
  35. /**
  36. * The column series type.
  37. *
  38. * @private
  39. * @class
  40. * @name Highcharts.seriesTypes.column
  41. *
  42. * @augments Highcharts.Series
  43. */
  44. seriesType('column', 'line',
  45. /**
  46. * Column series display one column per value along an X axis.
  47. *
  48. * @sample {highcharts} highcharts/demo/column-basic/
  49. * Column chart
  50. * @sample {highstock} stock/demo/column/
  51. * Column chart
  52. *
  53. * @extends plotOptions.line
  54. * @excluding connectEnds, connectNulls, gapSize, gapUnit, linecap,
  55. * lineWidth, marker, step, useOhlcData
  56. * @product highcharts highstock
  57. * @optionparent plotOptions.column
  58. */
  59. {
  60. /**
  61. * The corner radius of the border surrounding each column or bar.
  62. *
  63. * @sample {highcharts} highcharts/plotoptions/column-borderradius/
  64. * Rounded columns
  65. *
  66. * @product highcharts highstock gantt
  67. *
  68. * @private
  69. */
  70. borderRadius: 0,
  71. /**
  72. * When using automatic point colors pulled from the global
  73. * [colors](colors) or series-specific
  74. * [plotOptions.column.colors](series.colors) collections, this option
  75. * determines whether the chart should receive one color per series or
  76. * one color per point.
  77. *
  78. * In styled mode, the `colors` or `series.colors` arrays are not
  79. * supported, and instead this option gives the points individual color
  80. * class names on the form `highcharts-color-{n}`.
  81. *
  82. * @see [series colors](#plotOptions.column.colors)
  83. *
  84. * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-false/
  85. * False by default
  86. * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-true/
  87. * True
  88. *
  89. * @type {boolean}
  90. * @default false
  91. * @since 2.0
  92. * @product highcharts highstock gantt
  93. * @apioption plotOptions.column.colorByPoint
  94. */
  95. /**
  96. * A series specific or series type specific color set to apply instead
  97. * of the global [colors](#colors) when [colorByPoint](
  98. * #plotOptions.column.colorByPoint) is true.
  99. *
  100. * @type {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
  101. * @since 3.0
  102. * @product highcharts highstock gantt
  103. * @apioption plotOptions.column.colors
  104. */
  105. /**
  106. * When `true`, the columns will center in the category, ignoring null
  107. * or missing points. When `false`, space will be reserved for null or
  108. * missing points.
  109. *
  110. * @sample {highcharts} highcharts/series-column/centerincategory/
  111. * Center in category
  112. *
  113. * @since 8.0.1
  114. * @product highcharts highstock gantt
  115. */
  116. centerInCategory: false,
  117. /**
  118. * Padding between each value groups, in x axis units.
  119. *
  120. * @sample {highcharts} highcharts/plotoptions/column-grouppadding-default/
  121. * 0.2 by default
  122. * @sample {highcharts} highcharts/plotoptions/column-grouppadding-none/
  123. * No group padding - all columns are evenly spaced
  124. *
  125. * @product highcharts highstock gantt
  126. *
  127. * @private
  128. */
  129. groupPadding: 0.2,
  130. /**
  131. * Whether to group non-stacked columns or to let them render
  132. * independent of each other. Non-grouped columns will be laid out
  133. * individually and overlap each other.
  134. *
  135. * @sample {highcharts} highcharts/plotoptions/column-grouping-false/
  136. * Grouping disabled
  137. * @sample {highstock} highcharts/plotoptions/column-grouping-false/
  138. * Grouping disabled
  139. *
  140. * @type {boolean}
  141. * @default true
  142. * @since 2.3.0
  143. * @product highcharts highstock gantt
  144. * @apioption plotOptions.column.grouping
  145. */
  146. /**
  147. * @ignore-option
  148. * @private
  149. */
  150. marker: null,
  151. /**
  152. * The maximum allowed pixel width for a column, translated to the
  153. * height of a bar in a bar chart. This prevents the columns from
  154. * becoming too wide when there is a small number of points in the
  155. * chart.
  156. *
  157. * @see [pointWidth](#plotOptions.column.pointWidth)
  158. *
  159. * @sample {highcharts} highcharts/plotoptions/column-maxpointwidth-20/
  160. * Limited to 50
  161. * @sample {highstock} highcharts/plotoptions/column-maxpointwidth-20/
  162. * Limited to 50
  163. *
  164. * @type {number}
  165. * @since 4.1.8
  166. * @product highcharts highstock gantt
  167. * @apioption plotOptions.column.maxPointWidth
  168. */
  169. /**
  170. * Padding between each column or bar, in x axis units.
  171. *
  172. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-default/
  173. * 0.1 by default
  174. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-025/
  175. * 0.25
  176. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-none/
  177. * 0 for tightly packed columns
  178. *
  179. * @product highcharts highstock gantt
  180. *
  181. * @private
  182. */
  183. pointPadding: 0.1,
  184. /**
  185. * A pixel value specifying a fixed width for each column or bar point.
  186. * When `null`, the width is calculated from the `pointPadding` and
  187. * `groupPadding`. The width effects the dimension that is not based on
  188. * the point value. For column series it is the hoizontal length and for
  189. * bar series it is the vertical length.
  190. *
  191. * @see [maxPointWidth](#plotOptions.column.maxPointWidth)
  192. *
  193. * @sample {highcharts} highcharts/plotoptions/column-pointwidth-20/
  194. * 20px wide columns regardless of chart width or the amount of
  195. * data points
  196. *
  197. * @type {number}
  198. * @since 1.2.5
  199. * @product highcharts highstock gantt
  200. * @apioption plotOptions.column.pointWidth
  201. */
  202. /**
  203. * A pixel value specifying a fixed width for the column or bar.
  204. * Overrides pointWidth on the series.
  205. *
  206. * @see [series.pointWidth](#plotOptions.column.pointWidth)
  207. *
  208. * @type {number}
  209. * @default undefined
  210. * @since 7.0.0
  211. * @product highcharts highstock gantt
  212. * @apioption series.column.data.pointWidth
  213. */
  214. /**
  215. * The minimal height for a column or width for a bar. By default,
  216. * 0 values are not shown. To visualize a 0 (or close to zero) point,
  217. * set the minimal point length to a pixel value like 3\. In stacked
  218. * column charts, minPointLength might not be respected for tightly
  219. * packed values.
  220. *
  221. * @sample {highcharts} highcharts/plotoptions/column-minpointlength/
  222. * Zero base value
  223. * @sample {highcharts} highcharts/plotoptions/column-minpointlength-pos-and-neg/
  224. * Positive and negative close to zero values
  225. *
  226. * @product highcharts highstock gantt
  227. *
  228. * @private
  229. */
  230. minPointLength: 0,
  231. /**
  232. * When the series contains less points than the crop threshold, all
  233. * points are drawn, event if the points fall outside the visible plot
  234. * area at the current zoom. The advantage of drawing all points
  235. * (including markers and columns), is that animation is performed on
  236. * updates. On the other hand, when the series contains more points than
  237. * the crop threshold, the series data is cropped to only contain points
  238. * that fall within the plot area. The advantage of cropping away
  239. * invisible points is to increase performance on large series.
  240. *
  241. * @product highcharts highstock gantt
  242. *
  243. * @private
  244. */
  245. cropThreshold: 50,
  246. /**
  247. * The X axis range that each point is valid for. This determines the
  248. * width of the column. On a categorized axis, the range will be 1
  249. * by default (one category unit). On linear and datetime axes, the
  250. * range will be computed as the distance between the two closest data
  251. * points.
  252. *
  253. * The default `null` means it is computed automatically, but this
  254. * option can be used to override the automatic value.
  255. *
  256. * This option is set by default to 1 if data sorting is enabled.
  257. *
  258. * @sample {highcharts} highcharts/plotoptions/column-pointrange/
  259. * Set the point range to one day on a data set with one week
  260. * between the points
  261. *
  262. * @type {number|null}
  263. * @since 2.3
  264. * @product highcharts highstock gantt
  265. *
  266. * @private
  267. */
  268. pointRange: null,
  269. states: {
  270. /**
  271. * Options for the hovered point. These settings override the normal
  272. * state options when a point is moused over or touched.
  273. *
  274. * @extends plotOptions.series.states.hover
  275. * @excluding halo, lineWidth, lineWidthPlus, marker
  276. * @product highcharts highstock gantt
  277. */
  278. hover: {
  279. /** @ignore-option */
  280. halo: false,
  281. /**
  282. * A specific border color for the hovered point. Defaults to
  283. * inherit the normal state border color.
  284. *
  285. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  286. * @product highcharts gantt
  287. * @apioption plotOptions.column.states.hover.borderColor
  288. */
  289. /**
  290. * A specific color for the hovered point.
  291. *
  292. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  293. * @product highcharts gantt
  294. * @apioption plotOptions.column.states.hover.color
  295. */
  296. /**
  297. * How much to brighten the point on interaction. Requires the
  298. * main color to be defined in hex or rgb(a) format.
  299. *
  300. * In styled mode, the hover brightening is by default replaced
  301. * with a fill-opacity set in the `.highcharts-point:hover`
  302. * rule.
  303. *
  304. * @sample {highcharts} highcharts/plotoptions/column-states-hover-brightness/
  305. * Brighten by 0.5
  306. *
  307. * @product highcharts highstock gantt
  308. */
  309. brightness: 0.1
  310. },
  311. /**
  312. * Options for the selected point. These settings override the
  313. * normal state options when a point is selected.
  314. *
  315. * @extends plotOptions.series.states.select
  316. * @excluding halo, lineWidth, lineWidthPlus, marker
  317. * @product highcharts highstock gantt
  318. */
  319. select: {
  320. /**
  321. * A specific color for the selected point.
  322. *
  323. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  324. * @default #cccccc
  325. * @product highcharts highstock gantt
  326. */
  327. color: '#cccccc',
  328. /**
  329. * A specific border color for the selected point.
  330. *
  331. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  332. * @default #000000
  333. * @product highcharts highstock gantt
  334. */
  335. borderColor: '#000000'
  336. }
  337. },
  338. dataLabels: {
  339. align: void 0,
  340. verticalAlign: void 0,
  341. /**
  342. * The y position offset of the label relative to the point in
  343. * pixels.
  344. *
  345. * @type {number}
  346. */
  347. y: void 0
  348. },
  349. // false doesn't work well: https://jsfiddle.net/highcharts/hz8fopan/14/
  350. /**
  351. * @ignore-option
  352. * @private
  353. */
  354. startFromThreshold: true,
  355. stickyTracking: false,
  356. tooltip: {
  357. distance: 6
  358. },
  359. /**
  360. * The Y axis value to serve as the base for the columns, for
  361. * distinguishing between values above and below a threshold. If `null`,
  362. * the columns extend from the padding Y axis minimum.
  363. *
  364. * @type {number|null}
  365. * @since 2.0
  366. * @product highcharts
  367. *
  368. * @private
  369. */
  370. threshold: 0,
  371. /**
  372. * The width of the border surrounding each column or bar. Defaults to
  373. * `1` when there is room for a border, but to `0` when the columns are
  374. * so dense that a border would cover the next column.
  375. *
  376. * In styled mode, the stroke width can be set with the
  377. * `.highcharts-point` rule.
  378. *
  379. * @sample {highcharts} highcharts/plotoptions/column-borderwidth/
  380. * 2px black border
  381. *
  382. * @type {number}
  383. * @default undefined
  384. * @product highcharts highstock gantt
  385. * @apioption plotOptions.column.borderWidth
  386. */
  387. /**
  388. * The color of the border surrounding each column or bar.
  389. *
  390. * In styled mode, the border stroke can be set with the
  391. * `.highcharts-point` rule.
  392. *
  393. * @sample {highcharts} highcharts/plotoptions/column-bordercolor/
  394. * Dark gray border
  395. *
  396. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  397. * @default #ffffff
  398. * @product highcharts highstock gantt
  399. *
  400. * @private
  401. */
  402. borderColor: '#ffffff'
  403. },
  404. /**
  405. * @lends seriesTypes.column.prototype
  406. */
  407. {
  408. cropShoulder: 0,
  409. // When tooltip is not shared, this series (and derivatives) requires
  410. // direct touch/hover. KD-tree does not apply.
  411. directTouch: true,
  412. trackerGroups: ['group', 'dataLabelsGroup'],
  413. // use separate negative stacks, unlike area stacks where a negative
  414. // point is substracted from previous (#1910)
  415. negStacks: true,
  416. /* eslint-disable valid-jsdoc */
  417. /**
  418. * Initialize the series. Extends the basic Series.init method by
  419. * marking other series of the same type as dirty.
  420. *
  421. * @private
  422. * @function Highcharts.seriesTypes.column#init
  423. * @return {void}
  424. */
  425. init: function () {
  426. Series.prototype.init.apply(this, arguments);
  427. var series = this, chart = series.chart;
  428. // if the series is added dynamically, force redraw of other
  429. // series affected by a new column
  430. if (chart.hasRendered) {
  431. chart.series.forEach(function (otherSeries) {
  432. if (otherSeries.type === series.type) {
  433. otherSeries.isDirty = true;
  434. }
  435. });
  436. }
  437. },
  438. /**
  439. * Return the width and x offset of the columns adjusted for grouping,
  440. * groupPadding, pointPadding, pointWidth etc.
  441. *
  442. * @private
  443. * @function Highcharts.seriesTypes.column#getColumnMetrics
  444. * @return {Highcharts.ColumnMetricsObject}
  445. */
  446. getColumnMetrics: function () {
  447. var series = this, options = series.options, xAxis = series.xAxis, yAxis = series.yAxis, reversedStacks = xAxis.options.reversedStacks,
  448. // Keep backward compatibility: reversed xAxis had reversed
  449. // stacks
  450. reverseStacks = (xAxis.reversed && !reversedStacks) ||
  451. (!xAxis.reversed && reversedStacks), stackKey, stackGroups = {}, columnCount = 0;
  452. // Get the total number of column type series. This is called on
  453. // every series. Consider moving this logic to a chart.orderStacks()
  454. // function and call it on init, addSeries and removeSeries
  455. if (options.grouping === false) {
  456. columnCount = 1;
  457. }
  458. else {
  459. series.chart.series.forEach(function (otherSeries) {
  460. var otherYAxis = otherSeries.yAxis, otherOptions = otherSeries.options, columnIndex;
  461. if (otherSeries.type === series.type &&
  462. (otherSeries.visible ||
  463. !series.chart.options.chart
  464. .ignoreHiddenSeries) &&
  465. yAxis.len === otherYAxis.len &&
  466. yAxis.pos === otherYAxis.pos) { // #642, #2086
  467. if (otherOptions.stacking && otherOptions.stacking !== 'group') {
  468. stackKey = otherSeries.stackKey;
  469. if (typeof stackGroups[stackKey] ===
  470. 'undefined') {
  471. stackGroups[stackKey] = columnCount++;
  472. }
  473. columnIndex = stackGroups[stackKey];
  474. }
  475. else if (otherOptions.grouping !== false) { // #1162
  476. columnIndex = columnCount++;
  477. }
  478. otherSeries.columnIndex = columnIndex;
  479. }
  480. });
  481. }
  482. var categoryWidth = Math.min(Math.abs(xAxis.transA) * ((xAxis.ordinal && xAxis.ordinal.slope) ||
  483. options.pointRange ||
  484. xAxis.closestPointRange ||
  485. xAxis.tickInterval ||
  486. 1), // #2610
  487. xAxis.len // #1535
  488. ), groupPadding = categoryWidth * options.groupPadding, groupWidth = categoryWidth - 2 * groupPadding, pointOffsetWidth = groupWidth / (columnCount || 1), pointWidth = Math.min(options.maxPointWidth || xAxis.len, pick(options.pointWidth, pointOffsetWidth * (1 - 2 * options.pointPadding))), pointPadding = (pointOffsetWidth - pointWidth) / 2,
  489. // #1251, #3737
  490. colIndex = (series.columnIndex || 0) + (reverseStacks ? 1 : 0), pointXOffset = pointPadding +
  491. (groupPadding +
  492. colIndex * pointOffsetWidth -
  493. (categoryWidth / 2)) * (reverseStacks ? -1 : 1);
  494. // Save it for reading in linked series (Error bars particularly)
  495. series.columnMetrics = {
  496. width: pointWidth,
  497. offset: pointXOffset,
  498. paddedWidth: pointOffsetWidth,
  499. columnCount: columnCount
  500. };
  501. return series.columnMetrics;
  502. },
  503. /**
  504. * Make the columns crisp. The edges are rounded to the nearest full
  505. * pixel.
  506. *
  507. * @private
  508. * @function Highcharts.seriesTypes.column#crispCol
  509. * @param {number} x
  510. * @param {number} y
  511. * @param {number} w
  512. * @param {number} h
  513. * @return {Highcharts.BBoxObject}
  514. */
  515. crispCol: function (x, y, w, h) {
  516. var chart = this.chart, borderWidth = this.borderWidth, xCrisp = -(borderWidth % 2 ? 0.5 : 0), yCrisp = borderWidth % 2 ? 0.5 : 1, right, bottom, fromTop;
  517. if (chart.inverted && chart.renderer.isVML) {
  518. yCrisp += 1;
  519. }
  520. // Horizontal. We need to first compute the exact right edge, then
  521. // round it and compute the width from there.
  522. if (this.options.crisp) {
  523. right = Math.round(x + w) + xCrisp;
  524. x = Math.round(x) + xCrisp;
  525. w = right - x;
  526. }
  527. // Vertical
  528. bottom = Math.round(y + h) + yCrisp;
  529. fromTop = Math.abs(y) <= 0.5 && bottom > 0.5; // #4504, #4656
  530. y = Math.round(y) + yCrisp;
  531. h = bottom - y;
  532. // Top edges are exceptions
  533. if (fromTop && h) { // #5146
  534. y -= 1;
  535. h += 1;
  536. }
  537. return {
  538. x: x,
  539. y: y,
  540. width: w,
  541. height: h
  542. };
  543. },
  544. /**
  545. * Adjust for missing columns, according to the `centerInCategory`
  546. * option. Missing columns are either single points or stacks where the
  547. * point or points are either missing or null.
  548. *
  549. * @private
  550. * @function Highcharts.seriesTypes.column#adjustForMissingColumns
  551. * @param {number} x
  552. * The x coordinate of the column, left side
  553. * @param {number} pointWidth
  554. * The pointWidth, already computed upstream
  555. * @param {Highcharts.ColumnPoint} point
  556. * The point instance
  557. * @param {Highcharts.ColumnMetricsObject} metrics
  558. * The series-wide column metrics
  559. * @return {number}
  560. * The adjusted x position, or the original if not adjusted
  561. */
  562. adjustForMissingColumns: function (x, pointWidth, point, metrics) {
  563. var _this = this;
  564. var stacking = this.options.stacking;
  565. if (!point.isNull && metrics.columnCount > 1) {
  566. var indexInCategory_1 = 0;
  567. var totalInCategory_1 = 0;
  568. // Loop over all the stacks on the Y axis. When stacking is
  569. // enabled, these are real point stacks. When stacking is not
  570. // enabled, but `centerInCategory` is true, there is one stack
  571. // handling the grouping of points in each category. This is
  572. // done in the `setGroupedPoints` function.
  573. objectEach(this.yAxis.stacking && this.yAxis.stacking.stacks, function (stack) {
  574. if (typeof point.x === 'number') {
  575. var stackItem = stack[point.x.toString()];
  576. if (stackItem) {
  577. var pointValues = stackItem.points[_this.index], total = stackItem.total;
  578. // If true `stacking` is enabled, count the
  579. // total number of non-null stacks in the
  580. // category, and note which index this point is
  581. // within those stacks.
  582. if (stacking) {
  583. if (pointValues) {
  584. indexInCategory_1 = totalInCategory_1;
  585. }
  586. if (stackItem.hasValidPoints) {
  587. totalInCategory_1++;
  588. }
  589. // If `stacking` is not enabled, look for the
  590. // index and total of the `group` stack.
  591. }
  592. else if (H.isArray(pointValues)) {
  593. indexInCategory_1 = pointValues[1];
  594. totalInCategory_1 = total || 0;
  595. }
  596. }
  597. }
  598. });
  599. // Compute the adjusted x position
  600. var boxWidth = (totalInCategory_1 - 1) * metrics.paddedWidth +
  601. pointWidth;
  602. x = (point.plotX || 0) + boxWidth / 2 - pointWidth -
  603. indexInCategory_1 * metrics.paddedWidth;
  604. }
  605. return x;
  606. },
  607. /**
  608. * Translate each point to the plot area coordinate system and find
  609. * shape positions
  610. *
  611. * @private
  612. * @function Highcharts.seriesTypes.column#translate
  613. */
  614. translate: function () {
  615. var series = this, chart = series.chart, options = series.options, dense = series.dense =
  616. series.closestPointRange * series.xAxis.transA < 2, borderWidth = series.borderWidth = pick(options.borderWidth, dense ? 0 : 1 // #3635
  617. ), xAxis = series.xAxis, yAxis = series.yAxis, threshold = options.threshold, translatedThreshold = series.translatedThreshold =
  618. yAxis.getThreshold(threshold), minPointLength = pick(options.minPointLength, 5), metrics = series.getColumnMetrics(), seriesPointWidth = metrics.width,
  619. // postprocessed for border width
  620. seriesBarW = series.barW =
  621. Math.max(seriesPointWidth, 1 + 2 * borderWidth), seriesXOffset = series.pointXOffset = metrics.offset, dataMin = series.dataMin, dataMax = series.dataMax;
  622. if (chart.inverted) {
  623. translatedThreshold -= 0.5; // #3355
  624. }
  625. // When the pointPadding is 0, we want the columns to be packed
  626. // tightly, so we allow individual columns to have individual sizes.
  627. // When pointPadding is greater, we strive for equal-width columns
  628. // (#2694).
  629. if (options.pointPadding) {
  630. seriesBarW = Math.ceil(seriesBarW);
  631. }
  632. Series.prototype.translate.apply(series);
  633. // Record the new values
  634. series.points.forEach(function (point) {
  635. var yBottom = pick(point.yBottom, translatedThreshold), safeDistance = 999 + Math.abs(yBottom), pointWidth = seriesPointWidth, plotX = point.plotX || 0,
  636. // Don't draw too far outside plot area (#1303, #2241,
  637. // #4264)
  638. plotY = clamp(point.plotY, -safeDistance, yAxis.len + safeDistance), barX = plotX + seriesXOffset, barW = seriesBarW, barY = Math.min(plotY, yBottom), up, barH = Math.max(plotY, yBottom) - barY;
  639. // Handle options.minPointLength
  640. if (minPointLength && Math.abs(barH) < minPointLength) {
  641. barH = minPointLength;
  642. up = (!yAxis.reversed && !point.negative) ||
  643. (yAxis.reversed && point.negative);
  644. // Reverse zeros if there's no positive value in the series
  645. // in visible range (#7046)
  646. if (isNumber(threshold) &&
  647. isNumber(dataMax) &&
  648. point.y === threshold &&
  649. dataMax <= threshold &&
  650. // and if there's room for it (#7311)
  651. (yAxis.min || 0) < threshold &&
  652. // if all points are the same value (i.e zero) not draw
  653. // as negative points (#10646)
  654. dataMin !== dataMax) {
  655. up = !up;
  656. }
  657. // If stacked...
  658. barY = (Math.abs(barY - translatedThreshold) > minPointLength ?
  659. // ...keep position
  660. yBottom - minPointLength :
  661. // #1485, #4051
  662. translatedThreshold -
  663. (up ? minPointLength : 0));
  664. }
  665. // Handle point.options.pointWidth
  666. // @todo Handle grouping/stacking too. Calculate offset properly
  667. if (defined(point.options.pointWidth)) {
  668. pointWidth = barW =
  669. Math.ceil(point.options.pointWidth);
  670. barX -= Math.round((pointWidth - seriesPointWidth) / 2);
  671. }
  672. // Adjust for null or missing points
  673. if (options.centerInCategory) {
  674. barX = series.adjustForMissingColumns(barX, pointWidth, point, metrics);
  675. }
  676. // Cache for access in polar
  677. point.barX = barX;
  678. point.pointWidth = pointWidth;
  679. // Fix the tooltip on center of grouped columns (#1216, #424,
  680. // #3648)
  681. point.tooltipPos = chart.inverted ?
  682. [
  683. yAxis.len + yAxis.pos - chart.plotLeft - plotY,
  684. xAxis.len + xAxis.pos - chart.plotTop - (plotX || 0) - seriesXOffset - barW / 2,
  685. barH
  686. ] :
  687. [barX + barW / 2, plotY + yAxis.pos -
  688. chart.plotTop, barH];
  689. // Register shape type and arguments to be used in drawPoints
  690. // Allow shapeType defined on pointClass level
  691. point.shapeType =
  692. series.pointClass.prototype.shapeType || 'rect';
  693. point.shapeArgs = series.crispCol.apply(series, point.isNull ?
  694. // #3169, drilldown from null must have a position to work
  695. // from #6585, dataLabel should be placed on xAxis, not
  696. // floating in the middle of the chart
  697. [barX, translatedThreshold, barW, 0] :
  698. [barX, barY, barW, barH]);
  699. });
  700. },
  701. getSymbol: noop,
  702. /**
  703. * Use a solid rectangle like the area series types
  704. *
  705. * @private
  706. * @function Highcharts.seriesTypes.column#drawLegendSymbol
  707. *
  708. * @param {Highcharts.Legend} legend
  709. * The legend object
  710. *
  711. * @param {Highcharts.Series|Highcharts.Point} item
  712. * The series (this) or point
  713. */
  714. drawLegendSymbol: LegendSymbolMixin.drawRectangle,
  715. /**
  716. * Columns have no graph
  717. *
  718. * @private
  719. * @function Highcharts.seriesTypes.column#drawGraph
  720. */
  721. drawGraph: function () {
  722. this.group[this.dense ? 'addClass' : 'removeClass']('highcharts-dense-data');
  723. },
  724. /**
  725. * Get presentational attributes
  726. *
  727. * @private
  728. * @function Highcharts.seriesTypes.column#pointAttribs
  729. *
  730. * @param {Highcharts.ColumnPoint} point
  731. *
  732. * @param {string} state
  733. *
  734. * @return {Highcharts.SVGAttributes}
  735. */
  736. pointAttribs: function (point, state) {
  737. var options = this.options, stateOptions, ret, p2o = this.pointAttrToOptions || {}, strokeOption = p2o.stroke || 'borderColor', strokeWidthOption = p2o['stroke-width'] || 'borderWidth', fill = (point && point.color) || this.color,
  738. // set to fill when borderColor null:
  739. stroke = ((point && point[strokeOption]) ||
  740. options[strokeOption] ||
  741. this.color ||
  742. fill), strokeWidth = (point && point[strokeWidthOption]) ||
  743. options[strokeWidthOption] ||
  744. this[strokeWidthOption] || 0, dashstyle = (point && point.options.dashStyle) || options.dashStyle, opacity = pick(point && point.opacity, options.opacity, 1), zone, brightness;
  745. // Handle zone colors
  746. if (point && this.zones.length) {
  747. zone = point.getZone();
  748. // When zones are present, don't use point.color (#4267).
  749. // Changed order (#6527), added support for colorAxis (#10670)
  750. fill = (point.options.color ||
  751. (zone && (zone.color || point.nonZonedColor)) ||
  752. this.color);
  753. if (zone) {
  754. stroke = zone.borderColor || stroke;
  755. dashstyle = zone.dashStyle || dashstyle;
  756. strokeWidth = zone.borderWidth || strokeWidth;
  757. }
  758. }
  759. // Select or hover states
  760. if (state && point) {
  761. stateOptions = merge(options.states[state],
  762. // #6401
  763. point.options.states &&
  764. point.options.states[state] ||
  765. {});
  766. brightness = stateOptions.brightness;
  767. fill =
  768. stateOptions.color || (typeof brightness !== 'undefined' &&
  769. color(fill)
  770. .brighten(stateOptions.brightness)
  771. .get()) || fill;
  772. stroke = stateOptions[strokeOption] || stroke;
  773. strokeWidth =
  774. stateOptions[strokeWidthOption] || strokeWidth;
  775. dashstyle = stateOptions.dashStyle || dashstyle;
  776. opacity = pick(stateOptions.opacity, opacity);
  777. }
  778. ret = {
  779. fill: fill,
  780. stroke: stroke,
  781. 'stroke-width': strokeWidth,
  782. opacity: opacity
  783. };
  784. if (dashstyle) {
  785. ret.dashstyle = dashstyle;
  786. }
  787. return ret;
  788. },
  789. /**
  790. * Draw the columns. For bars, the series.group is rotated, so the same
  791. * coordinates apply for columns and bars. This method is inherited by
  792. * scatter series.
  793. *
  794. * @private
  795. * @function Highcharts.seriesTypes.column#drawPoints
  796. */
  797. drawPoints: function () {
  798. var series = this, chart = this.chart, options = series.options, renderer = chart.renderer, animationLimit = options.animationLimit || 250, shapeArgs;
  799. // draw the columns
  800. series.points.forEach(function (point) {
  801. var plotY = point.plotY, graphic = point.graphic, hasGraphic = !!graphic, verb = graphic && chart.pointCount < animationLimit ?
  802. 'animate' : 'attr';
  803. if (isNumber(plotY) && point.y !== null) {
  804. shapeArgs = point.shapeArgs;
  805. // When updating a series between 2d and 3d or cartesian and
  806. // polar, the shape type changes.
  807. if (graphic && point.hasNewShapeType()) {
  808. graphic = graphic.destroy();
  809. }
  810. // Set starting position for point sliding animation.
  811. if (series.enabledDataSorting) {
  812. point.startXPos = series.xAxis.reversed ?
  813. -(shapeArgs ? shapeArgs.width : 0) :
  814. series.xAxis.width;
  815. }
  816. if (!graphic) {
  817. point.graphic = graphic =
  818. renderer[point.shapeType](shapeArgs)
  819. .add(point.group || series.group);
  820. if (graphic &&
  821. series.enabledDataSorting &&
  822. chart.hasRendered &&
  823. chart.pointCount < animationLimit) {
  824. graphic.attr({
  825. x: point.startXPos
  826. });
  827. hasGraphic = true;
  828. verb = 'animate';
  829. }
  830. }
  831. if (graphic && hasGraphic) { // update
  832. graphic[verb](merge(shapeArgs));
  833. }
  834. // Border radius is not stylable (#6900)
  835. if (options.borderRadius) {
  836. graphic[verb]({
  837. r: options.borderRadius
  838. });
  839. }
  840. // Presentational
  841. if (!chart.styledMode) {
  842. graphic[verb](series.pointAttribs(point, (point.selected && 'select')))
  843. .shadow(point.allowShadow !== false && options.shadow, null, options.stacking && !options.borderRadius);
  844. }
  845. graphic.addClass(point.getClassName(), true);
  846. }
  847. else if (graphic) {
  848. point.graphic = graphic.destroy(); // #1269
  849. }
  850. });
  851. },
  852. /**
  853. * Animate the column heights one by one from zero.
  854. *
  855. * @private
  856. * @function Highcharts.seriesTypes.column#animate
  857. *
  858. * @param {boolean} init
  859. * Whether to initialize the animation or run it
  860. */
  861. animate: function (init) {
  862. var series = this, yAxis = this.yAxis, options = series.options, inverted = this.chart.inverted, attr = {}, translateProp = inverted ? 'translateX' : 'translateY', translateStart, translatedThreshold;
  863. if (init) {
  864. attr.scaleY = 0.001;
  865. translatedThreshold = clamp(yAxis.toPixels(options.threshold), yAxis.pos, yAxis.pos + yAxis.len);
  866. if (inverted) {
  867. attr.translateX = translatedThreshold - yAxis.len;
  868. }
  869. else {
  870. attr.translateY = translatedThreshold;
  871. }
  872. // apply finnal clipping (used in Highstock) (#7083)
  873. // animation is done by scaleY, so cliping is for panes
  874. if (series.clipBox) {
  875. series.setClip();
  876. }
  877. series.group.attr(attr);
  878. }
  879. else { // run the animation
  880. translateStart = series.group.attr(translateProp);
  881. series.group.animate({ scaleY: 1 }, extend(animObject(series.options.animation), {
  882. // Do the scale synchronously to ensure smooth
  883. // updating (#5030, #7228)
  884. step: function (val, fx) {
  885. if (series.group) {
  886. attr[translateProp] = translateStart +
  887. fx.pos * (yAxis.pos - translateStart);
  888. series.group.attr(attr);
  889. }
  890. }
  891. }));
  892. }
  893. },
  894. /**
  895. * Remove this series from the chart
  896. *
  897. * @private
  898. * @function Highcharts.seriesTypes.column#remove
  899. */
  900. remove: function () {
  901. var series = this, chart = series.chart;
  902. // column and bar series affects other series of the same type
  903. // as they are either stacked or grouped
  904. if (chart.hasRendered) {
  905. chart.series.forEach(function (otherSeries) {
  906. if (otherSeries.type === series.type) {
  907. otherSeries.isDirty = true;
  908. }
  909. });
  910. }
  911. Series.prototype.remove.apply(series, arguments);
  912. }
  913. });
  914. /* eslint-enable valid-jsdoc */
  915. /**
  916. * A `column` series. If the [type](#series.column.type) option is
  917. * not specified, it is inherited from [chart.type](#chart.type).
  918. *
  919. * @extends series,plotOptions.column
  920. * @excluding connectNulls, dataParser, dataURL, gapSize, gapUnit, linecap,
  921. * lineWidth, marker, connectEnds, step
  922. * @product highcharts highstock
  923. * @apioption series.column
  924. */
  925. /**
  926. * An array of data points for the series. For the `column` series type,
  927. * points can be given in the following ways:
  928. *
  929. * 1. An array of numerical values. In this case, the numerical values will be
  930. * interpreted as `y` options. The `x` values will be automatically
  931. * calculated, either starting at 0 and incremented by 1, or from
  932. * `pointStart` and `pointInterval` given in the series options. If the axis
  933. * has categories, these will be used. Example:
  934. * ```js
  935. * data: [0, 5, 3, 5]
  936. * ```
  937. *
  938. * 2. An array of arrays with 2 values. In this case, the values correspond to
  939. * `x,y`. If the first value is a string, it is applied as the name of the
  940. * point, and the `x` value is inferred.
  941. * ```js
  942. * data: [
  943. * [0, 6],
  944. * [1, 2],
  945. * [2, 6]
  946. * ]
  947. * ```
  948. *
  949. * 3. An array of objects with named values. The following snippet shows only a
  950. * few settings, see the complete options set below. If the total number of
  951. * data points exceeds the series'
  952. * [turboThreshold](#series.column.turboThreshold), this option is not
  953. * available.
  954. * ```js
  955. * data: [{
  956. * x: 1,
  957. * y: 9,
  958. * name: "Point2",
  959. * color: "#00FF00"
  960. * }, {
  961. * x: 1,
  962. * y: 6,
  963. * name: "Point1",
  964. * color: "#FF00FF"
  965. * }]
  966. * ```
  967. *
  968. * @sample {highcharts} highcharts/chart/reflow-true/
  969. * Numerical values
  970. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  971. * Arrays of numeric x and y
  972. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  973. * Arrays of datetime x and y
  974. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  975. * Arrays of point.name and y
  976. * @sample {highcharts} highcharts/series/data-array-of-objects/
  977. * Config objects
  978. *
  979. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  980. * @extends series.line.data
  981. * @excluding marker
  982. * @product highcharts highstock
  983. * @apioption series.column.data
  984. */
  985. /**
  986. * The color of the border surrounding the column or bar.
  987. *
  988. * In styled mode, the border stroke can be set with the `.highcharts-point`
  989. * rule.
  990. *
  991. * @sample {highcharts} highcharts/plotoptions/column-bordercolor/
  992. * Dark gray border
  993. *
  994. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  995. * @product highcharts highstock
  996. * @apioption series.column.data.borderColor
  997. */
  998. /**
  999. * The width of the border surrounding the column or bar.
  1000. *
  1001. * In styled mode, the stroke width can be set with the `.highcharts-point`
  1002. * rule.
  1003. *
  1004. * @sample {highcharts} highcharts/plotoptions/column-borderwidth/
  1005. * 2px black border
  1006. *
  1007. * @type {number}
  1008. * @product highcharts highstock
  1009. * @apioption series.column.data.borderWidth
  1010. */
  1011. /**
  1012. * A name for the dash style to use for the column or bar. Overrides
  1013. * dashStyle on the series.
  1014. *
  1015. * In styled mode, the stroke dash-array can be set with the same classes as
  1016. * listed under [data.color](#series.column.data.color).
  1017. *
  1018. * @see [series.pointWidth](#plotOptions.column.dashStyle)
  1019. *
  1020. * @type {Highcharts.DashStyleValue}
  1021. * @apioption series.column.data.dashStyle
  1022. */
  1023. /**
  1024. * A pixel value specifying a fixed width for the column or bar. Overrides
  1025. * pointWidth on the series. The width effects the dimension that is not based
  1026. * on the point value.
  1027. *
  1028. * @see [series.pointWidth](#plotOptions.column.pointWidth)
  1029. *
  1030. * @type {number}
  1031. * @apioption series.column.data.pointWidth
  1032. */
  1033. /**
  1034. * @excluding halo, lineWidth, lineWidthPlus, marker
  1035. * @product highcharts highstock
  1036. * @apioption series.column.states.hover
  1037. */
  1038. /**
  1039. * @excluding halo, lineWidth, lineWidthPlus, marker
  1040. * @product highcharts highstock
  1041. * @apioption series.column.states.select
  1042. */
  1043. ''; // includes above doclets in transpilat