grid-axis.src.js 48 KB

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