treegrid.src.js 142 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238
  1. /**
  2. * @license Highcharts Gantt JS v9.1.1 (2021-06-04)
  3. *
  4. * Tree Grid
  5. *
  6. * (c) 2016-2021 Jon Arild Nygard
  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/treegrid', ['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/BrokenAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Series/Series.js'], _modules['Extensions/Stacking.js'], _modules['Core/Utilities.js']], function (Axis, Series, StackItem, U) {
  32. /* *
  33. *
  34. * (c) 2009-2021 Torstein Honsi
  35. *
  36. * License: www.highcharts.com/license
  37. *
  38. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  39. *
  40. * */
  41. var addEvent = U.addEvent,
  42. find = U.find,
  43. fireEvent = U.fireEvent,
  44. isArray = U.isArray,
  45. isNumber = U.isNumber,
  46. pick = U.pick;
  47. /**
  48. * Axis with support of broken data rows.
  49. * @private
  50. * @class
  51. */
  52. var BrokenAxis;
  53. (function (BrokenAxis) {
  54. /* *
  55. *
  56. * Functions
  57. *
  58. * */
  59. /* eslint-disable valid-jsdoc */
  60. /**
  61. * Adds support for broken axes.
  62. * @private
  63. */
  64. function compose(AxisClass, SeriesClass) {
  65. if (AxisClass.keepProps.indexOf('brokenAxis') === -1) {
  66. AxisClass.keepProps.push('brokenAxis');
  67. var seriesProto = Series.prototype;
  68. seriesProto.drawBreaks = seriesDrawBreaks;
  69. seriesProto.gappedPath = seriesGappedPath;
  70. addEvent(AxisClass, 'init', onInit);
  71. addEvent(AxisClass, 'afterInit', onAfterInit);
  72. addEvent(AxisClass, 'afterSetTickPositions', onAfterSetTickPositions);
  73. addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions);
  74. addEvent(SeriesClass, 'afterGeneratePoints', onSeriesAfterGeneratePoints);
  75. addEvent(SeriesClass, 'afterRender', onSeriesAfterRender);
  76. }
  77. return AxisClass;
  78. }
  79. BrokenAxis.compose = compose;
  80. /**
  81. * @private
  82. */
  83. function onAfterInit() {
  84. if (typeof this.brokenAxis !== 'undefined') {
  85. this.brokenAxis.setBreaks(this.options.breaks, false);
  86. }
  87. }
  88. /**
  89. * Force Axis to be not-ordinal when breaks are defined.
  90. * @private
  91. */
  92. function onAfterSetOptions() {
  93. var axis = this;
  94. if (axis.brokenAxis && axis.brokenAxis.hasBreaks) {
  95. axis.options.ordinal = false;
  96. }
  97. }
  98. /**
  99. * @private
  100. */
  101. function onAfterSetTickPositions() {
  102. var axis = this,
  103. brokenAxis = axis.brokenAxis;
  104. if (brokenAxis &&
  105. brokenAxis.hasBreaks) {
  106. var tickPositions = axis.tickPositions,
  107. info = axis.tickPositions.info,
  108. newPositions = [];
  109. for (var i = 0; i < tickPositions.length; i++) {
  110. if (!brokenAxis.isInAnyBreak(tickPositions[i])) {
  111. newPositions.push(tickPositions[i]);
  112. }
  113. }
  114. axis.tickPositions = newPositions;
  115. axis.tickPositions.info = info;
  116. }
  117. }
  118. /**
  119. * @private
  120. */
  121. function onInit() {
  122. var axis = this;
  123. if (!axis.brokenAxis) {
  124. axis.brokenAxis = new Additions(axis);
  125. }
  126. }
  127. /**
  128. * @private
  129. */
  130. function onSeriesAfterGeneratePoints() {
  131. var _a = this,
  132. isDirty = _a.isDirty,
  133. connectNulls = _a.options.connectNulls,
  134. points = _a.points,
  135. xAxis = _a.xAxis,
  136. yAxis = _a.yAxis;
  137. // Set, or reset visibility of the points. Axis.setBreaks marks
  138. // the series as isDirty
  139. if (isDirty) {
  140. var i = points.length;
  141. while (i--) {
  142. var point = points[i];
  143. // Respect nulls inside the break (#4275)
  144. var nullGap = point.y === null && connectNulls === false;
  145. var isPointInBreak = (!nullGap && ((xAxis &&
  146. xAxis.brokenAxis &&
  147. xAxis.brokenAxis.isInAnyBreak(point.x,
  148. true)) || (yAxis &&
  149. yAxis.brokenAxis &&
  150. yAxis.brokenAxis.isInAnyBreak(point.y,
  151. true))));
  152. // Set point.visible if in any break.
  153. // If not in break, reset visible to original value.
  154. point.visible = isPointInBreak ?
  155. false :
  156. point.options.visible !== false;
  157. }
  158. }
  159. }
  160. /**
  161. * @private
  162. */
  163. function onSeriesAfterRender() {
  164. this.drawBreaks(this.xAxis, ['x']);
  165. this.drawBreaks(this.yAxis, pick(this.pointArrayMap, ['y']));
  166. }
  167. /**
  168. * @private
  169. */
  170. function seriesDrawBreaks(axis, keys) {
  171. var series = this,
  172. points = series.points;
  173. var breaks,
  174. threshold,
  175. eventName,
  176. y;
  177. if (axis && // #5950
  178. axis.brokenAxis &&
  179. axis.brokenAxis.hasBreaks) {
  180. var brokenAxis_1 = axis.brokenAxis;
  181. keys.forEach(function (key) {
  182. breaks = brokenAxis_1 && brokenAxis_1.breakArray || [];
  183. threshold = axis.isXAxis ?
  184. axis.min :
  185. pick(series.options.threshold, axis.min);
  186. points.forEach(function (point) {
  187. y = pick(point['stack' + key.toUpperCase()], point[key]);
  188. breaks.forEach(function (brk) {
  189. if (isNumber(threshold) && isNumber(y)) {
  190. eventName = false;
  191. if ((threshold < brk.from && y > brk.to) ||
  192. (threshold > brk.from && y < brk.from)) {
  193. eventName = 'pointBreak';
  194. }
  195. else if ((threshold < brk.from && y > brk.from && y < brk.to) ||
  196. (threshold > brk.from && y > brk.to && y < brk.from)) {
  197. eventName = 'pointInBreak';
  198. }
  199. if (eventName) {
  200. fireEvent(axis, eventName, { point: point, brk: brk });
  201. }
  202. }
  203. });
  204. });
  205. });
  206. }
  207. }
  208. /**
  209. * Extend getGraphPath by identifying gaps in the data so that we
  210. * can draw a gap in the line or area. This was moved from ordinal
  211. * axis module to broken axis module as of #5045.
  212. *
  213. * @private
  214. * @function Highcharts.Series#gappedPath
  215. *
  216. * @return {Highcharts.SVGPathArray}
  217. * Gapped path
  218. */
  219. function seriesGappedPath() {
  220. var currentDataGrouping = this.currentDataGrouping,
  221. groupingSize = currentDataGrouping && currentDataGrouping.gapSize,
  222. points = this.points.slice(),
  223. yAxis = this.yAxis;
  224. var gapSize = this.options.gapSize,
  225. i = points.length - 1,
  226. stack;
  227. /**
  228. * Defines when to display a gap in the graph, together with the
  229. * [gapUnit](plotOptions.series.gapUnit) option.
  230. *
  231. * In case when `dataGrouping` is enabled, points can be grouped
  232. * into a larger time span. This can make the grouped points to
  233. * have a greater distance than the absolute value of `gapSize`
  234. * property, which will result in disappearing graph completely.
  235. * To prevent this situation the mentioned distance between
  236. * grouped points is used instead of previously defined
  237. * `gapSize`.
  238. *
  239. * In practice, this option is most often used to visualize gaps
  240. * in time series. In a stock chart, intraday data is available
  241. * for daytime hours, while gaps will appear in nights and
  242. * weekends.
  243. *
  244. * @see [gapUnit](plotOptions.series.gapUnit)
  245. * @see [xAxis.breaks](#xAxis.breaks)
  246. *
  247. * @sample {highstock} stock/plotoptions/series-gapsize/
  248. * Setting the gap size to 2 introduces gaps for weekends in
  249. * daily datasets.
  250. *
  251. * @type {number}
  252. * @default 0
  253. * @product highstock
  254. * @requires modules/broken-axis
  255. * @apioption plotOptions.series.gapSize
  256. */
  257. /**
  258. * Together with [gapSize](plotOptions.series.gapSize), this
  259. * option defines where to draw gaps in the graph.
  260. *
  261. * When the `gapUnit` is `"relative"` (default), a gap size of 5
  262. * means that if the distance between two points is greater than
  263. * 5 times that of the two closest points, the graph will be
  264. * broken.
  265. *
  266. * When the `gapUnit` is `"value"`, the gap is based on absolute
  267. * axis values, which on a datetime axis is milliseconds. This
  268. * also applies to the navigator series that inherits gap
  269. * options from the base series.
  270. *
  271. * @see [gapSize](plotOptions.series.gapSize)
  272. *
  273. * @type {string}
  274. * @default relative
  275. * @since 5.0.13
  276. * @product highstock
  277. * @validvalue ["relative", "value"]
  278. * @requires modules/broken-axis
  279. * @apioption plotOptions.series.gapUnit
  280. */
  281. if (gapSize && i > 0) { // #5008
  282. // Gap unit is relative
  283. if (this.options.gapUnit !== 'value') {
  284. gapSize *= this.basePointRange;
  285. }
  286. // Setting a new gapSize in case dataGrouping is enabled
  287. // (#7686)
  288. if (groupingSize &&
  289. groupingSize > gapSize &&
  290. // Except when DG is forced (e.g. from other series)
  291. // and has lower granularity than actual points (#11351)
  292. groupingSize >= this.basePointRange) {
  293. gapSize = groupingSize;
  294. }
  295. // extension for ordinal breaks
  296. var current = void 0,
  297. next = void 0;
  298. while (i--) {
  299. // Reassign next if it is not visible
  300. if (!(next && next.visible !== false)) {
  301. next = points[i + 1];
  302. }
  303. current = points[i];
  304. // Skip iteration if one of the points is not visible
  305. if (next.visible === false || current.visible === false) {
  306. continue;
  307. }
  308. if (next.x - current.x > gapSize) {
  309. var xRange = (current.x + next.x) / 2;
  310. points.splice(// insert after this one
  311. i + 1, 0, {
  312. isNull: true,
  313. x: xRange
  314. });
  315. // For stacked chart generate empty stack items,
  316. // #6546
  317. if (yAxis.stacking && this.options.stacking) {
  318. stack = yAxis.stacking.stacks[this.stackKey][xRange] =
  319. new StackItem(yAxis, yAxis.options
  320. .stackLabels, false, xRange, this.stack);
  321. stack.total = 0;
  322. }
  323. }
  324. // Assign current to next for the upcoming iteration
  325. next = current;
  326. }
  327. }
  328. // Call base method
  329. return this.getGraphPath(points);
  330. }
  331. /* *
  332. *
  333. * Class
  334. *
  335. * */
  336. /**
  337. * Provides support for broken axes.
  338. * @private
  339. * @class
  340. */
  341. var Additions = /** @class */ (function () {
  342. /* *
  343. *
  344. * Constructors
  345. *
  346. * */
  347. function Additions(axis) {
  348. this.hasBreaks = false;
  349. this.axis = axis;
  350. }
  351. /* *
  352. *
  353. * Static Functions
  354. *
  355. * */
  356. /**
  357. * @private
  358. */
  359. Additions.isInBreak = function (brk, val) {
  360. var repeat = brk.repeat || Infinity,
  361. from = brk.from,
  362. length = brk.to - brk.from,
  363. test = (val >= from ?
  364. (val - from) % repeat :
  365. repeat - ((from - val) % repeat));
  366. var ret;
  367. if (!brk.inclusive) {
  368. ret = test < length && test !== 0;
  369. }
  370. else {
  371. ret = test <= length;
  372. }
  373. return ret;
  374. };
  375. /**
  376. * @private
  377. */
  378. Additions.lin2Val = function (val) {
  379. var axis = this;
  380. var brokenAxis = axis.brokenAxis;
  381. var breakArray = brokenAxis && brokenAxis.breakArray;
  382. if (!breakArray || !isNumber(val)) {
  383. return val;
  384. }
  385. var nval = val,
  386. brk,
  387. i;
  388. for (i = 0; i < breakArray.length; i++) {
  389. brk = breakArray[i];
  390. if (brk.from >= nval) {
  391. break;
  392. }
  393. else if (brk.to < nval) {
  394. nval += brk.len;
  395. }
  396. else if (Additions.isInBreak(brk, nval)) {
  397. nval += brk.len;
  398. }
  399. }
  400. return nval;
  401. };
  402. /**
  403. * @private
  404. */
  405. Additions.val2Lin = function (val) {
  406. var axis = this;
  407. var brokenAxis = axis.brokenAxis;
  408. var breakArray = brokenAxis && brokenAxis.breakArray;
  409. if (!breakArray || !isNumber(val)) {
  410. return val;
  411. }
  412. var nval = val,
  413. brk,
  414. i;
  415. for (i = 0; i < breakArray.length; i++) {
  416. brk = breakArray[i];
  417. if (brk.to <= val) {
  418. nval -= brk.len;
  419. }
  420. else if (brk.from >= val) {
  421. break;
  422. }
  423. else if (Additions.isInBreak(brk, val)) {
  424. nval -= (val - brk.from);
  425. break;
  426. }
  427. }
  428. return nval;
  429. };
  430. /* *
  431. *
  432. * Functions
  433. *
  434. * */
  435. /**
  436. * Returns the first break found where the x is larger then break.from
  437. * and smaller then break.to.
  438. *
  439. * @param {number} x
  440. * The number which should be within a break.
  441. *
  442. * @param {Array<Highcharts.XAxisBreaksOptions>} breaks
  443. * The array of breaks to search within.
  444. *
  445. * @return {Highcharts.XAxisBreaksOptions|undefined}
  446. * Returns the first break found that matches, returns false if no break
  447. * is found.
  448. */
  449. Additions.prototype.findBreakAt = function (x, breaks) {
  450. return find(breaks, function (b) {
  451. return b.from < x && x < b.to;
  452. });
  453. };
  454. /**
  455. * @private
  456. */
  457. Additions.prototype.isInAnyBreak = function (val, testKeep) {
  458. var brokenAxis = this,
  459. axis = brokenAxis.axis,
  460. breaks = axis.options.breaks || [];
  461. var i = breaks.length,
  462. inbrk,
  463. keep,
  464. ret;
  465. if (i && isNumber(val)) {
  466. while (i--) {
  467. if (Additions.isInBreak(breaks[i], val)) {
  468. inbrk = true;
  469. if (!keep) {
  470. keep = pick(breaks[i].showPoints, !axis.isXAxis);
  471. }
  472. }
  473. }
  474. if (inbrk && testKeep) {
  475. ret = inbrk && !keep;
  476. }
  477. else {
  478. ret = inbrk;
  479. }
  480. }
  481. return ret;
  482. };
  483. /**
  484. * Dynamically set or unset breaks in an axis. This function in lighter
  485. * than usin Axis.update, and it also preserves animation.
  486. *
  487. * @private
  488. * @function Highcharts.Axis#setBreaks
  489. *
  490. * @param {Array<Highcharts.XAxisBreaksOptions>} [breaks]
  491. * The breaks to add. When `undefined` it removes existing breaks.
  492. *
  493. * @param {boolean} [redraw=true]
  494. * Whether to redraw the chart immediately.
  495. */
  496. Additions.prototype.setBreaks = function (breaks, redraw) {
  497. var brokenAxis = this;
  498. var axis = brokenAxis.axis;
  499. var hasBreaks = (isArray(breaks) && !!breaks.length);
  500. axis.isDirty = brokenAxis.hasBreaks !== hasBreaks;
  501. brokenAxis.hasBreaks = hasBreaks;
  502. axis.options.breaks = axis.userOptions.breaks = breaks;
  503. axis.forceRedraw = true; // Force recalculation in setScale
  504. // Recalculate series related to the axis.
  505. axis.series.forEach(function (series) {
  506. series.isDirty = true;
  507. });
  508. if (!hasBreaks && axis.val2lin === Additions.val2Lin) {
  509. // Revert to prototype functions
  510. delete axis.val2lin;
  511. delete axis.lin2val;
  512. }
  513. if (hasBreaks) {
  514. axis.userOptions.ordinal = false;
  515. axis.lin2val = Additions.lin2Val;
  516. axis.val2lin = Additions.val2Lin;
  517. axis.setExtremes = function (newMin, newMax, redraw, animation, eventArguments) {
  518. // If trying to set extremes inside a break, extend min to
  519. // after, and max to before the break ( #3857 )
  520. if (brokenAxis.hasBreaks) {
  521. var breaks_1 = (this.options.breaks || []);
  522. var axisBreak = void 0;
  523. while ((axisBreak = brokenAxis.findBreakAt(newMin, breaks_1))) {
  524. newMin = axisBreak.to;
  525. }
  526. while ((axisBreak = brokenAxis.findBreakAt(newMax, breaks_1))) {
  527. newMax = axisBreak.from;
  528. }
  529. // If both min and max is within the same break.
  530. if (newMax < newMin) {
  531. newMax = newMin;
  532. }
  533. }
  534. Axis.prototype.setExtremes.call(this, newMin, newMax, redraw, animation, eventArguments);
  535. };
  536. axis.setAxisTranslation = function () {
  537. Axis.prototype.setAxisTranslation.call(this);
  538. brokenAxis.unitLength = void 0;
  539. if (brokenAxis.hasBreaks) {
  540. var breaks_2 = axis.options.breaks || [],
  541. // Temporary one:
  542. breakArrayT_1 = [],
  543. breakArray_1 = [],
  544. pointRangePadding = pick(axis.pointRangePadding, 0);
  545. var length_1 = 0,
  546. inBrk_1,
  547. repeat_1,
  548. min_1 = axis.userMin || axis.min,
  549. max_1 = axis.userMax || axis.max,
  550. start_1,
  551. i_1;
  552. // Min & max check (#4247)
  553. breaks_2.forEach(function (brk) {
  554. repeat_1 = brk.repeat || Infinity;
  555. if (isNumber(min_1) && isNumber(max_1)) {
  556. if (Additions.isInBreak(brk, min_1)) {
  557. min_1 += (brk.to % repeat_1) - (min_1 % repeat_1);
  558. }
  559. if (Additions.isInBreak(brk, max_1)) {
  560. max_1 -= (max_1 % repeat_1) - (brk.from % repeat_1);
  561. }
  562. }
  563. });
  564. // Construct an array holding all breaks in the axis
  565. breaks_2.forEach(function (brk) {
  566. start_1 = brk.from;
  567. repeat_1 = brk.repeat || Infinity;
  568. if (isNumber(min_1) && isNumber(max_1)) {
  569. while (start_1 - repeat_1 > min_1) {
  570. start_1 -= repeat_1;
  571. }
  572. while (start_1 < min_1) {
  573. start_1 += repeat_1;
  574. }
  575. for (i_1 = start_1; i_1 < max_1; i_1 += repeat_1) {
  576. breakArrayT_1.push({
  577. value: i_1,
  578. move: 'in'
  579. });
  580. breakArrayT_1.push({
  581. value: i_1 + brk.to - brk.from,
  582. move: 'out',
  583. size: brk.breakSize
  584. });
  585. }
  586. }
  587. });
  588. breakArrayT_1.sort(function (a, b) {
  589. return ((a.value === b.value) ?
  590. ((a.move === 'in' ? 0 : 1) -
  591. (b.move === 'in' ? 0 : 1)) :
  592. a.value - b.value);
  593. });
  594. // Simplify the breaks
  595. inBrk_1 = 0;
  596. start_1 = min_1;
  597. breakArrayT_1.forEach(function (brk) {
  598. inBrk_1 += (brk.move === 'in' ? 1 : -1);
  599. if (inBrk_1 === 1 && brk.move === 'in') {
  600. start_1 = brk.value;
  601. }
  602. if (inBrk_1 === 0 && isNumber(start_1)) {
  603. breakArray_1.push({
  604. from: start_1,
  605. to: brk.value,
  606. len: brk.value - start_1 - (brk.size || 0)
  607. });
  608. length_1 += brk.value - start_1 - (brk.size || 0);
  609. }
  610. });
  611. brokenAxis.breakArray = breakArray_1;
  612. // Used with staticScale, and below the actual axis
  613. // length, when breaks are substracted.
  614. if (isNumber(min_1) && isNumber(max_1) && isNumber(axis.min)) {
  615. brokenAxis.unitLength = max_1 - min_1 - length_1 +
  616. pointRangePadding;
  617. fireEvent(axis, 'afterBreaks');
  618. if (axis.staticScale) {
  619. axis.transA = axis.staticScale;
  620. }
  621. else if (brokenAxis.unitLength) {
  622. axis.transA *=
  623. (max_1 - axis.min + pointRangePadding) /
  624. brokenAxis.unitLength;
  625. }
  626. if (pointRangePadding) {
  627. axis.minPixelPadding =
  628. axis.transA * (axis.minPointOffset || 0);
  629. }
  630. axis.min = min_1;
  631. axis.max = max_1;
  632. }
  633. }
  634. };
  635. }
  636. if (pick(redraw, true)) {
  637. axis.chart.redraw();
  638. }
  639. };
  640. return Additions;
  641. }());
  642. BrokenAxis.Additions = Additions;
  643. })(BrokenAxis || (BrokenAxis = {}));
  644. /* *
  645. *
  646. * Default Export
  647. *
  648. * */
  649. return BrokenAxis;
  650. });
  651. _registerModule(_modules, 'Core/Axis/GridAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Axis/AxisDefaults.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (Axis, AxisDefaults, H, U) {
  652. /* *
  653. *
  654. * (c) 2016 Highsoft AS
  655. * Authors: Lars A. V. Cabrera
  656. *
  657. * License: www.highcharts.com/license
  658. *
  659. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  660. *
  661. * */
  662. var dateFormats = H.dateFormats;
  663. var addEvent = U.addEvent,
  664. defined = U.defined,
  665. erase = U.erase,
  666. find = U.find,
  667. isArray = U.isArray,
  668. isNumber = U.isNumber,
  669. merge = U.merge,
  670. pick = U.pick,
  671. timeUnits = U.timeUnits,
  672. wrap = U.wrap;
  673. /* *
  674. *
  675. * Functions
  676. *
  677. * */
  678. /* eslint-disable require-jsdoc */
  679. function argsToArray(args) {
  680. return Array.prototype.slice.call(args, 1);
  681. }
  682. function isObject(x) {
  683. // Always use strict mode
  684. return U.isObject(x, true);
  685. }
  686. function applyGridOptions(axis) {
  687. var options = axis.options;
  688. // Center-align by default
  689. /*
  690. if (!options.labels) {
  691. options.labels = {};
  692. }
  693. */
  694. options.labels.align = pick(options.labels.align, 'center');
  695. // @todo: Check against tickLabelPlacement between/on etc
  696. /* Prevents adding the last tick label if the axis is not a category
  697. axis.
  698. Since numeric labels are normally placed at starts and ends of a
  699. range of value, and this module makes the label point at the value,
  700. an "extra" label would appear. */
  701. if (!axis.categories) {
  702. options.showLastLabel = false;
  703. }
  704. // Prevents rotation of labels when squished, as rotating them would not
  705. // help.
  706. axis.labelRotation = 0;
  707. options.labels.rotation = 0;
  708. }
  709. /**
  710. * Axis with grid support.
  711. * @private
  712. */
  713. var GridAxis;
  714. (function (GridAxis) {
  715. /* *
  716. *
  717. * Declarations
  718. *
  719. * */
  720. /**
  721. * Enum for which side the axis is on. Maps to axis.side.
  722. * @private
  723. */
  724. var Side;
  725. (function (Side) {
  726. Side[Side["top"] = 0] = "top";
  727. Side[Side["right"] = 1] = "right";
  728. Side[Side["bottom"] = 2] = "bottom";
  729. Side[Side["left"] = 3] = "left";
  730. })(Side = GridAxis.Side || (GridAxis.Side = {}));
  731. /* *
  732. *
  733. * Functions
  734. *
  735. * */
  736. /* eslint-disable valid-jsdoc */
  737. /**
  738. * Extends axis class with grid support.
  739. * @private
  740. */
  741. function compose(AxisClass, ChartClass, TickClass) {
  742. if (AxisClass.keepProps.indexOf('grid') === -1) {
  743. AxisClass.keepProps.push('grid');
  744. AxisClass.prototype.getMaxLabelDimensions = getMaxLabelDimensions;
  745. wrap(AxisClass.prototype, 'unsquish', wrapUnsquish);
  746. // Add event handlers
  747. addEvent(AxisClass, 'init', onInit);
  748. addEvent(AxisClass, 'afterGetOffset', onAfterGetOffset);
  749. addEvent(AxisClass, 'afterGetTitlePosition', onAfterGetTitlePosition);
  750. addEvent(AxisClass, 'afterInit', onAfterInit);
  751. addEvent(AxisClass, 'afterRender', onAfterRender);
  752. addEvent(AxisClass, 'afterSetAxisTranslation', onAfterSetAxisTranslation);
  753. addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions);
  754. addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions2);
  755. addEvent(AxisClass, 'afterSetScale', onAfterSetScale);
  756. addEvent(AxisClass, 'afterTickSize', onAfterTickSize);
  757. addEvent(AxisClass, 'trimTicks', onTrimTicks);
  758. addEvent(AxisClass, 'destroy', onDestroy);
  759. }
  760. addEvent(ChartClass, 'afterSetChartSize', onChartAfterSetChartSize);
  761. addEvent(TickClass, 'afterGetLabelPosition', onTickAfterGetLabelPosition);
  762. addEvent(TickClass, 'labelFormat', onTickLabelFormat);
  763. return AxisClass;
  764. }
  765. GridAxis.compose = compose;
  766. /**
  767. * Get the largest label width and height.
  768. *
  769. * @private
  770. * @function Highcharts.Axis#getMaxLabelDimensions
  771. *
  772. * @param {Highcharts.Dictionary<Highcharts.Tick>} ticks
  773. * All the ticks on one axis.
  774. *
  775. * @param {Array<number|string>} tickPositions
  776. * All the tick positions on one axis.
  777. *
  778. * @return {Highcharts.SizeObject}
  779. * Object containing the properties height and width.
  780. *
  781. * @todo Move this to the generic axis implementation, as it is used there.
  782. */
  783. function getMaxLabelDimensions(ticks, tickPositions) {
  784. var dimensions = {
  785. width: 0,
  786. height: 0
  787. };
  788. tickPositions.forEach(function (pos) {
  789. var tick = ticks[pos];
  790. var labelHeight = 0,
  791. labelWidth = 0,
  792. label;
  793. if (isObject(tick)) {
  794. label = isObject(tick.label) ? tick.label : {};
  795. // Find width and height of label
  796. labelHeight = label.getBBox ? label.getBBox().height : 0;
  797. if (label.textStr && !isNumber(label.textPxLength)) {
  798. label.textPxLength = label.getBBox().width;
  799. }
  800. labelWidth = isNumber(label.textPxLength) ?
  801. // Math.round ensures crisp lines
  802. Math.round(label.textPxLength) :
  803. 0;
  804. if (label.textStr) {
  805. // Set the tickWidth same as the label width after ellipsis
  806. // applied #10281
  807. labelWidth = Math.round(label.getBBox().width);
  808. }
  809. // Update the result if width and/or height are larger
  810. dimensions.height = Math.max(labelHeight, dimensions.height);
  811. dimensions.width = Math.max(labelWidth, dimensions.width);
  812. }
  813. });
  814. // For tree grid, add indentation
  815. if (this.options.type === 'treegrid' &&
  816. this.treeGrid &&
  817. this.treeGrid.mapOfPosToGridNode) {
  818. var treeDepth = this.treeGrid.mapOfPosToGridNode[-1].height || 0;
  819. dimensions.width += this.options.labels.indentation * (treeDepth - 1);
  820. }
  821. return dimensions;
  822. }
  823. /**
  824. * Handle columns and getOffset.
  825. * @private
  826. */
  827. function onAfterGetOffset() {
  828. var grid = this.grid;
  829. (grid && grid.columns || []).forEach(function (column) {
  830. column.getOffset();
  831. });
  832. }
  833. /**
  834. * @private
  835. */
  836. function onAfterGetTitlePosition(e) {
  837. var axis = this;
  838. var options = axis.options;
  839. var gridOptions = options.grid || {};
  840. if (gridOptions.enabled === true) {
  841. // compute anchor points for each of the title align options
  842. var axisTitle = axis.axisTitle,
  843. axisHeight = axis.height,
  844. horiz = axis.horiz,
  845. axisLeft = axis.left,
  846. offset = axis.offset,
  847. opposite = axis.opposite,
  848. options_1 = axis.options,
  849. axisTop = axis.top,
  850. axisWidth = axis.width;
  851. var tickSize = axis.tickSize();
  852. var titleWidth = axisTitle && axisTitle.getBBox().width;
  853. var xOption = options_1.title.x;
  854. var yOption = options_1.title.y;
  855. var titleMargin = pick(options_1.title.margin,
  856. horiz ? 5 : 10);
  857. var titleFontSize = axis.chart.renderer.fontMetrics(options_1.title.style.fontSize,
  858. axisTitle).f;
  859. var crispCorr = tickSize ? tickSize[0] / 2 : 0;
  860. // TODO account for alignment
  861. // the position in the perpendicular direction of the axis
  862. var offAxis = ((horiz ? axisTop + axisHeight : axisLeft) +
  863. (horiz ? 1 : -1) * // horizontal axis reverses the margin
  864. (opposite ? -1 : 1) * // so does opposite axes
  865. crispCorr +
  866. (axis.side === GridAxis.Side.bottom ? titleFontSize : 0));
  867. e.titlePosition.x = horiz ?
  868. axisLeft - (titleWidth || 0) / 2 - titleMargin + xOption :
  869. offAxis + (opposite ? axisWidth : 0) + offset + xOption;
  870. e.titlePosition.y = horiz ?
  871. (offAxis -
  872. (opposite ? axisHeight : 0) +
  873. (opposite ? titleFontSize : -titleFontSize) / 2 +
  874. offset +
  875. yOption) :
  876. axisTop - titleMargin + yOption;
  877. }
  878. }
  879. /**
  880. * @private
  881. */
  882. function onAfterInit() {
  883. var axis = this;
  884. var chart = axis.chart,
  885. _a = axis.options.grid,
  886. gridOptions = _a === void 0 ? {} : _a,
  887. userOptions = axis.userOptions;
  888. if (gridOptions.enabled) {
  889. applyGridOptions(axis);
  890. }
  891. if (gridOptions.columns) {
  892. var columns = axis.grid.columns = [];
  893. var columnIndex = axis.grid.columnIndex = 0;
  894. // Handle columns, each column is a grid axis
  895. while (++columnIndex < gridOptions.columns.length) {
  896. var columnOptions = merge(userOptions,
  897. gridOptions.columns[gridOptions.columns.length - columnIndex - 1], {
  898. linkedTo: 0,
  899. // Force to behave like category axis
  900. type: 'category',
  901. // Disable by default the scrollbar on the grid axis
  902. scrollbar: {
  903. enabled: false
  904. }
  905. });
  906. delete columnOptions.grid.columns; // Prevent recursion
  907. var column = new Axis(axis.chart,
  908. columnOptions);
  909. column.grid.isColumn = true;
  910. column.grid.columnIndex = columnIndex;
  911. // Remove column axis from chart axes array, and place it
  912. // in the columns array.
  913. erase(chart.axes, column);
  914. erase(chart[axis.coll], column);
  915. columns.push(column);
  916. }
  917. }
  918. }
  919. /**
  920. * Draw an extra line on the far side of the outermost axis,
  921. * creating floor/roof/wall of a grid. And some padding.
  922. * ```
  923. * Make this:
  924. * (axis.min) __________________________ (axis.max)
  925. * | | | | |
  926. * Into this:
  927. * (axis.min) __________________________ (axis.max)
  928. * ___|____|____|____|____|__
  929. * ```
  930. * @private
  931. */
  932. function onAfterRender() {
  933. var axis = this,
  934. grid = axis.grid,
  935. options = axis.options,
  936. gridOptions = options.grid || {};
  937. if (gridOptions.enabled === true) {
  938. var min = axis.min || 0,
  939. max = axis.max || 0;
  940. // @todo acutual label padding (top, bottom, left, right)
  941. axis.maxLabelDimensions = axis.getMaxLabelDimensions(axis.ticks, axis.tickPositions);
  942. // Remove right wall before rendering if updating
  943. if (axis.rightWall) {
  944. axis.rightWall.destroy();
  945. }
  946. /*
  947. Draw an extra axis line on outer axes
  948. >
  949. Make this: |______|______|______|___
  950. > _________________________
  951. Into this: |______|______|______|__|
  952. */
  953. if (axis.grid && axis.grid.isOuterAxis() && axis.axisLine) {
  954. var lineWidth = options.lineWidth;
  955. if (lineWidth) {
  956. var linePath = axis.getLinePath(lineWidth),
  957. startPoint = linePath[0],
  958. endPoint = linePath[1],
  959. // Negate distance if top or left axis
  960. // Subtract 1px to draw the line at the end of the tick
  961. tickLength = (axis.tickSize('tick') || [1])[0],
  962. distance = (tickLength - 1) * ((axis.side === GridAxis.Side.top ||
  963. axis.side === GridAxis.Side.left) ? -1 : 1);
  964. // If axis is horizontal, reposition line path vertically
  965. if (startPoint[0] === 'M' && endPoint[0] === 'L') {
  966. if (axis.horiz) {
  967. startPoint[2] += distance;
  968. endPoint[2] += distance;
  969. }
  970. else {
  971. startPoint[1] += distance;
  972. endPoint[1] += distance;
  973. }
  974. }
  975. // If it doesn't exist, add an upper and lower border
  976. // for the vertical grid axis.
  977. if (!axis.horiz && axis.chart.marginRight) {
  978. var upperBorderStartPoint = startPoint,
  979. upperBorderEndPoint = [
  980. 'L',
  981. axis.left,
  982. startPoint[2] || 0
  983. ],
  984. upperBorderPath = [upperBorderStartPoint,
  985. upperBorderEndPoint],
  986. lowerBorderEndPoint = [
  987. 'L',
  988. axis.chart.chartWidth - axis.chart.marginRight,
  989. axis.toPixels(max + axis.tickmarkOffset)
  990. ],
  991. lowerBorderStartPoint = [
  992. 'M',
  993. endPoint[1] || 0,
  994. axis.toPixels(max + axis.tickmarkOffset)
  995. ],
  996. lowerBorderPath = [lowerBorderStartPoint,
  997. lowerBorderEndPoint];
  998. if (!axis.grid.upperBorder && min % 1 !== 0) {
  999. axis.grid.upperBorder = axis.grid.renderBorder(upperBorderPath);
  1000. }
  1001. if (axis.grid.upperBorder) {
  1002. axis.grid.upperBorder.attr({
  1003. stroke: options.lineColor,
  1004. 'stroke-width': options.lineWidth
  1005. });
  1006. axis.grid.upperBorder.animate({
  1007. d: upperBorderPath
  1008. });
  1009. }
  1010. if (!axis.grid.lowerBorder && max % 1 !== 0) {
  1011. axis.grid.lowerBorder = axis.grid.renderBorder(lowerBorderPath);
  1012. }
  1013. if (axis.grid.lowerBorder) {
  1014. axis.grid.lowerBorder.attr({
  1015. stroke: options.lineColor,
  1016. 'stroke-width': options.lineWidth
  1017. });
  1018. axis.grid.lowerBorder.animate({
  1019. d: lowerBorderPath
  1020. });
  1021. }
  1022. }
  1023. // Render an extra line parallel to the existing axes,
  1024. // to close the grid.
  1025. if (!axis.grid.axisLineExtra) {
  1026. axis.grid.axisLineExtra = axis.grid.renderBorder(linePath);
  1027. }
  1028. else {
  1029. axis.grid.axisLineExtra.attr({
  1030. stroke: options.lineColor,
  1031. 'stroke-width': options.lineWidth
  1032. });
  1033. axis.grid.axisLineExtra.animate({
  1034. d: linePath
  1035. });
  1036. }
  1037. // show or hide the line depending on
  1038. // options.showEmpty
  1039. axis.axisLine[axis.showAxis ? 'show' : 'hide'](true);
  1040. }
  1041. }
  1042. (grid && grid.columns || []).forEach(function (column) {
  1043. column.render();
  1044. });
  1045. // Manipulate the tick mark visibility
  1046. // based on the axis.max- allows smooth scrolling.
  1047. if (!axis.horiz &&
  1048. axis.chart.hasRendered &&
  1049. (axis.scrollbar ||
  1050. (axis.linkedParent && axis.linkedParent.scrollbar))) {
  1051. var tickmarkOffset = axis.tickmarkOffset,
  1052. lastTick = axis.tickPositions[axis.tickPositions.length - 1],
  1053. firstTick = axis.tickPositions[0];
  1054. // Hide/show firts tick label.
  1055. var label = axis.ticks[firstTick].label;
  1056. if (label) {
  1057. if (min - firstTick > tickmarkOffset) {
  1058. label.hide();
  1059. }
  1060. else {
  1061. label.show();
  1062. }
  1063. }
  1064. // Hide/show last tick mark/label.
  1065. label = axis.ticks[lastTick].label;
  1066. if (label) {
  1067. if (lastTick - max > tickmarkOffset) {
  1068. label.hide();
  1069. }
  1070. else {
  1071. label.show();
  1072. }
  1073. }
  1074. var mark = axis.ticks[lastTick].mark;
  1075. if (mark) {
  1076. if (lastTick - max < tickmarkOffset && lastTick - max > 0 && axis.ticks[lastTick].isLast) {
  1077. mark.hide();
  1078. }
  1079. else if (axis.ticks[lastTick - 1]) {
  1080. mark.show();
  1081. }
  1082. }
  1083. }
  1084. }
  1085. }
  1086. /**
  1087. * @private
  1088. */
  1089. function onAfterSetAxisTranslation() {
  1090. var axis = this;
  1091. var tickInfo = axis.tickPositions && axis.tickPositions.info;
  1092. var options = axis.options;
  1093. var gridOptions = options.grid || {};
  1094. var userLabels = axis.userOptions.labels || {};
  1095. // Fire this only for the Gantt type chart, #14868.
  1096. if (gridOptions.enabled) {
  1097. if (axis.horiz) {
  1098. axis.series.forEach(function (series) {
  1099. series.options.pointRange = 0;
  1100. });
  1101. // Lower level time ticks, like hours or minutes, represent
  1102. // points in time and not ranges. These should be aligned
  1103. // left in the grid cell by default. The same applies to
  1104. // years of higher order.
  1105. if (tickInfo &&
  1106. options.dateTimeLabelFormats &&
  1107. options.labels &&
  1108. !defined(userLabels.align) &&
  1109. (options.dateTimeLabelFormats[tickInfo.unitName].range === false ||
  1110. tickInfo.count > 1 // years
  1111. )) {
  1112. options.labels.align = 'left';
  1113. if (!defined(userLabels.x)) {
  1114. options.labels.x = 3;
  1115. }
  1116. }
  1117. }
  1118. else {
  1119. // Don't trim ticks which not in min/max range but
  1120. // they are still in the min/max plus tickInterval.
  1121. if (this.options.type !== 'treegrid' &&
  1122. axis.grid &&
  1123. axis.grid.columns) {
  1124. this.minPointOffset = this.tickInterval;
  1125. }
  1126. }
  1127. }
  1128. }
  1129. /**
  1130. * Creates a left and right wall on horizontal axes:
  1131. * - Places leftmost tick at the start of the axis, to create a left
  1132. * wall
  1133. * - Ensures that the rightmost tick is at the end of the axis, to
  1134. * create a right wall.
  1135. * @private
  1136. */
  1137. function onAfterSetOptions(e) {
  1138. var options = this.options,
  1139. userOptions = e.userOptions,
  1140. gridOptions = ((options && isObject(options.grid)) ? options.grid : {});
  1141. var gridAxisOptions;
  1142. if (gridOptions.enabled === true) {
  1143. // Merge the user options into default grid axis options so
  1144. // that when a user option is set, it takes presedence.
  1145. gridAxisOptions = merge(true, {
  1146. className: ('highcharts-grid-axis ' + (userOptions.className || '')),
  1147. dateTimeLabelFormats: {
  1148. hour: {
  1149. list: ['%H:%M', '%H']
  1150. },
  1151. day: {
  1152. list: ['%A, %e. %B', '%a, %e. %b', '%E']
  1153. },
  1154. week: {
  1155. list: ['Week %W', 'W%W']
  1156. },
  1157. month: {
  1158. list: ['%B', '%b', '%o']
  1159. }
  1160. },
  1161. grid: {
  1162. borderWidth: 1
  1163. },
  1164. labels: {
  1165. padding: 2,
  1166. style: {
  1167. fontSize: '13px'
  1168. }
  1169. },
  1170. margin: 0,
  1171. title: {
  1172. text: null,
  1173. reserveSpace: false,
  1174. rotation: 0
  1175. },
  1176. // In a grid axis, only allow one unit of certain types,
  1177. // for example we shouln't have one grid cell spanning
  1178. // two days.
  1179. units: [[
  1180. 'millisecond',
  1181. [1, 10, 100]
  1182. ], [
  1183. 'second',
  1184. [1, 10]
  1185. ], [
  1186. 'minute',
  1187. [1, 5, 15]
  1188. ], [
  1189. 'hour',
  1190. [1, 6]
  1191. ], [
  1192. 'day',
  1193. [1]
  1194. ], [
  1195. 'week',
  1196. [1]
  1197. ], [
  1198. 'month',
  1199. [1]
  1200. ], [
  1201. 'year',
  1202. null
  1203. ]]
  1204. }, userOptions);
  1205. // X-axis specific options
  1206. if (this.coll === 'xAxis') {
  1207. // For linked axes, tickPixelInterval is used only if
  1208. // the tickPositioner below doesn't run or returns
  1209. // undefined (like multiple years)
  1210. if (defined(userOptions.linkedTo) &&
  1211. !defined(userOptions.tickPixelInterval)) {
  1212. gridAxisOptions.tickPixelInterval = 350;
  1213. }
  1214. // For the secondary grid axis, use the primary axis'
  1215. // tick intervals and return ticks one level higher.
  1216. if (
  1217. // Check for tick pixel interval in options
  1218. !defined(userOptions.tickPixelInterval) &&
  1219. // Only for linked axes
  1220. defined(userOptions.linkedTo) &&
  1221. !defined(userOptions.tickPositioner) &&
  1222. !defined(userOptions.tickInterval)) {
  1223. gridAxisOptions.tickPositioner = function (min, max) {
  1224. var parentInfo = (this.linkedParent &&
  1225. this.linkedParent.tickPositions &&
  1226. this.linkedParent.tickPositions.info);
  1227. if (parentInfo) {
  1228. var units = (gridAxisOptions.units || []);
  1229. var unitIdx = void 0,
  1230. count = void 0,
  1231. unitName = void 0;
  1232. for (var i = 0; i < units.length; i++) {
  1233. if (units[i][0] ===
  1234. parentInfo.unitName) {
  1235. unitIdx = i;
  1236. break;
  1237. }
  1238. }
  1239. // Get the first allowed count on the next
  1240. // unit.
  1241. if (units[unitIdx + 1]) {
  1242. unitName = units[unitIdx + 1][0];
  1243. count =
  1244. (units[unitIdx + 1][1] || [1])[0];
  1245. // In case the base X axis shows years, make
  1246. // the secondary axis show ten times the
  1247. // years (#11427)
  1248. }
  1249. else if (parentInfo.unitName === 'year') {
  1250. unitName = 'year';
  1251. count = parentInfo.count * 10;
  1252. }
  1253. var unitRange = timeUnits[unitName];
  1254. this.tickInterval = unitRange * count;
  1255. return this.getTimeTicks({
  1256. unitRange: unitRange,
  1257. count: count,
  1258. unitName: unitName
  1259. }, min, max, this.options.startOfWeek);
  1260. }
  1261. };
  1262. }
  1263. }
  1264. // Now merge the combined options into the axis options
  1265. merge(true, this.options, gridAxisOptions);
  1266. if (this.horiz) {
  1267. /* _________________________
  1268. Make this: ___|_____|_____|_____|__|
  1269. ^ ^
  1270. _________________________
  1271. Into this: |_____|_____|_____|_____|
  1272. ^ ^ */
  1273. options.minPadding = pick(userOptions.minPadding, 0);
  1274. options.maxPadding = pick(userOptions.maxPadding, 0);
  1275. }
  1276. // If borderWidth is set, then use its value for tick and
  1277. // line width.
  1278. if (isNumber(options.grid.borderWidth)) {
  1279. options.tickWidth = options.lineWidth =
  1280. gridOptions.borderWidth;
  1281. }
  1282. }
  1283. }
  1284. /**
  1285. * @private
  1286. */
  1287. function onAfterSetOptions2(e) {
  1288. var axis = this;
  1289. var userOptions = e.userOptions;
  1290. var gridOptions = userOptions && userOptions.grid || {};
  1291. var columns = gridOptions.columns;
  1292. // Add column options to the parent axis. Children has their column
  1293. // options set on init in onGridAxisAfterInit.
  1294. if (gridOptions.enabled && columns) {
  1295. merge(true, axis.options, columns[columns.length - 1]);
  1296. }
  1297. }
  1298. /**
  1299. * Handle columns and setScale.
  1300. * @private
  1301. */
  1302. function onAfterSetScale() {
  1303. var axis = this;
  1304. (axis.grid.columns || []).forEach(function (column) {
  1305. column.setScale();
  1306. });
  1307. }
  1308. /**
  1309. * Draw vertical axis ticks extra long to create cell floors and roofs.
  1310. * Overrides the tickLength for vertical axes.
  1311. * @private
  1312. */
  1313. function onAfterTickSize(e) {
  1314. var defaultLeftAxisOptions = AxisDefaults.defaultLeftAxisOptions;
  1315. var _a = this,
  1316. horiz = _a.horiz,
  1317. maxLabelDimensions = _a.maxLabelDimensions,
  1318. _b = _a.options.grid,
  1319. gridOptions = _b === void 0 ? {} : _b;
  1320. if (gridOptions.enabled && maxLabelDimensions) {
  1321. var labelPadding = (Math.abs(defaultLeftAxisOptions.labels.x) * 2);
  1322. var distance = horiz ?
  1323. gridOptions.cellHeight || labelPadding + maxLabelDimensions.height :
  1324. labelPadding + maxLabelDimensions.width;
  1325. if (isArray(e.tickSize)) {
  1326. e.tickSize[0] = distance;
  1327. }
  1328. else {
  1329. e.tickSize = [distance, 0];
  1330. }
  1331. }
  1332. }
  1333. /**
  1334. * @private
  1335. */
  1336. function onChartAfterSetChartSize() {
  1337. this.axes.forEach(function (axis) {
  1338. (axis.grid && axis.grid.columns || []).forEach(function (column) {
  1339. column.setAxisSize();
  1340. column.setAxisTranslation();
  1341. });
  1342. });
  1343. }
  1344. /**
  1345. * @private
  1346. */
  1347. function onDestroy(e) {
  1348. var grid = this.grid;
  1349. (grid.columns || []).forEach(function (column) {
  1350. column.destroy(e.keepEvents);
  1351. });
  1352. grid.columns = void 0;
  1353. }
  1354. /**
  1355. * Wraps axis init to draw cell walls on vertical axes.
  1356. * @private
  1357. */
  1358. function onInit(e) {
  1359. var axis = this;
  1360. var userOptions = e.userOptions || {};
  1361. var gridOptions = userOptions.grid || {};
  1362. if (gridOptions.enabled && defined(gridOptions.borderColor)) {
  1363. userOptions.tickColor = userOptions.lineColor = gridOptions.borderColor;
  1364. }
  1365. if (!axis.grid) {
  1366. axis.grid = new Additions(axis);
  1367. }
  1368. }
  1369. /**
  1370. * Center tick labels in cells.
  1371. * @private
  1372. */
  1373. function onTickAfterGetLabelPosition(e) {
  1374. var tick = this,
  1375. label = tick.label,
  1376. axis = tick.axis,
  1377. reversed = axis.reversed,
  1378. chart = axis.chart,
  1379. options = axis.options,
  1380. gridOptions = options.grid || {},
  1381. labelOpts = axis.options.labels,
  1382. align = labelOpts.align,
  1383. // verticalAlign is currently not supported for axis.labels.
  1384. verticalAlign = 'middle', // labelOpts.verticalAlign,
  1385. side = GridAxis.Side[axis.side],
  1386. tickmarkOffset = e.tickmarkOffset,
  1387. tickPositions = axis.tickPositions,
  1388. tickPos = tick.pos - tickmarkOffset,
  1389. nextTickPos = (isNumber(tickPositions[e.index + 1]) ?
  1390. tickPositions[e.index + 1] - tickmarkOffset :
  1391. (axis.max || 0) + tickmarkOffset),
  1392. tickSize = axis.tickSize('tick'),
  1393. tickWidth = tickSize ? tickSize[0] : 0,
  1394. crispCorr = tickSize ? tickSize[1] / 2 : 0;
  1395. var labelHeight,
  1396. lblMetrics,
  1397. lines,
  1398. bottom,
  1399. top,
  1400. left,
  1401. right;
  1402. // Only center tick labels in grid axes
  1403. if (gridOptions.enabled === true) {
  1404. // Calculate top and bottom positions of the cell.
  1405. if (side === 'top') {
  1406. bottom = axis.top + axis.offset;
  1407. top = bottom - tickWidth;
  1408. }
  1409. else if (side === 'bottom') {
  1410. top = chart.chartHeight - axis.bottom + axis.offset;
  1411. bottom = top + tickWidth;
  1412. }
  1413. else {
  1414. bottom = axis.top + axis.len - (axis.translate(reversed ? nextTickPos : tickPos) || 0);
  1415. top = axis.top + axis.len - (axis.translate(reversed ? tickPos : nextTickPos) || 0);
  1416. }
  1417. // Calculate left and right positions of the cell.
  1418. if (side === 'right') {
  1419. left = chart.chartWidth - axis.right + axis.offset;
  1420. right = left + tickWidth;
  1421. }
  1422. else if (side === 'left') {
  1423. right = axis.left + axis.offset;
  1424. left = right - tickWidth;
  1425. }
  1426. else {
  1427. left = Math.round(axis.left + (axis.translate(reversed ? nextTickPos : tickPos) || 0)) - crispCorr;
  1428. right = Math.min(// #15742
  1429. Math.round(axis.left + (axis.translate(reversed ? tickPos : nextTickPos) || 0)) - crispCorr, axis.left + axis.len);
  1430. }
  1431. tick.slotWidth = right - left;
  1432. // Calculate the positioning of the label based on
  1433. // alignment.
  1434. e.pos.x = (align === 'left' ?
  1435. left :
  1436. align === 'right' ?
  1437. right :
  1438. left + ((right - left) / 2) // default to center
  1439. );
  1440. e.pos.y = (verticalAlign === 'top' ?
  1441. top :
  1442. verticalAlign === 'bottom' ?
  1443. bottom :
  1444. top + ((bottom - top) / 2) // default to middle
  1445. );
  1446. lblMetrics = chart.renderer.fontMetrics(labelOpts.style.fontSize, label && label.element);
  1447. labelHeight = label ? label.getBBox().height : 0;
  1448. // Adjustment to y position to align the label correctly.
  1449. // Would be better to have a setter or similar for this.
  1450. if (!labelOpts.useHTML) {
  1451. lines = Math.round(labelHeight / lblMetrics.h);
  1452. e.pos.y += (
  1453. // Center the label
  1454. // TODO: why does this actually center the label?
  1455. ((lblMetrics.b - (lblMetrics.h - lblMetrics.f)) / 2) +
  1456. // Adjust for height of additional lines.
  1457. -(((lines - 1) * lblMetrics.h) / 2));
  1458. }
  1459. else {
  1460. e.pos.y += (
  1461. // Readjust yCorr in htmlUpdateTransform
  1462. lblMetrics.b +
  1463. // Adjust for height of html label
  1464. -(labelHeight / 2));
  1465. }
  1466. e.pos.x += (axis.horiz && labelOpts.x) || 0;
  1467. }
  1468. }
  1469. /**
  1470. * @private
  1471. */
  1472. function onTickLabelFormat(ctx) {
  1473. var axis = ctx.axis,
  1474. value = ctx.value;
  1475. if (axis.options.grid &&
  1476. axis.options.grid.enabled) {
  1477. var tickPos = axis.tickPositions;
  1478. var series = (axis.linkedParent || axis).series[0];
  1479. var isFirst = value === tickPos[0];
  1480. var isLast = value === tickPos[tickPos.length - 1];
  1481. var point = series && find(series.options.data,
  1482. function (p) {
  1483. return p[axis.isXAxis ? 'x' : 'y'] === value;
  1484. });
  1485. var pointCopy = void 0;
  1486. if (point && series.is('gantt')) {
  1487. // For the Gantt set point aliases to the pointCopy
  1488. // to do not change the original point
  1489. pointCopy = merge(point);
  1490. H.seriesTypes.gantt.prototype.pointClass
  1491. .setGanttPointAliases(pointCopy);
  1492. }
  1493. // Make additional properties available for the
  1494. // formatter
  1495. ctx.isFirst = isFirst;
  1496. ctx.isLast = isLast;
  1497. ctx.point = pointCopy;
  1498. }
  1499. }
  1500. /**
  1501. * Makes tick labels which are usually ignored in a linked axis
  1502. * displayed if they are within range of linkedParent.min.
  1503. * ```
  1504. * _____________________________
  1505. * | | | | |
  1506. * Make this: | | 2 | 3 | 4 |
  1507. * |___|_______|_______|_______|
  1508. * ^
  1509. * _____________________________
  1510. * | | | | |
  1511. * Into this: | 1 | 2 | 3 | 4 |
  1512. * |___|_______|_______|_______|
  1513. * ^
  1514. * ```
  1515. * @private
  1516. * @todo Does this function do what the drawing says? Seems to affect
  1517. * ticks and not the labels directly?
  1518. */
  1519. function onTrimTicks() {
  1520. var axis = this;
  1521. var options = axis.options;
  1522. var gridOptions = options.grid || {};
  1523. var categoryAxis = axis.categories;
  1524. var tickPositions = axis.tickPositions;
  1525. var firstPos = tickPositions[0];
  1526. var lastPos = tickPositions[tickPositions.length - 1];
  1527. var linkedMin = axis.linkedParent && axis.linkedParent.min;
  1528. var linkedMax = axis.linkedParent && axis.linkedParent.max;
  1529. var min = linkedMin || axis.min;
  1530. var max = linkedMax || axis.max;
  1531. var tickInterval = axis.tickInterval;
  1532. var endMoreThanMin = (firstPos < min &&
  1533. firstPos + tickInterval > min);
  1534. var startLessThanMax = (lastPos > max &&
  1535. lastPos - tickInterval < max);
  1536. if (gridOptions.enabled === true &&
  1537. !categoryAxis &&
  1538. (axis.horiz || axis.isLinked)) {
  1539. if (endMoreThanMin && !options.startOnTick) {
  1540. tickPositions[0] = min;
  1541. }
  1542. if (startLessThanMax && !options.endOnTick) {
  1543. tickPositions[tickPositions.length - 1] = max;
  1544. }
  1545. }
  1546. }
  1547. /**
  1548. * Avoid altering tickInterval when reserving space.
  1549. * @private
  1550. */
  1551. function wrapUnsquish(proceed) {
  1552. var axis = this;
  1553. var _a = axis.options.grid,
  1554. gridOptions = _a === void 0 ? {} : _a;
  1555. if (gridOptions.enabled === true && axis.categories) {
  1556. return axis.tickInterval;
  1557. }
  1558. return proceed.apply(axis, argsToArray(arguments));
  1559. }
  1560. /* *
  1561. *
  1562. * Class
  1563. *
  1564. * */
  1565. /**
  1566. * Additions for grid axes.
  1567. * @private
  1568. * @class
  1569. */
  1570. var Additions = /** @class */ (function () {
  1571. /* *
  1572. *
  1573. * Constructors
  1574. *
  1575. * */
  1576. function Additions(axis) {
  1577. this.axis = axis;
  1578. }
  1579. /* *
  1580. *
  1581. * Functions
  1582. *
  1583. * */
  1584. /**
  1585. * Checks if an axis is the outer axis in its dimension. Since
  1586. * axes are placed outwards in order, the axis with the highest
  1587. * index is the outermost axis.
  1588. *
  1589. * Example: If there are multiple x-axes at the top of the chart,
  1590. * this function returns true if the axis supplied is the last
  1591. * of the x-axes.
  1592. *
  1593. * @private
  1594. *
  1595. * @return {boolean}
  1596. * True if the axis is the outermost axis in its dimension; false if
  1597. * not.
  1598. */
  1599. Additions.prototype.isOuterAxis = function () {
  1600. var axis = this.axis;
  1601. var chart = axis.chart;
  1602. var columnIndex = axis.grid.columnIndex;
  1603. var columns = (axis.linkedParent && axis.linkedParent.grid.columns ||
  1604. axis.grid.columns);
  1605. var parentAxis = columnIndex ? axis.linkedParent : axis;
  1606. var thisIndex = -1,
  1607. lastIndex = 0;
  1608. chart[axis.coll].forEach(function (otherAxis, index) {
  1609. if (otherAxis.side === axis.side && !otherAxis.options.isInternal) {
  1610. lastIndex = index;
  1611. if (otherAxis === parentAxis) {
  1612. // Get the index of the axis in question
  1613. thisIndex = index;
  1614. }
  1615. }
  1616. });
  1617. return (lastIndex === thisIndex &&
  1618. (isNumber(columnIndex) ? columns.length === columnIndex : true));
  1619. };
  1620. /**
  1621. * Add extra border based on the provided path.
  1622. * *
  1623. * @private
  1624. *
  1625. * @param {SVGPath} path
  1626. * The path of the border.
  1627. *
  1628. * @return {Highcharts.SVGElement}
  1629. */
  1630. Additions.prototype.renderBorder = function (path) {
  1631. var axis = this.axis,
  1632. renderer = axis.chart.renderer,
  1633. options = axis.options,
  1634. extraBorderLine = renderer.path(path)
  1635. .addClass('highcharts-axis-line')
  1636. .add(axis.axisBorder);
  1637. if (!renderer.styledMode) {
  1638. extraBorderLine.attr({
  1639. stroke: options.lineColor,
  1640. 'stroke-width': options.lineWidth,
  1641. zIndex: 7
  1642. });
  1643. }
  1644. return extraBorderLine;
  1645. };
  1646. return Additions;
  1647. }());
  1648. GridAxis.Additions = Additions;
  1649. })(GridAxis || (GridAxis = {}));
  1650. /* *
  1651. *
  1652. * Registry
  1653. *
  1654. * */
  1655. // First letter of the day of the week, e.g. 'M' for 'Monday'.
  1656. dateFormats.E = function (timestamp) {
  1657. return this.dateFormat('%a', timestamp, true).charAt(0);
  1658. };
  1659. // Adds week date format
  1660. dateFormats.W = function (timestamp) {
  1661. var d = new this.Date(timestamp);
  1662. var firstDay = (this.get('Day',
  1663. d) + 6) % 7;
  1664. var thursday = new this.Date(d.valueOf());
  1665. this.set('Date', thursday, this.get('Date', d) - firstDay + 3);
  1666. var firstThursday = new this.Date(this.get('FullYear',
  1667. thursday), 0, 1);
  1668. if (this.get('Day', firstThursday) !== 4) {
  1669. this.set('Month', d, 0);
  1670. this.set('Date', d, 1 + (11 - this.get('Day', firstThursday)) % 7);
  1671. }
  1672. return (1 +
  1673. Math.floor((thursday.valueOf() - firstThursday.valueOf()) / 604800000)).toString();
  1674. };
  1675. /* *
  1676. *
  1677. * Default Export
  1678. *
  1679. * */
  1680. /* *
  1681. *
  1682. * API Options
  1683. *
  1684. * */
  1685. /**
  1686. * @productdesc {gantt}
  1687. * For grid axes (like in Gantt charts),
  1688. * it is possible to declare as a list to provide different
  1689. * formats depending on available space.
  1690. *
  1691. * Defaults to:
  1692. * ```js
  1693. * {
  1694. * hour: { list: ['%H:%M', '%H'] },
  1695. * day: { list: ['%A, %e. %B', '%a, %e. %b', '%E'] },
  1696. * week: { list: ['Week %W', 'W%W'] },
  1697. * month: { list: ['%B', '%b', '%o'] }
  1698. * }
  1699. * ```
  1700. *
  1701. * @sample {gantt} gantt/grid-axis/date-time-label-formats
  1702. * Gantt chart with custom axis date format.
  1703. *
  1704. * @apioption xAxis.dateTimeLabelFormats
  1705. */
  1706. /**
  1707. * Set grid options for the axis labels. Requires Highcharts Gantt.
  1708. *
  1709. * @since 6.2.0
  1710. * @product gantt
  1711. * @apioption xAxis.grid
  1712. */
  1713. /**
  1714. * Enable grid on the axis labels. Defaults to true for Gantt charts.
  1715. *
  1716. * @type {boolean}
  1717. * @default true
  1718. * @since 6.2.0
  1719. * @product gantt
  1720. * @apioption xAxis.grid.enabled
  1721. */
  1722. /**
  1723. * Set specific options for each column (or row for horizontal axes) in the
  1724. * grid. Each extra column/row is its own axis, and the axis options can be set
  1725. * here.
  1726. *
  1727. * @sample gantt/demo/left-axis-table
  1728. * Left axis as a table
  1729. *
  1730. * @type {Array<Highcharts.XAxisOptions>}
  1731. * @apioption xAxis.grid.columns
  1732. */
  1733. /**
  1734. * Set border color for the label grid lines.
  1735. *
  1736. * @type {Highcharts.ColorString}
  1737. * @apioption xAxis.grid.borderColor
  1738. */
  1739. /**
  1740. * Set border width of the label grid lines.
  1741. *
  1742. * @type {number}
  1743. * @default 1
  1744. * @apioption xAxis.grid.borderWidth
  1745. */
  1746. /**
  1747. * Set cell height for grid axis labels. By default this is calculated from font
  1748. * size. This option only applies to horizontal axes.
  1749. *
  1750. * @sample gantt/grid-axis/cellheight
  1751. * Gant chart with custom cell height
  1752. * @type {number}
  1753. * @apioption xAxis.grid.cellHeight
  1754. */
  1755. ''; // keeps doclets above in JS file
  1756. return GridAxis;
  1757. });
  1758. _registerModule(_modules, 'Gantt/Tree.js', [_modules['Core/Utilities.js']], function (U) {
  1759. /* *
  1760. *
  1761. * (c) 2016-2021 Highsoft AS
  1762. *
  1763. * Authors: Jon Arild Nygard
  1764. *
  1765. * License: www.highcharts.com/license
  1766. *
  1767. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1768. *
  1769. * */
  1770. /* eslint no-console: 0 */
  1771. var extend = U.extend,
  1772. isNumber = U.isNumber,
  1773. pick = U.pick;
  1774. /**
  1775. * Creates an object map from parent id to childrens index.
  1776. *
  1777. * @private
  1778. * @function Highcharts.Tree#getListOfParents
  1779. *
  1780. * @param {Array<*>} data
  1781. * List of points set in options. `Array.parent` is parent id of point.
  1782. *
  1783. * @param {Array<string>} ids
  1784. * List of all point ids.
  1785. *
  1786. * @return {Highcharts.Dictionary<Array<*>>}
  1787. * Map from parent id to children index in data
  1788. */
  1789. var getListOfParents = function (data,
  1790. ids) {
  1791. var listOfParents = data.reduce(function (prev,
  1792. curr) {
  1793. var parent = pick(curr.parent, '');
  1794. if (typeof prev[parent] === 'undefined') {
  1795. prev[parent] = [];
  1796. }
  1797. prev[parent].push(curr);
  1798. return prev;
  1799. }, {}), parents = Object.keys(listOfParents);
  1800. // If parent does not exist, hoist parent to root of tree.
  1801. parents.forEach(function (parent, list) {
  1802. var children = listOfParents[parent];
  1803. if ((parent !== '') && (ids.indexOf(parent) === -1)) {
  1804. children.forEach(function (child) {
  1805. list[''].push(child);
  1806. });
  1807. delete list[parent];
  1808. }
  1809. });
  1810. return listOfParents;
  1811. };
  1812. var getNode = function (id,
  1813. parent,
  1814. level,
  1815. data,
  1816. mapOfIdToChildren,
  1817. options) {
  1818. var descendants = 0,
  1819. height = 0,
  1820. after = options && options.after,
  1821. before = options && options.before,
  1822. node = {
  1823. data: data,
  1824. depth: level - 1,
  1825. id: id,
  1826. level: level,
  1827. parent: parent
  1828. },
  1829. start,
  1830. end,
  1831. children;
  1832. // Allow custom logic before the children has been created.
  1833. if (typeof before === 'function') {
  1834. before(node, options);
  1835. }
  1836. // Call getNode recursively on the children. Calulate the height of the
  1837. // node, and the number of descendants.
  1838. children = ((mapOfIdToChildren[id] || [])).map(function (child) {
  1839. var node = getNode(child.id,
  1840. id, (level + 1),
  1841. child,
  1842. mapOfIdToChildren,
  1843. options),
  1844. childStart = child.start,
  1845. childEnd = (child.milestone === true ?
  1846. childStart :
  1847. child.end);
  1848. // Start should be the lowest child.start.
  1849. start = ((!isNumber(start) || childStart < start) ?
  1850. childStart :
  1851. start);
  1852. // End should be the largest child.end.
  1853. // If child is milestone, then use start as end.
  1854. end = ((!isNumber(end) || childEnd > end) ?
  1855. childEnd :
  1856. end);
  1857. descendants = descendants + 1 + node.descendants;
  1858. height = Math.max(node.height + 1, height);
  1859. return node;
  1860. });
  1861. // Calculate start and end for point if it is not already explicitly set.
  1862. if (data) {
  1863. data.start = pick(data.start, start);
  1864. data.end = pick(data.end, end);
  1865. }
  1866. extend(node, {
  1867. children: children,
  1868. descendants: descendants,
  1869. height: height
  1870. });
  1871. // Allow custom logic after the children has been created.
  1872. if (typeof after === 'function') {
  1873. after(node, options);
  1874. }
  1875. return node;
  1876. };
  1877. var getTree = function (data,
  1878. options) {
  1879. var ids = data.map(function (d) {
  1880. return d.id;
  1881. }), mapOfIdToChildren = getListOfParents(data, ids);
  1882. return getNode('', null, 1, null, mapOfIdToChildren, options);
  1883. };
  1884. var Tree = {
  1885. getListOfParents: getListOfParents,
  1886. getNode: getNode,
  1887. getTree: getTree
  1888. };
  1889. return Tree;
  1890. });
  1891. _registerModule(_modules, 'Core/Axis/TreeGridTick.js', [_modules['Core/Color/Palette.js'], _modules['Core/Utilities.js']], function (palette, U) {
  1892. /* *
  1893. *
  1894. * (c) 2016 Highsoft AS
  1895. * Authors: Jon Arild Nygard
  1896. *
  1897. * License: www.highcharts.com/license
  1898. *
  1899. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1900. *
  1901. * */
  1902. var addEvent = U.addEvent,
  1903. isObject = U.isObject,
  1904. isNumber = U.isNumber,
  1905. pick = U.pick,
  1906. wrap = U.wrap;
  1907. /* eslint-disable no-invalid-this, valid-jsdoc */
  1908. /**
  1909. * @private
  1910. */
  1911. var TreeGridTick;
  1912. (function (TreeGridTick) {
  1913. /* *
  1914. *
  1915. * Interfaces
  1916. *
  1917. * */
  1918. /* *
  1919. *
  1920. * Variables
  1921. *
  1922. * */
  1923. var applied = false;
  1924. /* *
  1925. *
  1926. * Functions
  1927. *
  1928. * */
  1929. /**
  1930. * @private
  1931. */
  1932. function compose(TickClass) {
  1933. if (!applied) {
  1934. addEvent(TickClass, 'init', onInit);
  1935. wrap(TickClass.prototype, 'getLabelPosition', wrapGetLabelPosition);
  1936. wrap(TickClass.prototype, 'renderLabel', wrapRenderLabel);
  1937. // backwards compatibility
  1938. TickClass.prototype.collapse = function (redraw) {
  1939. this.treeGrid.collapse(redraw);
  1940. };
  1941. TickClass.prototype.expand = function (redraw) {
  1942. this.treeGrid.expand(redraw);
  1943. };
  1944. TickClass.prototype.toggleCollapse = function (redraw) {
  1945. this.treeGrid.toggleCollapse(redraw);
  1946. };
  1947. applied = true;
  1948. }
  1949. }
  1950. TreeGridTick.compose = compose;
  1951. /**
  1952. * @private
  1953. */
  1954. function onInit() {
  1955. var tick = this;
  1956. if (!tick.treeGrid) {
  1957. tick.treeGrid = new Additions(tick);
  1958. }
  1959. }
  1960. /**
  1961. * @private
  1962. */
  1963. function onTickHover(label) {
  1964. label.addClass('highcharts-treegrid-node-active');
  1965. if (!label.renderer.styledMode) {
  1966. label.css({
  1967. textDecoration: 'underline'
  1968. });
  1969. }
  1970. }
  1971. /**
  1972. * @private
  1973. */
  1974. function onTickHoverExit(label, options) {
  1975. var css = isObject(options.style) ? options.style : {};
  1976. label.removeClass('highcharts-treegrid-node-active');
  1977. if (!label.renderer.styledMode) {
  1978. label.css({ textDecoration: css.textDecoration });
  1979. }
  1980. }
  1981. /**
  1982. * @private
  1983. */
  1984. function renderLabelIcon(tick, params) {
  1985. var treeGrid = tick.treeGrid,
  1986. isNew = !treeGrid.labelIcon,
  1987. renderer = params.renderer,
  1988. labelBox = params.xy,
  1989. options = params.options,
  1990. width = options.width || 0,
  1991. height = options.height || 0,
  1992. iconCenter = {
  1993. x: labelBox.x - (width / 2) - (options.padding || 0),
  1994. y: labelBox.y - (height / 2)
  1995. },
  1996. rotation = params.collapsed ? 90 : 180,
  1997. shouldRender = params.show && isNumber(iconCenter.y);
  1998. var icon = treeGrid.labelIcon;
  1999. if (!icon) {
  2000. treeGrid.labelIcon = icon = renderer
  2001. .path(renderer.symbols[options.type](options.x || 0, options.y || 0, width, height))
  2002. .addClass('highcharts-label-icon')
  2003. .add(params.group);
  2004. }
  2005. // Set the new position, and show or hide
  2006. icon.attr({ y: shouldRender ? 0 : -9999 }); // #14904, #1338
  2007. // Presentational attributes
  2008. if (!renderer.styledMode) {
  2009. icon
  2010. .attr({
  2011. cursor: 'pointer',
  2012. 'fill': pick(params.color, palette.neutralColor60),
  2013. 'stroke-width': 1,
  2014. stroke: options.lineColor,
  2015. strokeWidth: options.lineWidth || 0
  2016. });
  2017. }
  2018. // Update the icon positions
  2019. icon[isNew ? 'attr' : 'animate']({
  2020. translateX: iconCenter.x,
  2021. translateY: iconCenter.y,
  2022. rotation: rotation
  2023. });
  2024. }
  2025. /**
  2026. * @private
  2027. */
  2028. function wrapGetLabelPosition(proceed, x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
  2029. var tick = this,
  2030. lbOptions = pick(tick.options && tick.options.labels,
  2031. labelOptions),
  2032. pos = tick.pos,
  2033. axis = tick.axis,
  2034. options = axis.options,
  2035. isTreeGrid = options.type === 'treegrid',
  2036. result = proceed.apply(tick,
  2037. [x,
  2038. y,
  2039. label,
  2040. horiz,
  2041. lbOptions,
  2042. tickmarkOffset,
  2043. index,
  2044. step]);
  2045. var symbolOptions,
  2046. indentation,
  2047. mapOfPosToGridNode,
  2048. node,
  2049. level;
  2050. if (isTreeGrid) {
  2051. symbolOptions = (lbOptions && isObject(lbOptions.symbol, true) ?
  2052. lbOptions.symbol :
  2053. {});
  2054. indentation = (lbOptions && isNumber(lbOptions.indentation) ?
  2055. lbOptions.indentation :
  2056. 0);
  2057. mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode;
  2058. node = mapOfPosToGridNode && mapOfPosToGridNode[pos];
  2059. level = (node && node.depth) || 1;
  2060. result.x += (
  2061. // Add space for symbols
  2062. ((symbolOptions.width || 0) +
  2063. ((symbolOptions.padding || 0) * 2)) +
  2064. // Apply indentation
  2065. ((level - 1) * indentation));
  2066. }
  2067. return result;
  2068. }
  2069. /**
  2070. * @private
  2071. */
  2072. function wrapRenderLabel(proceed) {
  2073. var tick = this, pos = tick.pos, axis = tick.axis, label = tick.label, mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode, options = axis.options, labelOptions = pick(tick.options && tick.options.labels, options && options.labels), symbolOptions = (labelOptions && isObject(labelOptions.symbol, true) ?
  2074. labelOptions.symbol :
  2075. {}), node = mapOfPosToGridNode && mapOfPosToGridNode[pos], level = node && node.depth, isTreeGrid = options.type === 'treegrid', shouldRender = axis.tickPositions.indexOf(pos) > -1, prefixClassName = 'highcharts-treegrid-node-', styledMode = axis.chart.styledMode;
  2076. var collapsed,
  2077. addClassName,
  2078. removeClassName;
  2079. if (isTreeGrid && node) {
  2080. // Add class name for hierarchical styling.
  2081. if (label &&
  2082. label.element) {
  2083. label.addClass(prefixClassName + 'level-' + level);
  2084. }
  2085. }
  2086. proceed.apply(tick, Array.prototype.slice.call(arguments, 1));
  2087. if (isTreeGrid &&
  2088. label &&
  2089. label.element &&
  2090. node &&
  2091. node.descendants &&
  2092. node.descendants > 0) {
  2093. collapsed = axis.treeGrid.isCollapsed(node);
  2094. renderLabelIcon(tick, {
  2095. color: !styledMode && label.styles && label.styles.color || '',
  2096. collapsed: collapsed,
  2097. group: label.parentGroup,
  2098. options: symbolOptions,
  2099. renderer: label.renderer,
  2100. show: shouldRender,
  2101. xy: label.xy
  2102. });
  2103. // Add class name for the node.
  2104. addClassName = prefixClassName +
  2105. (collapsed ? 'collapsed' : 'expanded');
  2106. removeClassName = prefixClassName +
  2107. (collapsed ? 'expanded' : 'collapsed');
  2108. label
  2109. .addClass(addClassName)
  2110. .removeClass(removeClassName);
  2111. if (!styledMode) {
  2112. label.css({
  2113. cursor: 'pointer'
  2114. });
  2115. }
  2116. // Add events to both label text and icon
  2117. [label, tick.treeGrid.labelIcon].forEach(function (object) {
  2118. if (object && !object.attachedTreeGridEvents) {
  2119. // On hover
  2120. addEvent(object.element, 'mouseover', function () {
  2121. onTickHover(label);
  2122. });
  2123. // On hover out
  2124. addEvent(object.element, 'mouseout', function () {
  2125. onTickHoverExit(label, labelOptions);
  2126. });
  2127. addEvent(object.element, 'click', function () {
  2128. tick.treeGrid.toggleCollapse();
  2129. });
  2130. object.attachedTreeGridEvents = true;
  2131. }
  2132. });
  2133. }
  2134. }
  2135. /* *
  2136. *
  2137. * Classes
  2138. *
  2139. * */
  2140. /**
  2141. * @private
  2142. * @class
  2143. */
  2144. var Additions = /** @class */ (function () {
  2145. /* *
  2146. *
  2147. * Constructors
  2148. *
  2149. * */
  2150. /**
  2151. * @private
  2152. */
  2153. function Additions(tick) {
  2154. this.tick = tick;
  2155. }
  2156. /* *
  2157. *
  2158. * Functions
  2159. *
  2160. * */
  2161. /**
  2162. * Collapse the grid cell. Used when axis is of type treegrid.
  2163. *
  2164. * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
  2165. *
  2166. * @private
  2167. * @function Highcharts.Tick#collapse
  2168. *
  2169. * @param {boolean} [redraw=true]
  2170. * Whether to redraw the chart or wait for an explicit call to
  2171. * {@link Highcharts.Chart#redraw}
  2172. */
  2173. Additions.prototype.collapse = function (redraw) {
  2174. var tick = this.tick,
  2175. axis = tick.axis,
  2176. brokenAxis = axis.brokenAxis;
  2177. if (brokenAxis &&
  2178. axis.treeGrid.mapOfPosToGridNode) {
  2179. var pos = tick.pos,
  2180. node = axis.treeGrid.mapOfPosToGridNode[pos],
  2181. breaks = axis.treeGrid.collapse(node);
  2182. brokenAxis.setBreaks(breaks, pick(redraw, true));
  2183. }
  2184. };
  2185. /**
  2186. * Expand the grid cell. Used when axis is of type treegrid.
  2187. *
  2188. * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
  2189. *
  2190. * @private
  2191. * @function Highcharts.Tick#expand
  2192. *
  2193. * @param {boolean} [redraw=true]
  2194. * Whether to redraw the chart or wait for an explicit call to
  2195. * {@link Highcharts.Chart#redraw}
  2196. */
  2197. Additions.prototype.expand = function (redraw) {
  2198. var tick = this.tick,
  2199. axis = tick.axis,
  2200. brokenAxis = axis.brokenAxis;
  2201. if (brokenAxis &&
  2202. axis.treeGrid.mapOfPosToGridNode) {
  2203. var pos = tick.pos,
  2204. node = axis.treeGrid.mapOfPosToGridNode[pos],
  2205. breaks = axis.treeGrid.expand(node);
  2206. brokenAxis.setBreaks(breaks, pick(redraw, true));
  2207. }
  2208. };
  2209. /**
  2210. * Toggle the collapse/expand state of the grid cell. Used when axis is
  2211. * of type treegrid.
  2212. *
  2213. * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
  2214. *
  2215. * @private
  2216. * @function Highcharts.Tick#toggleCollapse
  2217. *
  2218. * @param {boolean} [redraw=true]
  2219. * Whether to redraw the chart or wait for an explicit call to
  2220. * {@link Highcharts.Chart#redraw}
  2221. */
  2222. Additions.prototype.toggleCollapse = function (redraw) {
  2223. var tick = this.tick,
  2224. axis = tick.axis,
  2225. brokenAxis = axis.brokenAxis;
  2226. if (brokenAxis &&
  2227. axis.treeGrid.mapOfPosToGridNode) {
  2228. var pos = tick.pos,
  2229. node = axis.treeGrid.mapOfPosToGridNode[pos],
  2230. breaks = axis.treeGrid.toggleCollapse(node);
  2231. brokenAxis.setBreaks(breaks, pick(redraw, true));
  2232. }
  2233. };
  2234. return Additions;
  2235. }());
  2236. TreeGridTick.Additions = Additions;
  2237. })(TreeGridTick || (TreeGridTick = {}));
  2238. return TreeGridTick;
  2239. });
  2240. _registerModule(_modules, 'Mixins/TreeSeries.js', [_modules['Core/Color/Color.js'], _modules['Core/Utilities.js']], function (Color, U) {
  2241. /* *
  2242. *
  2243. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2244. *
  2245. * */
  2246. var extend = U.extend,
  2247. isArray = U.isArray,
  2248. isNumber = U.isNumber,
  2249. isObject = U.isObject,
  2250. merge = U.merge,
  2251. pick = U.pick;
  2252. var isBoolean = function (x) {
  2253. return typeof x === 'boolean';
  2254. }, isFn = function (x) {
  2255. return typeof x === 'function';
  2256. };
  2257. /* eslint-disable valid-jsdoc */
  2258. /**
  2259. * @todo Combine buildTree and buildNode with setTreeValues
  2260. * @todo Remove logic from Treemap and make it utilize this mixin.
  2261. * @private
  2262. */
  2263. var setTreeValues = function setTreeValues(tree,
  2264. options) {
  2265. var before = options.before,
  2266. idRoot = options.idRoot,
  2267. mapIdToNode = options.mapIdToNode,
  2268. nodeRoot = mapIdToNode[idRoot],
  2269. levelIsConstant = (isBoolean(options.levelIsConstant) ?
  2270. options.levelIsConstant :
  2271. true),
  2272. points = options.points,
  2273. point = points[tree.i],
  2274. optionsPoint = point && point.options || {},
  2275. childrenTotal = 0,
  2276. children = [],
  2277. value;
  2278. tree.levelDynamic = tree.level - (levelIsConstant ? 0 : nodeRoot.level);
  2279. tree.name = pick(point && point.name, '');
  2280. tree.visible = (idRoot === tree.id ||
  2281. (isBoolean(options.visible) ? options.visible : false));
  2282. if (isFn(before)) {
  2283. tree = before(tree, options);
  2284. }
  2285. // First give the children some values
  2286. tree.children.forEach(function (child, i) {
  2287. var newOptions = extend({},
  2288. options);
  2289. extend(newOptions, {
  2290. index: i,
  2291. siblings: tree.children.length,
  2292. visible: tree.visible
  2293. });
  2294. child = setTreeValues(child, newOptions);
  2295. children.push(child);
  2296. if (child.visible) {
  2297. childrenTotal += child.val;
  2298. }
  2299. });
  2300. tree.visible = childrenTotal > 0 || tree.visible;
  2301. // Set the values
  2302. value = pick(optionsPoint.value, childrenTotal);
  2303. tree.children = children;
  2304. tree.childrenTotal = childrenTotal;
  2305. tree.isLeaf = tree.visible && !childrenTotal;
  2306. tree.val = value;
  2307. return tree;
  2308. };
  2309. /**
  2310. * @private
  2311. */
  2312. var getColor = function getColor(node,
  2313. options) {
  2314. var index = options.index,
  2315. mapOptionsToLevel = options.mapOptionsToLevel,
  2316. parentColor = options.parentColor,
  2317. parentColorIndex = options.parentColorIndex,
  2318. series = options.series,
  2319. colors = options.colors,
  2320. siblings = options.siblings,
  2321. points = series.points,
  2322. getColorByPoint,
  2323. chartOptionsChart = series.chart.options.chart,
  2324. point,
  2325. level,
  2326. colorByPoint,
  2327. colorIndexByPoint,
  2328. color,
  2329. colorIndex;
  2330. /**
  2331. * @private
  2332. */
  2333. function variation(color) {
  2334. var colorVariation = level && level.colorVariation;
  2335. if (colorVariation) {
  2336. if (colorVariation.key === 'brightness') {
  2337. return Color.parse(color).brighten(colorVariation.to * (index / siblings)).get();
  2338. }
  2339. }
  2340. return color;
  2341. }
  2342. if (node) {
  2343. point = points[node.i];
  2344. level = mapOptionsToLevel[node.level] || {};
  2345. getColorByPoint = point && level.colorByPoint;
  2346. if (getColorByPoint) {
  2347. colorIndexByPoint = point.index % (colors ?
  2348. colors.length :
  2349. chartOptionsChart.colorCount);
  2350. colorByPoint = colors && colors[colorIndexByPoint];
  2351. }
  2352. // Select either point color, level color or inherited color.
  2353. if (!series.chart.styledMode) {
  2354. color = pick(point && point.options.color, level && level.color, colorByPoint, parentColor && variation(parentColor), series.color);
  2355. }
  2356. colorIndex = pick(point && point.options.colorIndex, level && level.colorIndex, colorIndexByPoint, parentColorIndex, options.colorIndex);
  2357. }
  2358. return {
  2359. color: color,
  2360. colorIndex: colorIndex
  2361. };
  2362. };
  2363. /**
  2364. * Creates a map from level number to its given options.
  2365. *
  2366. * @private
  2367. * @function getLevelOptions
  2368. * @param {object} params
  2369. * Object containing parameters.
  2370. * - `defaults` Object containing default options. The default options
  2371. * are merged with the userOptions to get the final options for a
  2372. * specific level.
  2373. * - `from` The lowest level number.
  2374. * - `levels` User options from series.levels.
  2375. * - `to` The highest level number.
  2376. * @return {Highcharts.Dictionary<object>|null}
  2377. * Returns a map from level number to its given options.
  2378. */
  2379. var getLevelOptions = function getLevelOptions(params) {
  2380. var result = null,
  2381. defaults,
  2382. converted,
  2383. i,
  2384. from,
  2385. to,
  2386. levels;
  2387. if (isObject(params)) {
  2388. result = {};
  2389. from = isNumber(params.from) ? params.from : 1;
  2390. levels = params.levels;
  2391. converted = {};
  2392. defaults = isObject(params.defaults) ? params.defaults : {};
  2393. if (isArray(levels)) {
  2394. converted = levels.reduce(function (obj, item) {
  2395. var level,
  2396. levelIsConstant,
  2397. options;
  2398. if (isObject(item) && isNumber(item.level)) {
  2399. options = merge({}, item);
  2400. levelIsConstant = (isBoolean(options.levelIsConstant) ?
  2401. options.levelIsConstant :
  2402. defaults.levelIsConstant);
  2403. // Delete redundant properties.
  2404. delete options.levelIsConstant;
  2405. delete options.level;
  2406. // Calculate which level these options apply to.
  2407. level = item.level + (levelIsConstant ? 0 : from - 1);
  2408. if (isObject(obj[level])) {
  2409. extend(obj[level], options);
  2410. }
  2411. else {
  2412. obj[level] = options;
  2413. }
  2414. }
  2415. return obj;
  2416. }, {});
  2417. }
  2418. to = isNumber(params.to) ? params.to : 1;
  2419. for (i = 0; i <= to; i++) {
  2420. result[i] = merge({}, defaults, isObject(converted[i]) ? converted[i] : {});
  2421. }
  2422. }
  2423. return result;
  2424. };
  2425. /**
  2426. * Update the rootId property on the series. Also makes sure that it is
  2427. * accessible to exporting.
  2428. *
  2429. * @private
  2430. * @function updateRootId
  2431. *
  2432. * @param {object} series
  2433. * The series to operate on.
  2434. *
  2435. * @return {string}
  2436. * Returns the resulting rootId after update.
  2437. */
  2438. var updateRootId = function (series) {
  2439. var rootId,
  2440. options;
  2441. if (isObject(series)) {
  2442. // Get the series options.
  2443. options = isObject(series.options) ? series.options : {};
  2444. // Calculate the rootId.
  2445. rootId = pick(series.rootNode, options.rootId, '');
  2446. // Set rootId on series.userOptions to pick it up in exporting.
  2447. if (isObject(series.userOptions)) {
  2448. series.userOptions.rootId = rootId;
  2449. }
  2450. // Set rootId on series to pick it up on next update.
  2451. series.rootNode = rootId;
  2452. }
  2453. return rootId;
  2454. };
  2455. var result = {
  2456. getColor: getColor,
  2457. getLevelOptions: getLevelOptions,
  2458. setTreeValues: setTreeValues,
  2459. updateRootId: updateRootId
  2460. };
  2461. return result;
  2462. });
  2463. _registerModule(_modules, 'Core/Axis/TreeGridAxis.js', [_modules['Core/Axis/BrokenAxis.js'], _modules['Core/Axis/GridAxis.js'], _modules['Gantt/Tree.js'], _modules['Core/Axis/TreeGridTick.js'], _modules['Mixins/TreeSeries.js'], _modules['Core/Utilities.js']], function (BrokenAxis, GridAxis, Tree, TreeGridTick, mixinTreeSeries, U) {
  2464. /* *
  2465. *
  2466. * (c) 2016 Highsoft AS
  2467. * Authors: Jon Arild Nygard
  2468. *
  2469. * License: www.highcharts.com/license
  2470. *
  2471. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2472. *
  2473. * */
  2474. var getLevelOptions = mixinTreeSeries.getLevelOptions;
  2475. var addEvent = U.addEvent,
  2476. find = U.find,
  2477. fireEvent = U.fireEvent,
  2478. isArray = U.isArray,
  2479. isObject = U.isObject,
  2480. isString = U.isString,
  2481. merge = U.merge,
  2482. pick = U.pick,
  2483. wrap = U.wrap;
  2484. /**
  2485. * @private
  2486. */
  2487. var TreeGridAxis;
  2488. (function (TreeGridAxis) {
  2489. /* *
  2490. *
  2491. * Declarations
  2492. *
  2493. * */
  2494. /* *
  2495. *
  2496. * Variables
  2497. *
  2498. * */
  2499. var TickConstructor;
  2500. /* *
  2501. *
  2502. * Functions
  2503. *
  2504. * */
  2505. /**
  2506. * @private
  2507. */
  2508. function compose(AxisClass, ChartClass, SeriesClass, TickClass) {
  2509. if (AxisClass.keepProps.indexOf('treeGrid') === -1) {
  2510. AxisClass.keepProps.push('treeGrid');
  2511. TickConstructor = TickClass;
  2512. wrap(AxisClass.prototype, 'generateTick', wrapGenerateTick);
  2513. wrap(AxisClass.prototype, 'init', wrapInit);
  2514. wrap(AxisClass.prototype, 'setTickInterval', wrapSetTickInterval);
  2515. // Make utility functions available for testing.
  2516. AxisClass.prototype.utils = {
  2517. getNode: Tree.getNode
  2518. };
  2519. GridAxis.compose(AxisClass, ChartClass, TickClass);
  2520. BrokenAxis.compose(AxisClass, SeriesClass);
  2521. TreeGridTick.compose(TickClass);
  2522. }
  2523. return AxisClass;
  2524. }
  2525. TreeGridAxis.compose = compose;
  2526. /**
  2527. * @private
  2528. */
  2529. function getBreakFromNode(node, max) {
  2530. var to = node.collapseEnd || 0;
  2531. var from = node.collapseStart || 0;
  2532. // In broken-axis, the axis.max is minimized until it is not within a
  2533. // break. Therefore, if break.to is larger than axis.max, the axis.to
  2534. // should not add the 0.5 axis.tickMarkOffset, to avoid adding a break
  2535. // larger than axis.max.
  2536. // TODO consider simplifying broken-axis and this might solve itself
  2537. if (to >= max) {
  2538. from -= 0.5;
  2539. }
  2540. return {
  2541. from: from,
  2542. to: to,
  2543. showPoints: false
  2544. };
  2545. }
  2546. /**
  2547. * Creates a tree structure of the data, and the treegrid. Calculates
  2548. * categories, and y-values of points based on the tree.
  2549. *
  2550. * @private
  2551. * @function getTreeGridFromData
  2552. *
  2553. * @param {Array<Highcharts.GanttPointOptions>} data
  2554. * All the data points to display in the axis.
  2555. *
  2556. * @param {boolean} uniqueNames
  2557. * Wether or not the data node with the same name should share grid cell. If
  2558. * true they do share cell. False by default.
  2559. *
  2560. * @param {number} numberOfSeries
  2561. *
  2562. * @return {object}
  2563. * Returns an object containing categories, mapOfIdToNode,
  2564. * mapOfPosToGridNode, and tree.
  2565. *
  2566. * @todo There should be only one point per line.
  2567. * @todo It should be optional to have one category per point, or merge
  2568. * cells
  2569. * @todo Add unit-tests.
  2570. */
  2571. function getTreeGridFromData(data, uniqueNames, numberOfSeries) {
  2572. var categories = [],
  2573. collapsedNodes = [],
  2574. mapOfIdToNode = {},
  2575. uniqueNamesEnabled = typeof uniqueNames === 'boolean' ? uniqueNames : false;
  2576. var mapOfPosToGridNode = {},
  2577. posIterator = -1;
  2578. // Build the tree from the series data.
  2579. var treeParams = {
  2580. // After the children has been created.
  2581. after: function (node) {
  2582. var gridNode = mapOfPosToGridNode[node.pos];
  2583. var height = 0,
  2584. descendants = 0;
  2585. gridNode.children.forEach(function (child) {
  2586. descendants += (child.descendants || 0) + 1;
  2587. height = Math.max((child.height || 0) + 1, height);
  2588. });
  2589. gridNode.descendants = descendants;
  2590. gridNode.height = height;
  2591. if (gridNode.collapsed) {
  2592. collapsedNodes.push(gridNode);
  2593. }
  2594. },
  2595. // Before the children has been created.
  2596. before: function (node) {
  2597. var data = isObject(node.data,
  2598. true) ? node.data : {},
  2599. name = isString(data.name) ? data.name : '',
  2600. parentNode = mapOfIdToNode[node.parent],
  2601. parentGridNode = (isObject(parentNode,
  2602. true) ?
  2603. mapOfPosToGridNode[parentNode.pos] :
  2604. null),
  2605. hasSameName = function (x) {
  2606. return x.name === name;
  2607. };
  2608. var gridNode,
  2609. pos;
  2610. // If not unique names, look for sibling node with the same name
  2611. if (uniqueNamesEnabled &&
  2612. isObject(parentGridNode, true) &&
  2613. !!(gridNode = find(parentGridNode.children, hasSameName))) {
  2614. // If there is a gridNode with the same name, reuse position
  2615. pos = gridNode.pos;
  2616. // Add data node to list of nodes in the grid node.
  2617. gridNode.nodes.push(node);
  2618. }
  2619. else {
  2620. // If it is a new grid node, increment position.
  2621. pos = posIterator++;
  2622. }
  2623. // Add new grid node to map.
  2624. if (!mapOfPosToGridNode[pos]) {
  2625. mapOfPosToGridNode[pos] = gridNode = {
  2626. depth: parentGridNode ? parentGridNode.depth + 1 : 0,
  2627. name: name,
  2628. id: data.id,
  2629. nodes: [node],
  2630. children: [],
  2631. pos: pos
  2632. };
  2633. // If not root, then add name to categories.
  2634. if (pos !== -1) {
  2635. categories.push(name);
  2636. }
  2637. // Add name to list of children.
  2638. if (isObject(parentGridNode, true)) {
  2639. parentGridNode.children.push(gridNode);
  2640. }
  2641. }
  2642. // Add data node to map
  2643. if (isString(node.id)) {
  2644. mapOfIdToNode[node.id] = node;
  2645. }
  2646. // If one of the points are collapsed, then start the grid node
  2647. // in collapsed state.
  2648. if (gridNode &&
  2649. data.collapsed === true) {
  2650. gridNode.collapsed = true;
  2651. }
  2652. // Assign pos to data node
  2653. node.pos = pos;
  2654. }
  2655. };
  2656. var updateYValuesAndTickPos = function (map,
  2657. numberOfSeries) {
  2658. var setValues = function (gridNode,
  2659. start,
  2660. result) {
  2661. var nodes = gridNode.nodes,
  2662. padding = 0.5;
  2663. var end = start + (start === -1 ? 0 : numberOfSeries - 1);
  2664. var diff = (end - start) / 2,
  2665. pos = start + diff;
  2666. nodes.forEach(function (node) {
  2667. var data = node.data;
  2668. if (isObject(data, true)) {
  2669. // Update point
  2670. data.y = start + (data.seriesIndex || 0);
  2671. // Remove the property once used
  2672. delete data.seriesIndex;
  2673. }
  2674. node.pos = pos;
  2675. });
  2676. result[pos] = gridNode;
  2677. gridNode.pos = pos;
  2678. gridNode.tickmarkOffset = diff + padding;
  2679. gridNode.collapseStart = end + padding;
  2680. gridNode.children.forEach(function (child) {
  2681. setValues(child, end + 1, result);
  2682. end = (child.collapseEnd || 0) - padding;
  2683. });
  2684. // Set collapseEnd to the end of the last child node.
  2685. gridNode.collapseEnd = end + padding;
  2686. return result;
  2687. };
  2688. return setValues(map['-1'], -1, {});
  2689. };
  2690. // Create tree from data
  2691. var tree = Tree.getTree(data,
  2692. treeParams);
  2693. // Update y values of data, and set calculate tick positions.
  2694. mapOfPosToGridNode = updateYValuesAndTickPos(mapOfPosToGridNode, numberOfSeries);
  2695. // Return the resulting data.
  2696. return {
  2697. categories: categories,
  2698. mapOfIdToNode: mapOfIdToNode,
  2699. mapOfPosToGridNode: mapOfPosToGridNode,
  2700. collapsedNodes: collapsedNodes,
  2701. tree: tree
  2702. };
  2703. }
  2704. /**
  2705. * Builds the tree of categories and calculates its positions.
  2706. * @private
  2707. * @param {object} e Event object
  2708. * @param {object} e.target The chart instance which the event was fired on.
  2709. * @param {object[]} e.target.axes The axes of the chart.
  2710. */
  2711. function onBeforeRender(e) {
  2712. var chart = e.target,
  2713. axes = chart.axes;
  2714. axes.filter(function (axis) {
  2715. return axis.options.type === 'treegrid';
  2716. }).forEach(function (axis) {
  2717. var options = axis.options || {},
  2718. labelOptions = options.labels,
  2719. uniqueNames = options.uniqueNames,
  2720. max = options.max,
  2721. // Check whether any of series is rendering for the first
  2722. // time, visibility has changed, or its data is dirty, and
  2723. // only then update. #10570, #10580
  2724. // Also check if mapOfPosToGridNode exists. #10887
  2725. isDirty = (!axis.treeGrid.mapOfPosToGridNode ||
  2726. axis.series.some(function (series) {
  2727. return !series.hasRendered ||
  2728. series.isDirtyData ||
  2729. series.isDirty;
  2730. }));
  2731. var numberOfSeries = 0,
  2732. data,
  2733. treeGrid;
  2734. if (isDirty) {
  2735. // Concatenate data from all series assigned to this axis.
  2736. data = axis.series.reduce(function (arr, s) {
  2737. if (s.visible) {
  2738. // Push all data to array
  2739. (s.options.data || []).forEach(function (data) {
  2740. // For using keys - rebuild the data structure
  2741. if (s.options.keys && s.options.keys.length) {
  2742. data = s.pointClass.prototype.optionsToObject.call({ series: s }, data);
  2743. s.pointClass.setGanttPointAliases(data);
  2744. }
  2745. if (isObject(data, true)) {
  2746. // Set series index on data. Removed again
  2747. // after use.
  2748. data.seriesIndex = numberOfSeries;
  2749. arr.push(data);
  2750. }
  2751. });
  2752. // Increment series index
  2753. if (uniqueNames === true) {
  2754. numberOfSeries++;
  2755. }
  2756. }
  2757. return arr;
  2758. }, []);
  2759. // If max is higher than set data - add a
  2760. // dummy data to render categories #10779
  2761. if (max && data.length < max) {
  2762. for (var i = data.length; i <= max; i++) {
  2763. data.push({
  2764. // Use the zero-width character
  2765. // to avoid conflict with uniqueNames
  2766. name: i + '\u200B'
  2767. });
  2768. }
  2769. }
  2770. // setScale is fired after all the series is initialized,
  2771. // which is an ideal time to update the axis.categories.
  2772. treeGrid = getTreeGridFromData(data, uniqueNames || false, (uniqueNames === true) ? numberOfSeries : 1);
  2773. // Assign values to the axis.
  2774. axis.categories = treeGrid.categories;
  2775. axis.treeGrid.mapOfPosToGridNode = treeGrid.mapOfPosToGridNode;
  2776. axis.hasNames = true;
  2777. axis.treeGrid.tree = treeGrid.tree;
  2778. // Update yData now that we have calculated the y values
  2779. axis.series.forEach(function (series) {
  2780. var axisData = (series.options.data || []).map(function (d) {
  2781. if (isArray(d) && series.options.keys && series.options.keys.length) {
  2782. // Get the axisData from the data array used to
  2783. // build the treeGrid where has been modified
  2784. data.forEach(function (point) {
  2785. if (d.indexOf(point.x) >= 0 && d.indexOf(point.x2) >= 0) {
  2786. d = point;
  2787. }
  2788. });
  2789. }
  2790. return isObject(d, true) ? merge(d) : d;
  2791. });
  2792. // Avoid destroying points when series is not visible
  2793. if (series.visible) {
  2794. series.setData(axisData, false);
  2795. }
  2796. });
  2797. // Calculate the label options for each level in the tree.
  2798. axis.treeGrid.mapOptionsToLevel =
  2799. getLevelOptions({
  2800. defaults: labelOptions,
  2801. from: 1,
  2802. levels: labelOptions && labelOptions.levels,
  2803. to: axis.treeGrid.tree && axis.treeGrid.tree.height
  2804. });
  2805. // Setting initial collapsed nodes
  2806. if (e.type === 'beforeRender') {
  2807. axis.treeGrid.collapsedNodes = treeGrid.collapsedNodes;
  2808. }
  2809. }
  2810. });
  2811. }
  2812. /**
  2813. * Generates a tick for initial positioning.
  2814. *
  2815. * @private
  2816. * @function Highcharts.GridAxis#generateTick
  2817. *
  2818. * @param {Function} proceed
  2819. * The original generateTick function.
  2820. *
  2821. * @param {number} pos
  2822. * The tick position in axis values.
  2823. */
  2824. function wrapGenerateTick(proceed, pos) {
  2825. var axis = this,
  2826. mapOptionsToLevel = axis.treeGrid.mapOptionsToLevel || {},
  2827. isTreeGrid = axis.options.type === 'treegrid',
  2828. ticks = axis.ticks;
  2829. var tick = ticks[pos],
  2830. levelOptions,
  2831. options,
  2832. gridNode;
  2833. if (isTreeGrid &&
  2834. axis.treeGrid.mapOfPosToGridNode) {
  2835. gridNode = axis.treeGrid.mapOfPosToGridNode[pos];
  2836. levelOptions = mapOptionsToLevel[gridNode.depth];
  2837. if (levelOptions) {
  2838. options = {
  2839. labels: levelOptions
  2840. };
  2841. }
  2842. if (!tick &&
  2843. TickConstructor) {
  2844. ticks[pos] = tick =
  2845. new TickConstructor(axis, pos, void 0, void 0, {
  2846. category: gridNode.name,
  2847. tickmarkOffset: gridNode.tickmarkOffset,
  2848. options: options
  2849. });
  2850. }
  2851. else {
  2852. // update labels depending on tick interval
  2853. tick.parameters.category = gridNode.name;
  2854. tick.options = options;
  2855. tick.addLabel();
  2856. }
  2857. }
  2858. else {
  2859. proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  2860. }
  2861. }
  2862. /**
  2863. * @private
  2864. */
  2865. function wrapInit(proceed, chart, userOptions) {
  2866. var axis = this,
  2867. isTreeGrid = userOptions.type === 'treegrid';
  2868. if (!axis.treeGrid) {
  2869. axis.treeGrid = new Additions(axis);
  2870. }
  2871. // Set default and forced options for TreeGrid
  2872. if (isTreeGrid) {
  2873. // Add event for updating the categories of a treegrid.
  2874. // NOTE Preferably these events should be set on the axis.
  2875. addEvent(chart, 'beforeRender', onBeforeRender);
  2876. addEvent(chart, 'beforeRedraw', onBeforeRender);
  2877. // Add new collapsed nodes on addseries
  2878. addEvent(chart, 'addSeries', function (e) {
  2879. if (e.options.data) {
  2880. var treeGrid = getTreeGridFromData(e.options.data,
  2881. userOptions.uniqueNames || false, 1);
  2882. axis.treeGrid.collapsedNodes = (axis.treeGrid.collapsedNodes || []).concat(treeGrid.collapsedNodes);
  2883. }
  2884. });
  2885. // Collapse all nodes in axis.treegrid.collapsednodes
  2886. // where collapsed equals true.
  2887. addEvent(axis, 'foundExtremes', function () {
  2888. if (axis.treeGrid.collapsedNodes) {
  2889. axis.treeGrid.collapsedNodes.forEach(function (node) {
  2890. var breaks = axis.treeGrid.collapse(node);
  2891. if (axis.brokenAxis) {
  2892. axis.brokenAxis.setBreaks(breaks, false);
  2893. // remove the node from the axis collapsedNodes
  2894. if (axis.treeGrid.collapsedNodes) {
  2895. axis.treeGrid.collapsedNodes = axis.treeGrid.collapsedNodes.filter(function (n) {
  2896. return node.collapseStart !== n.collapseStart ||
  2897. node.collapseEnd !== n.collapseEnd;
  2898. });
  2899. }
  2900. }
  2901. });
  2902. }
  2903. });
  2904. // If staticScale is not defined on the yAxis
  2905. // and chart height is set, set axis.isDirty
  2906. // to ensure collapsing works (#12012)
  2907. addEvent(axis, 'afterBreaks', function () {
  2908. if (axis.coll === 'yAxis' &&
  2909. !axis.staticScale &&
  2910. axis.chart.options.chart.height) {
  2911. axis.isDirty = true;
  2912. }
  2913. });
  2914. userOptions = merge({
  2915. // Default options
  2916. grid: {
  2917. enabled: true
  2918. },
  2919. // TODO: add support for align in treegrid.
  2920. labels: {
  2921. align: 'left',
  2922. /**
  2923. * Set options on specific levels in a tree grid axis. Takes
  2924. * precedence over labels options.
  2925. *
  2926. * @sample {gantt} gantt/treegrid-axis/labels-levels
  2927. * Levels on TreeGrid Labels
  2928. *
  2929. * @type {Array<*>}
  2930. * @product gantt
  2931. * @apioption yAxis.labels.levels
  2932. *
  2933. * @private
  2934. */
  2935. levels: [{
  2936. /**
  2937. * Specify the level which the options within this object
  2938. * applies to.
  2939. *
  2940. * @type {number}
  2941. * @product gantt
  2942. * @apioption yAxis.labels.levels.level
  2943. *
  2944. * @private
  2945. */
  2946. level: void 0
  2947. }, {
  2948. level: 1,
  2949. /**
  2950. * @type {Highcharts.CSSObject}
  2951. * @product gantt
  2952. * @apioption yAxis.labels.levels.style
  2953. *
  2954. * @private
  2955. */
  2956. style: {
  2957. /** @ignore-option */
  2958. fontWeight: 'bold'
  2959. }
  2960. }],
  2961. /**
  2962. * The symbol for the collapse and expand icon in a
  2963. * treegrid.
  2964. *
  2965. * @product gantt
  2966. * @optionparent yAxis.labels.symbol
  2967. *
  2968. * @private
  2969. */
  2970. symbol: {
  2971. /**
  2972. * The symbol type. Points to a definition function in
  2973. * the `Highcharts.Renderer.symbols` collection.
  2974. *
  2975. * @type {Highcharts.SymbolKeyValue}
  2976. *
  2977. * @private
  2978. */
  2979. type: 'triangle',
  2980. x: -5,
  2981. y: -5,
  2982. height: 10,
  2983. width: 10,
  2984. padding: 5
  2985. }
  2986. },
  2987. uniqueNames: false
  2988. }, userOptions, {
  2989. // Forced options
  2990. reversed: true,
  2991. // grid.columns is not supported in treegrid
  2992. grid: {
  2993. columns: void 0
  2994. }
  2995. });
  2996. }
  2997. // Now apply the original function with the original arguments,
  2998. // which are sliced off this function's arguments
  2999. proceed.apply(axis, [chart, userOptions]);
  3000. if (isTreeGrid) {
  3001. axis.hasNames = true;
  3002. axis.options.showLastLabel = true;
  3003. }
  3004. }
  3005. /**
  3006. * Set the tick positions, tickInterval, axis min and max.
  3007. *
  3008. * @private
  3009. * @function Highcharts.GridAxis#setTickInterval
  3010. *
  3011. * @param {Function} proceed
  3012. * The original setTickInterval function.
  3013. */
  3014. function wrapSetTickInterval(proceed) {
  3015. var axis = this,
  3016. options = axis.options,
  3017. isTreeGrid = options.type === 'treegrid';
  3018. if (isTreeGrid) {
  3019. axis.min = pick(axis.userMin, options.min, axis.dataMin);
  3020. axis.max = pick(axis.userMax, options.max, axis.dataMax);
  3021. fireEvent(axis, 'foundExtremes');
  3022. // setAxisTranslation modifies the min and max according to
  3023. // axis breaks.
  3024. axis.setAxisTranslation();
  3025. axis.tickmarkOffset = 0.5;
  3026. axis.tickInterval = 1;
  3027. axis.tickPositions = axis.treeGrid.mapOfPosToGridNode ?
  3028. axis.treeGrid.getTickPositions() :
  3029. [];
  3030. }
  3031. else {
  3032. proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  3033. }
  3034. }
  3035. /* *
  3036. *
  3037. * Classes
  3038. *
  3039. * */
  3040. /**
  3041. * @private
  3042. * @class
  3043. */
  3044. var Additions = /** @class */ (function () {
  3045. /* *
  3046. *
  3047. * Constructors
  3048. *
  3049. * */
  3050. /**
  3051. * @private
  3052. */
  3053. function Additions(axis) {
  3054. this.axis = axis;
  3055. }
  3056. /* *
  3057. *
  3058. * Functions
  3059. *
  3060. * */
  3061. /**
  3062. * Set the collapse status.
  3063. *
  3064. * @private
  3065. *
  3066. * @param {Highcharts.Axis} axis
  3067. * The axis to check against.
  3068. *
  3069. * @param {Highcharts.GridNode} node
  3070. * The node to collapse.
  3071. */
  3072. Additions.prototype.setCollapsedStatus = function (node) {
  3073. var axis = this.axis,
  3074. chart = axis.chart;
  3075. axis.series.forEach(function (series) {
  3076. var data = series.options.data;
  3077. if (node.id && data) {
  3078. var point = chart.get(node.id),
  3079. dataPoint = data[series.data.indexOf(point)];
  3080. if (point && dataPoint) {
  3081. point.collapsed = node.collapsed;
  3082. dataPoint.collapsed = node.collapsed;
  3083. }
  3084. }
  3085. });
  3086. };
  3087. /**
  3088. * Calculates the new axis breaks to collapse a node.
  3089. *
  3090. * @private
  3091. *
  3092. * @param {Highcharts.Axis} axis
  3093. * The axis to check against.
  3094. *
  3095. * @param {Highcharts.GridNode} node
  3096. * The node to collapse.
  3097. *
  3098. * @param {number} pos
  3099. * The tick position to collapse.
  3100. *
  3101. * @return {Array<object>}
  3102. * Returns an array of the new breaks for the axis.
  3103. */
  3104. Additions.prototype.collapse = function (node) {
  3105. var axis = this.axis,
  3106. breaks = (axis.options.breaks || []),
  3107. obj = getBreakFromNode(node,
  3108. axis.max);
  3109. breaks.push(obj);
  3110. // Change the collapsed flag #13838
  3111. node.collapsed = true;
  3112. axis.treeGrid.setCollapsedStatus(node);
  3113. return breaks;
  3114. };
  3115. /**
  3116. * Calculates the new axis breaks to expand a node.
  3117. *
  3118. * @private
  3119. *
  3120. * @param {Highcharts.Axis} axis
  3121. * The axis to check against.
  3122. *
  3123. * @param {Highcharts.GridNode} node
  3124. * The node to expand.
  3125. *
  3126. * @param {number} pos
  3127. * The tick position to expand.
  3128. *
  3129. * @return {Array<object>}
  3130. * Returns an array of the new breaks for the axis.
  3131. */
  3132. Additions.prototype.expand = function (node) {
  3133. var axis = this.axis,
  3134. breaks = (axis.options.breaks || []),
  3135. obj = getBreakFromNode(node,
  3136. axis.max);
  3137. // Change the collapsed flag #13838
  3138. node.collapsed = false;
  3139. axis.treeGrid.setCollapsedStatus(node);
  3140. // Remove the break from the axis breaks array.
  3141. return breaks.reduce(function (arr, b) {
  3142. if (b.to !== obj.to || b.from !== obj.from) {
  3143. arr.push(b);
  3144. }
  3145. return arr;
  3146. }, []);
  3147. };
  3148. /**
  3149. * Creates a list of positions for the ticks on the axis. Filters out
  3150. * positions that are outside min and max, or is inside an axis break.
  3151. *
  3152. * @private
  3153. *
  3154. * @return {Array<number>}
  3155. * List of positions.
  3156. */
  3157. Additions.prototype.getTickPositions = function () {
  3158. var axis = this.axis,
  3159. roundedMin = Math.floor(axis.min / axis.tickInterval) * axis.tickInterval,
  3160. roundedMax = Math.ceil(axis.max / axis.tickInterval) * axis.tickInterval;
  3161. return Object.keys(axis.treeGrid.mapOfPosToGridNode || {}).reduce(function (arr, key) {
  3162. var pos = +key;
  3163. if (pos >= roundedMin &&
  3164. pos <= roundedMax &&
  3165. !(axis.brokenAxis && axis.brokenAxis.isInAnyBreak(pos))) {
  3166. arr.push(pos);
  3167. }
  3168. return arr;
  3169. }, []);
  3170. };
  3171. /**
  3172. * Check if a node is collapsed.
  3173. *
  3174. * @private
  3175. *
  3176. * @param {Highcharts.Axis} axis
  3177. * The axis to check against.
  3178. *
  3179. * @param {object} node
  3180. * The node to check if is collapsed.
  3181. *
  3182. * @param {number} pos
  3183. * The tick position to collapse.
  3184. *
  3185. * @return {boolean}
  3186. * Returns true if collapsed, false if expanded.
  3187. */
  3188. Additions.prototype.isCollapsed = function (node) {
  3189. var axis = this.axis,
  3190. breaks = (axis.options.breaks || []),
  3191. obj = getBreakFromNode(node,
  3192. axis.max);
  3193. return breaks.some(function (b) {
  3194. return b.from === obj.from && b.to === obj.to;
  3195. });
  3196. };
  3197. /**
  3198. * Calculates the new axis breaks after toggling the collapse/expand
  3199. * state of a node. If it is collapsed it will be expanded, and if it is
  3200. * exapended it will be collapsed.
  3201. *
  3202. * @private
  3203. *
  3204. * @param {Highcharts.Axis} axis
  3205. * The axis to check against.
  3206. *
  3207. * @param {Highcharts.GridNode} node
  3208. * The node to toggle.
  3209. *
  3210. * @return {Array<object>}
  3211. * Returns an array of the new breaks for the axis.
  3212. */
  3213. Additions.prototype.toggleCollapse = function (node) {
  3214. return (this.isCollapsed(node) ?
  3215. this.expand(node) :
  3216. this.collapse(node));
  3217. };
  3218. return Additions;
  3219. }());
  3220. TreeGridAxis.Additions = Additions;
  3221. })(TreeGridAxis || (TreeGridAxis = {}));
  3222. return TreeGridAxis;
  3223. });
  3224. _registerModule(_modules, 'masters/modules/treegrid.src.js', [_modules['Core/Globals.js'], _modules['Core/Axis/TreeGridAxis.js']], function (Highcharts, TreeGridAxis) {
  3225. var G = Highcharts;
  3226. // Compositions
  3227. TreeGridAxis.compose(G.Axis, G.Chart, G.Series, G.Tick);
  3228. });
  3229. }));