ColumnSeries.js 39 KB

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