grid-axis.src.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. /**
  2. * @license Highcharts Gantt JS v8.1.2 (2020-06-16)
  3. *
  4. * GridAxis
  5. *
  6. * (c) 2016-2019 Lars A. V. Cabrera
  7. *
  8. * License: www.highcharts.com/license
  9. */
  10. 'use strict';
  11. (function (factory) {
  12. if (typeof module === 'object' && module.exports) {
  13. factory['default'] = factory;
  14. module.exports = factory;
  15. } else if (typeof define === 'function' && define.amd) {
  16. define('highcharts/modules/grid-axis', ['highcharts'], function (Highcharts) {
  17. factory(Highcharts);
  18. factory.Highcharts = Highcharts;
  19. return factory;
  20. });
  21. } else {
  22. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  23. }
  24. }(function (Highcharts) {
  25. var _modules = Highcharts ? Highcharts._modules : {};
  26. function _registerModule(obj, path, args, fn) {
  27. if (!obj.hasOwnProperty(path)) {
  28. obj[path] = fn.apply(null, args);
  29. }
  30. }
  31. _registerModule(_modules, 'parts-gantt/GridAxis.js', [_modules['parts/Axis.js'], _modules['parts/Globals.js'], _modules['parts/Options.js'], _modules['parts/Tick.js'], _modules['parts/Utilities.js']], function (Axis, H, O, Tick, U) {
  32. /* *
  33. *
  34. * (c) 2016 Highsoft AS
  35. * Authors: Lars A. V. Cabrera
  36. *
  37. * License: www.highcharts.com/license
  38. *
  39. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40. *
  41. * */
  42. var dateFormat = O.dateFormat;
  43. var addEvent = U.addEvent, defined = U.defined, erase = U.erase, find = U.find, isArray = U.isArray, isNumber = U.isNumber, merge = U.merge, pick = U.pick, timeUnits = U.timeUnits, wrap = U.wrap;
  44. var argsToArray = function (args) {
  45. return Array.prototype.slice.call(args, 1);
  46. }, isObject = function (x) {
  47. // Always use strict mode
  48. return U.isObject(x, true);
  49. }, Chart = H.Chart;
  50. var applyGridOptions = function applyGridOptions(axis) {
  51. var options = axis.options;
  52. // Center-align by default
  53. if (!options.labels) {
  54. options.labels = {};
  55. }
  56. options.labels.align = pick(options.labels.align, 'center');
  57. // @todo: Check against tickLabelPlacement between/on etc
  58. /* Prevents adding the last tick label if the axis is not a category
  59. axis.
  60. Since numeric labels are normally placed at starts and ends of a
  61. range of value, and this module makes the label point at the value,
  62. an "extra" label would appear. */
  63. if (!axis.categories) {
  64. options.showLastLabel = false;
  65. }
  66. // Prevents rotation of labels when squished, as rotating them would not
  67. // help.
  68. axis.labelRotation = 0;
  69. options.labels.rotation = 0;
  70. };
  71. /**
  72. * Set grid options for the axis labels. Requires Highcharts Gantt.
  73. *
  74. * @since 6.2.0
  75. * @product gantt
  76. * @apioption xAxis.grid
  77. */
  78. /**
  79. * Enable grid on the axis labels. Defaults to true for Gantt charts.
  80. *
  81. * @type {boolean}
  82. * @default true
  83. * @since 6.2.0
  84. * @product gantt
  85. * @apioption xAxis.grid.enabled
  86. */
  87. /**
  88. * Set specific options for each column (or row for horizontal axes) in the
  89. * grid. Each extra column/row is its own axis, and the axis options can be set
  90. * here.
  91. *
  92. * @sample gantt/demo/left-axis-table
  93. * Left axis as a table
  94. *
  95. * @type {Array<Highcharts.XAxisOptions>}
  96. * @apioption xAxis.grid.columns
  97. */
  98. /**
  99. * Set border color for the label grid lines.
  100. *
  101. * @type {Highcharts.ColorString}
  102. * @apioption xAxis.grid.borderColor
  103. */
  104. /**
  105. * Set border width of the label grid lines.
  106. *
  107. * @type {number}
  108. * @default 1
  109. * @apioption xAxis.grid.borderWidth
  110. */
  111. /**
  112. * Set cell height for grid axis labels. By default this is calculated from font
  113. * size. This option only applies to horizontal axes.
  114. *
  115. * @sample gantt/grid-axis/cellheight
  116. * Gant chart with custom cell height
  117. * @type {number}
  118. * @apioption xAxis.grid.cellHeight
  119. */
  120. ''; // detach doclets above
  121. /**
  122. * Get the largest label width and height.
  123. *
  124. * @private
  125. * @function Highcharts.Axis#getMaxLabelDimensions
  126. *
  127. * @param {Highcharts.Dictionary<Highcharts.Tick>} ticks
  128. * All the ticks on one axis.
  129. *
  130. * @param {Array<number|string>} tickPositions
  131. * All the tick positions on one axis.
  132. *
  133. * @return {Highcharts.SizeObject}
  134. * Object containing the properties height and width.
  135. *
  136. * @todo Move this to the generic axis implementation, as it is used there.
  137. */
  138. Axis.prototype.getMaxLabelDimensions = function (ticks, tickPositions) {
  139. var dimensions = {
  140. width: 0,
  141. height: 0
  142. };
  143. tickPositions.forEach(function (pos) {
  144. var tick = ticks[pos], tickHeight = 0, tickWidth = 0, label;
  145. if (isObject(tick)) {
  146. label = isObject(tick.label) ? tick.label : {};
  147. // Find width and height of tick
  148. tickHeight = label.getBBox ? label.getBBox().height : 0;
  149. if (label.textStr && !isNumber(label.textPxLength)) {
  150. label.textPxLength = label.getBBox().width;
  151. }
  152. tickWidth = isNumber(label.textPxLength) ?
  153. // Math.round ensures crisp lines
  154. Math.round(label.textPxLength) :
  155. 0;
  156. // Update the result if width and/or height are larger
  157. dimensions.height = Math.max(tickHeight, dimensions.height);
  158. dimensions.width = Math.max(tickWidth, dimensions.width);
  159. }
  160. });
  161. return dimensions;
  162. };
  163. // Adds week date format
  164. H.dateFormats.W = function (timestamp) {
  165. var d = new this.Date(timestamp);
  166. var firstDay = (this.get('Day', d) + 6) % 7;
  167. var thursday = new this.Date(d.valueOf());
  168. this.set('Date', thursday, this.get('Date', d) - firstDay + 3);
  169. var firstThursday = new this.Date(this.get('FullYear', thursday), 0, 1);
  170. if (this.get('Day', firstThursday) !== 4) {
  171. this.set('Month', d, 0);
  172. this.set('Date', d, 1 + (11 - this.get('Day', firstThursday)) % 7);
  173. }
  174. return (1 +
  175. Math.floor((thursday.valueOf() - firstThursday.valueOf()) / 604800000)).toString();
  176. };
  177. // First letter of the day of the week, e.g. 'M' for 'Monday'.
  178. H.dateFormats.E = function (timestamp) {
  179. return dateFormat('%a', timestamp, true).charAt(0);
  180. };
  181. /* eslint-disable no-invalid-this */
  182. addEvent(Chart, 'afterSetChartSize', function () {
  183. this.axes.forEach(function (axis) {
  184. (axis.grid && axis.grid.columns || []).forEach(function (column) {
  185. column.setAxisSize();
  186. column.setAxisTranslation();
  187. });
  188. });
  189. });
  190. // Center tick labels in cells.
  191. addEvent(Tick, 'afterGetLabelPosition', function (e) {
  192. var tick = this, label = tick.label, axis = tick.axis, reversed = axis.reversed, chart = axis.chart, options = axis.options, gridOptions = options.grid || {}, labelOpts = axis.options.labels, align = labelOpts.align,
  193. // verticalAlign is currently not supported for axis.labels.
  194. verticalAlign = 'middle', // labelOpts.verticalAlign,
  195. side = GridAxis.Side[axis.side], tickmarkOffset = e.tickmarkOffset, tickPositions = axis.tickPositions, tickPos = tick.pos - tickmarkOffset, nextTickPos = (isNumber(tickPositions[e.index + 1]) ?
  196. tickPositions[e.index + 1] - tickmarkOffset :
  197. axis.max + tickmarkOffset), tickSize = axis.tickSize('tick'), tickWidth = tickSize ? tickSize[0] : 0, crispCorr = tickSize ? tickSize[1] / 2 : 0, labelHeight, lblMetrics, lines, bottom, top, left, right;
  198. // Only center tick labels in grid axes
  199. if (gridOptions.enabled === true) {
  200. // Calculate top and bottom positions of the cell.
  201. if (side === 'top') {
  202. bottom = axis.top + axis.offset;
  203. top = bottom - tickWidth;
  204. }
  205. else if (side === 'bottom') {
  206. top = chart.chartHeight - axis.bottom + axis.offset;
  207. bottom = top + tickWidth;
  208. }
  209. else {
  210. bottom = axis.top + axis.len - axis.translate(reversed ? nextTickPos : tickPos);
  211. top = axis.top + axis.len - axis.translate(reversed ? tickPos : nextTickPos);
  212. }
  213. // Calculate left and right positions of the cell.
  214. if (side === 'right') {
  215. left = chart.chartWidth - axis.right + axis.offset;
  216. right = left + tickWidth;
  217. }
  218. else if (side === 'left') {
  219. right = axis.left + axis.offset;
  220. left = right - tickWidth;
  221. }
  222. else {
  223. left = Math.round(axis.left + axis.translate(reversed ? nextTickPos : tickPos)) - crispCorr;
  224. right = Math.round(axis.left + axis.translate(reversed ? tickPos : nextTickPos)) - crispCorr;
  225. }
  226. tick.slotWidth = right - left;
  227. // Calculate the positioning of the label based on
  228. // alignment.
  229. e.pos.x = (align === 'left' ?
  230. left :
  231. align === 'right' ?
  232. right :
  233. left + ((right - left) / 2) // default to center
  234. );
  235. e.pos.y = (verticalAlign === 'top' ?
  236. top :
  237. verticalAlign === 'bottom' ?
  238. bottom :
  239. top + ((bottom - top) / 2) // default to middle
  240. );
  241. lblMetrics = chart.renderer.fontMetrics(labelOpts.style.fontSize, label.element);
  242. labelHeight = label.getBBox().height;
  243. // Adjustment to y position to align the label correctly.
  244. // Would be better to have a setter or similar for this.
  245. if (!labelOpts.useHTML) {
  246. lines = Math.round(labelHeight / lblMetrics.h);
  247. e.pos.y += (
  248. // Center the label
  249. // TODO: why does this actually center the label?
  250. ((lblMetrics.b - (lblMetrics.h - lblMetrics.f)) / 2) +
  251. // Adjust for height of additional lines.
  252. -(((lines - 1) * lblMetrics.h) / 2));
  253. }
  254. else {
  255. e.pos.y += (
  256. // Readjust yCorr in htmlUpdateTransform
  257. lblMetrics.b +
  258. // Adjust for height of html label
  259. -(labelHeight / 2));
  260. }
  261. e.pos.x += (axis.horiz && labelOpts.x || 0);
  262. }
  263. });
  264. /* eslint-enable no-invalid-this */
  265. /**
  266. * Additions for grid axes.
  267. * @private
  268. * @class
  269. */
  270. var GridAxisAdditions = /** @class */ (function () {
  271. /* *
  272. *
  273. * Constructors
  274. *
  275. * */
  276. function GridAxisAdditions(axis) {
  277. this.axis = axis;
  278. }
  279. /* *
  280. *
  281. * Functions
  282. *
  283. * */
  284. /**
  285. * Checks if an axis is the outer axis in its dimension. Since
  286. * axes are placed outwards in order, the axis with the highest
  287. * index is the outermost axis.
  288. *
  289. * Example: If there are multiple x-axes at the top of the chart,
  290. * this function returns true if the axis supplied is the last
  291. * of the x-axes.
  292. *
  293. * @private
  294. *
  295. * @return {boolean}
  296. * True if the axis is the outermost axis in its dimension; false if
  297. * not.
  298. */
  299. GridAxisAdditions.prototype.isOuterAxis = function () {
  300. var axis = this.axis;
  301. var chart = axis.chart;
  302. var columnIndex = axis.grid.columnIndex;
  303. var columns = (axis.linkedParent && axis.linkedParent.grid.columns ||
  304. axis.grid.columns);
  305. var parentAxis = columnIndex ? axis.linkedParent : axis;
  306. var thisIndex = -1, lastIndex = 0;
  307. chart[axis.coll].forEach(function (otherAxis, index) {
  308. if (otherAxis.side === axis.side && !otherAxis.options.isInternal) {
  309. lastIndex = index;
  310. if (otherAxis === parentAxis) {
  311. // Get the index of the axis in question
  312. thisIndex = index;
  313. }
  314. }
  315. });
  316. return (lastIndex === thisIndex &&
  317. (isNumber(columnIndex) ? columns.length === columnIndex : true));
  318. };
  319. return GridAxisAdditions;
  320. }());
  321. /**
  322. * Axis with grid support.
  323. * @private
  324. * @class
  325. */
  326. var GridAxis = /** @class */ (function () {
  327. function GridAxis() {
  328. }
  329. /* *
  330. *
  331. * Static Functions
  332. *
  333. * */
  334. /* eslint-disable valid-jsdoc */
  335. /**
  336. * Extends axis class with grid support.
  337. * @private
  338. */
  339. GridAxis.compose = function (AxisClass) {
  340. Axis.keepProps.push('grid');
  341. wrap(AxisClass.prototype, 'unsquish', GridAxis.wrapUnsquish);
  342. // Add event handlers
  343. addEvent(AxisClass, 'init', GridAxis.onInit);
  344. addEvent(AxisClass, 'afterGetOffset', GridAxis.onAfterGetOffset);
  345. addEvent(AxisClass, 'afterGetTitlePosition', GridAxis.onAfterGetTitlePosition);
  346. addEvent(AxisClass, 'afterInit', GridAxis.onAfterInit);
  347. addEvent(AxisClass, 'afterRender', GridAxis.onAfterRender);
  348. addEvent(AxisClass, 'afterSetAxisTranslation', GridAxis.onAfterSetAxisTranslation);
  349. addEvent(AxisClass, 'afterSetOptions', GridAxis.onAfterSetOptions);
  350. addEvent(AxisClass, 'afterSetOptions', GridAxis.onAfterSetOptions2);
  351. addEvent(AxisClass, 'afterSetScale', GridAxis.onAfterSetScale);
  352. addEvent(AxisClass, 'afterTickSize', GridAxis.onAfterTickSize);
  353. addEvent(AxisClass, 'trimTicks', GridAxis.onTrimTicks);
  354. addEvent(AxisClass, 'destroy', GridAxis.onDestroy);
  355. };
  356. /**
  357. * Handle columns and getOffset.
  358. * @private
  359. */
  360. GridAxis.onAfterGetOffset = function () {
  361. var grid = this.grid;
  362. (grid && grid.columns || []).forEach(function (column) {
  363. column.getOffset();
  364. });
  365. };
  366. /**
  367. * @private
  368. */
  369. GridAxis.onAfterGetTitlePosition = function (e) {
  370. var axis = this;
  371. var options = axis.options;
  372. var gridOptions = options.grid || {};
  373. if (gridOptions.enabled === true) {
  374. // compute anchor points for each of the title align options
  375. var title = axis.axisTitle, axisHeight = axis.height, horiz = axis.horiz, axisLeft = axis.left, offset = axis.offset, opposite = axis.opposite, _a = axis.options.title, axisTitleOptions = _a === void 0 ? {} : _a, axisTop = axis.top, axisWidth = axis.width;
  376. var tickSize = axis.tickSize();
  377. var titleWidth = title && title.getBBox().width;
  378. var xOption = axisTitleOptions.x || 0;
  379. var yOption = axisTitleOptions.y || 0;
  380. var titleMargin = pick(axisTitleOptions.margin, horiz ? 5 : 10);
  381. var titleFontSize = axis.chart.renderer.fontMetrics(axisTitleOptions.style &&
  382. axisTitleOptions.style.fontSize, title).f;
  383. var crispCorr = tickSize ? tickSize[0] / 2 : 0;
  384. // TODO account for alignment
  385. // the position in the perpendicular direction of the axis
  386. var offAxis = ((horiz ? axisTop + axisHeight : axisLeft) +
  387. (horiz ? 1 : -1) * // horizontal axis reverses the margin
  388. (opposite ? -1 : 1) * // so does opposite axes
  389. crispCorr +
  390. (axis.side === GridAxis.Side.bottom ? titleFontSize : 0));
  391. e.titlePosition.x = horiz ?
  392. axisLeft - titleWidth / 2 - titleMargin + xOption :
  393. offAxis + (opposite ? axisWidth : 0) + offset + xOption;
  394. e.titlePosition.y = horiz ?
  395. (offAxis -
  396. (opposite ? axisHeight : 0) +
  397. (opposite ? titleFontSize : -titleFontSize) / 2 +
  398. offset +
  399. yOption) :
  400. axisTop - titleMargin + yOption;
  401. }
  402. };
  403. /**
  404. * @private
  405. */
  406. GridAxis.onAfterInit = function () {
  407. var axis = this;
  408. var chart = axis.chart, _a = axis.options.grid, gridOptions = _a === void 0 ? {} : _a, userOptions = axis.userOptions;
  409. if (gridOptions.enabled) {
  410. applyGridOptions(axis);
  411. /* eslint-disable no-invalid-this */
  412. // TODO: wrap the axis instead
  413. wrap(axis, 'labelFormatter', function (proceed) {
  414. var _a = this, axis = _a.axis, value = _a.value;
  415. var tickPos = axis.tickPositions;
  416. var series = (axis.isLinked ?
  417. axis.linkedParent :
  418. axis).series[0];
  419. var isFirst = value === tickPos[0];
  420. var isLast = value === tickPos[tickPos.length - 1];
  421. var point = series && find(series.options.data, function (p) {
  422. return p[axis.isXAxis ? 'x' : 'y'] === value;
  423. });
  424. // Make additional properties available for the
  425. // formatter
  426. this.isFirst = isFirst;
  427. this.isLast = isLast;
  428. this.point = point;
  429. // Call original labelFormatter
  430. return proceed.call(this);
  431. });
  432. /* eslint-enable no-invalid-this */
  433. }
  434. if (gridOptions.columns) {
  435. var columns = axis.grid.columns = [], columnIndex = axis.grid.columnIndex = 0;
  436. // Handle columns, each column is a grid axis
  437. while (++columnIndex < gridOptions.columns.length) {
  438. var columnOptions = merge(userOptions, gridOptions.columns[gridOptions.columns.length - columnIndex - 1], {
  439. linkedTo: 0,
  440. // Force to behave like category axis
  441. type: 'category'
  442. });
  443. delete columnOptions.grid.columns; // Prevent recursion
  444. var column = new Axis(axis.chart, columnOptions);
  445. column.grid.isColumn = true;
  446. column.grid.columnIndex = columnIndex;
  447. // Remove column axis from chart axes array, and place it
  448. // in the columns array.
  449. erase(chart.axes, column);
  450. erase(chart[axis.coll], column);
  451. columns.push(column);
  452. }
  453. }
  454. };
  455. /**
  456. * Draw an extra line on the far side of the outermost axis,
  457. * creating floor/roof/wall of a grid. And some padding.
  458. * ```
  459. * Make this:
  460. * (axis.min) __________________________ (axis.max)
  461. * | | | | |
  462. * Into this:
  463. * (axis.min) __________________________ (axis.max)
  464. * ___|____|____|____|____|__
  465. * ```
  466. * @private
  467. */
  468. GridAxis.onAfterRender = function () {
  469. var axis = this;
  470. var grid = axis.grid;
  471. var options = axis.options;
  472. var renderer = axis.chart.renderer;
  473. var gridOptions = options.grid || {};
  474. var yStartIndex, yEndIndex, xStartIndex, xEndIndex;
  475. if (gridOptions.enabled === true) {
  476. // @todo acutual label padding (top, bottom, left, right)
  477. axis.maxLabelDimensions = axis.getMaxLabelDimensions(axis.ticks, axis.tickPositions);
  478. // Remove right wall before rendering if updating
  479. if (axis.rightWall) {
  480. axis.rightWall.destroy();
  481. }
  482. /*
  483. Draw an extra axis line on outer axes
  484. >
  485. Make this: |______|______|______|___
  486. > _________________________
  487. Into this: |______|______|______|__|
  488. */
  489. if (axis.grid && axis.grid.isOuterAxis() && axis.axisLine) {
  490. var lineWidth = options.lineWidth;
  491. if (lineWidth) {
  492. var linePath = axis.getLinePath(lineWidth);
  493. var startPoint = linePath[0];
  494. var endPoint = linePath[1];
  495. // Negate distance if top or left axis
  496. // Subtract 1px to draw the line at the end of the tick
  497. var tickLength = (axis.tickSize('tick') || [1])[0];
  498. var distance = (tickLength - 1) * ((axis.side === GridAxis.Side.top ||
  499. axis.side === GridAxis.Side.left) ? -1 : 1);
  500. // If axis is horizontal, reposition line path vertically
  501. if (startPoint[0] === 'M' && endPoint[0] === 'L') {
  502. if (axis.horiz) {
  503. startPoint[2] += distance;
  504. endPoint[2] += distance;
  505. }
  506. else {
  507. // If axis is vertical, reposition line path
  508. // horizontally
  509. startPoint[1] += distance;
  510. endPoint[1] += distance;
  511. }
  512. }
  513. if (!axis.grid.axisLineExtra) {
  514. axis.grid.axisLineExtra = renderer
  515. .path(linePath)
  516. .attr({
  517. zIndex: 7
  518. })
  519. .addClass('highcharts-axis-line')
  520. .add(axis.axisGroup);
  521. if (!renderer.styledMode) {
  522. axis.grid.axisLineExtra.attr({
  523. stroke: options.lineColor,
  524. 'stroke-width': lineWidth
  525. });
  526. }
  527. }
  528. else {
  529. axis.grid.axisLineExtra.animate({
  530. d: linePath
  531. });
  532. }
  533. // show or hide the line depending on
  534. // options.showEmpty
  535. axis.axisLine[axis.showAxis ? 'show' : 'hide'](true);
  536. }
  537. }
  538. (grid && grid.columns || []).forEach(function (column) {
  539. column.render();
  540. });
  541. }
  542. };
  543. /**
  544. * @private
  545. */
  546. GridAxis.onAfterSetAxisTranslation = function () {
  547. var axis = this;
  548. var tickInfo = axis.tickPositions && axis.tickPositions.info;
  549. var options = axis.options;
  550. var gridOptions = options.grid || {};
  551. var userLabels = axis.userOptions.labels || {};
  552. if (axis.horiz) {
  553. if (gridOptions.enabled === true) {
  554. axis.series.forEach(function (series) {
  555. series.options.pointRange = 0;
  556. });
  557. }
  558. // Lower level time ticks, like hours or minutes, represent
  559. // points in time and not ranges. These should be aligned
  560. // left in the grid cell by default. The same applies to
  561. // years of higher order.
  562. if (tickInfo &&
  563. options.dateTimeLabelFormats &&
  564. options.labels &&
  565. !defined(userLabels.align) &&
  566. (options.dateTimeLabelFormats[tickInfo.unitName].range === false ||
  567. tickInfo.count > 1 // years
  568. )) {
  569. options.labels.align = 'left';
  570. if (!defined(userLabels.x)) {
  571. options.labels.x = 3;
  572. }
  573. }
  574. }
  575. };
  576. /**
  577. * Creates a left and right wall on horizontal axes:
  578. * - Places leftmost tick at the start of the axis, to create a left
  579. * wall
  580. * - Ensures that the rightmost tick is at the end of the axis, to
  581. * create a right wall.
  582. * @private
  583. */
  584. GridAxis.onAfterSetOptions = function (e) {
  585. var options = this.options, userOptions = e.userOptions, gridAxisOptions, gridOptions = ((options && isObject(options.grid)) ? options.grid : {});
  586. if (gridOptions.enabled === true) {
  587. // Merge the user options into default grid axis options so
  588. // that when a user option is set, it takes presedence.
  589. gridAxisOptions = merge(true, {
  590. className: ('highcharts-grid-axis ' + (userOptions.className || '')),
  591. dateTimeLabelFormats: {
  592. hour: {
  593. list: ['%H:%M', '%H']
  594. },
  595. day: {
  596. list: ['%A, %e. %B', '%a, %e. %b', '%E']
  597. },
  598. week: {
  599. list: ['Week %W', 'W%W']
  600. },
  601. month: {
  602. list: ['%B', '%b', '%o']
  603. }
  604. },
  605. grid: {
  606. borderWidth: 1
  607. },
  608. labels: {
  609. padding: 2,
  610. style: {
  611. fontSize: '13px'
  612. }
  613. },
  614. margin: 0,
  615. title: {
  616. text: null,
  617. reserveSpace: false,
  618. rotation: 0
  619. },
  620. // In a grid axis, only allow one unit of certain types,
  621. // for example we shouln't have one grid cell spanning
  622. // two days.
  623. units: [[
  624. 'millisecond',
  625. [1, 10, 100]
  626. ], [
  627. 'second',
  628. [1, 10]
  629. ], [
  630. 'minute',
  631. [1, 5, 15]
  632. ], [
  633. 'hour',
  634. [1, 6]
  635. ], [
  636. 'day',
  637. [1]
  638. ], [
  639. 'week',
  640. [1]
  641. ], [
  642. 'month',
  643. [1]
  644. ], [
  645. 'year',
  646. null
  647. ]]
  648. }, userOptions);
  649. // X-axis specific options
  650. if (this.coll === 'xAxis') {
  651. // For linked axes, tickPixelInterval is used only if
  652. // the tickPositioner below doesn't run or returns
  653. // undefined (like multiple years)
  654. if (defined(userOptions.linkedTo) &&
  655. !defined(userOptions.tickPixelInterval)) {
  656. gridAxisOptions.tickPixelInterval = 350;
  657. }
  658. // For the secondary grid axis, use the primary axis'
  659. // tick intervals and return ticks one level higher.
  660. if (
  661. // Check for tick pixel interval in options
  662. !defined(userOptions.tickPixelInterval) &&
  663. // Only for linked axes
  664. defined(userOptions.linkedTo) &&
  665. !defined(userOptions.tickPositioner) &&
  666. !defined(userOptions.tickInterval)) {
  667. gridAxisOptions.tickPositioner = function (min, max) {
  668. var parentInfo = (this.linkedParent &&
  669. this.linkedParent.tickPositions &&
  670. this.linkedParent.tickPositions.info);
  671. if (parentInfo) {
  672. var unitIdx, count, unitName, i, units = gridAxisOptions.units, unitRange;
  673. for (i = 0; i < units.length; i++) {
  674. if (units[i][0] ===
  675. parentInfo.unitName) {
  676. unitIdx = i;
  677. break;
  678. }
  679. }
  680. // Get the first allowed count on the next
  681. // unit.
  682. if (units[unitIdx + 1]) {
  683. unitName = units[unitIdx + 1][0];
  684. count =
  685. (units[unitIdx + 1][1] || [1])[0];
  686. // In case the base X axis shows years, make
  687. // the secondary axis show ten times the
  688. // years (#11427)
  689. }
  690. else if (parentInfo.unitName === 'year') {
  691. unitName = 'year';
  692. count = parentInfo.count * 10;
  693. }
  694. unitRange = timeUnits[unitName];
  695. this.tickInterval = unitRange * count;
  696. return this.getTimeTicks({
  697. unitRange: unitRange,
  698. count: count,
  699. unitName: unitName
  700. }, min, max, this.options.startOfWeek);
  701. }
  702. };
  703. }
  704. }
  705. // Now merge the combined options into the axis options
  706. merge(true, this.options, gridAxisOptions);
  707. if (this.horiz) {
  708. /* _________________________
  709. Make this: ___|_____|_____|_____|__|
  710. ^ ^
  711. _________________________
  712. Into this: |_____|_____|_____|_____|
  713. ^ ^ */
  714. options.minPadding = pick(userOptions.minPadding, 0);
  715. options.maxPadding = pick(userOptions.maxPadding, 0);
  716. }
  717. // If borderWidth is set, then use its value for tick and
  718. // line width.
  719. if (isNumber(options.grid.borderWidth)) {
  720. options.tickWidth = options.lineWidth = gridOptions.borderWidth;
  721. }
  722. }
  723. };
  724. /**
  725. * @private
  726. */
  727. GridAxis.onAfterSetOptions2 = function (e) {
  728. var axis = this;
  729. var userOptions = e.userOptions;
  730. var gridOptions = userOptions && userOptions.grid || {};
  731. var columns = gridOptions.columns;
  732. // Add column options to the parent axis. Children has their column
  733. // options set on init in onGridAxisAfterInit.
  734. if (gridOptions.enabled && columns) {
  735. merge(true, axis.options, columns[columns.length - 1]);
  736. }
  737. };
  738. /**
  739. * Handle columns and setScale.
  740. * @private
  741. */
  742. GridAxis.onAfterSetScale = function () {
  743. var axis = this;
  744. (axis.grid.columns || []).forEach(function (column) {
  745. column.setScale();
  746. });
  747. };
  748. /**
  749. * Draw vertical axis ticks extra long to create cell floors and roofs.
  750. * Overrides the tickLength for vertical axes.
  751. * @private
  752. */
  753. GridAxis.onAfterTickSize = function (e) {
  754. var defaultLeftAxisOptions = Axis.defaultLeftAxisOptions;
  755. var _a = this, horiz = _a.horiz, maxLabelDimensions = _a.maxLabelDimensions, _b = _a.options.grid, gridOptions = _b === void 0 ? {} : _b;
  756. if (gridOptions.enabled && maxLabelDimensions) {
  757. var labelPadding = (Math.abs(defaultLeftAxisOptions.labels.x) * 2);
  758. var distance = horiz ?
  759. gridOptions.cellHeight || labelPadding + maxLabelDimensions.height :
  760. labelPadding + maxLabelDimensions.width;
  761. if (isArray(e.tickSize)) {
  762. e.tickSize[0] = distance;
  763. }
  764. else {
  765. e.tickSize = [distance, 0];
  766. }
  767. }
  768. };
  769. /**
  770. * @private
  771. */
  772. GridAxis.onDestroy = function (e) {
  773. var grid = this.grid;
  774. (grid.columns || []).forEach(function (column) {
  775. column.destroy(e.keepEvents);
  776. });
  777. grid.columns = void 0;
  778. };
  779. /**
  780. * Wraps axis init to draw cell walls on vertical axes.
  781. * @private
  782. */
  783. GridAxis.onInit = function (e) {
  784. var axis = this;
  785. var userOptions = e.userOptions || {};
  786. var gridOptions = userOptions.grid || {};
  787. if (gridOptions.enabled && defined(gridOptions.borderColor)) {
  788. userOptions.tickColor = userOptions.lineColor = gridOptions.borderColor;
  789. }
  790. if (!axis.grid) {
  791. axis.grid = new GridAxisAdditions(axis);
  792. }
  793. };
  794. /**
  795. * Makes tick labels which are usually ignored in a linked axis
  796. * displayed if they are within range of linkedParent.min.
  797. * ```
  798. * _____________________________
  799. * | | | | |
  800. * Make this: | | 2 | 3 | 4 |
  801. * |___|_______|_______|_______|
  802. * ^
  803. * _____________________________
  804. * | | | | |
  805. * Into this: | 1 | 2 | 3 | 4 |
  806. * |___|_______|_______|_______|
  807. * ^
  808. * ```
  809. * @private
  810. * @todo Does this function do what the drawing says? Seems to affect
  811. * ticks and not the labels directly?
  812. */
  813. GridAxis.onTrimTicks = function () {
  814. var axis = this;
  815. var options = axis.options;
  816. var gridOptions = options.grid || {};
  817. var categoryAxis = axis.categories;
  818. var tickPositions = axis.tickPositions;
  819. var firstPos = tickPositions[0];
  820. var lastPos = tickPositions[tickPositions.length - 1];
  821. var linkedMin = axis.linkedParent && axis.linkedParent.min;
  822. var linkedMax = axis.linkedParent && axis.linkedParent.max;
  823. var min = linkedMin || axis.min;
  824. var max = linkedMax || axis.max;
  825. var tickInterval = axis.tickInterval;
  826. var endMoreThanMin = (firstPos < min &&
  827. firstPos + tickInterval > min);
  828. var startLessThanMax = (lastPos > max &&
  829. lastPos - tickInterval < max);
  830. if (gridOptions.enabled === true &&
  831. !categoryAxis &&
  832. (axis.horiz || axis.isLinked)) {
  833. if (endMoreThanMin && !options.startOnTick) {
  834. tickPositions[0] = min;
  835. }
  836. if (startLessThanMax && !options.endOnTick) {
  837. tickPositions[tickPositions.length - 1] = max;
  838. }
  839. }
  840. };
  841. /**
  842. * Avoid altering tickInterval when reserving space.
  843. * @private
  844. */
  845. GridAxis.wrapUnsquish = function (proceed) {
  846. var axis = this;
  847. var _a = axis.options.grid, gridOptions = _a === void 0 ? {} : _a;
  848. if (gridOptions.enabled === true && axis.categories) {
  849. return axis.tickInterval;
  850. }
  851. return proceed.apply(axis, argsToArray(arguments));
  852. };
  853. return GridAxis;
  854. }());
  855. (function (GridAxis) {
  856. /**
  857. * Enum for which side the axis is on. Maps to axis.side.
  858. * @private
  859. */
  860. var Side;
  861. (function (Side) {
  862. Side[Side["top"] = 0] = "top";
  863. Side[Side["right"] = 1] = "right";
  864. Side[Side["bottom"] = 2] = "bottom";
  865. Side[Side["left"] = 3] = "left";
  866. })(Side = GridAxis.Side || (GridAxis.Side = {}));
  867. })(GridAxis || (GridAxis = {}));
  868. GridAxis.compose(Axis);
  869. return GridAxis;
  870. });
  871. _registerModule(_modules, 'masters/modules/grid-axis.src.js', [], function () {
  872. });
  873. }));