treegrid.src.js 137 KB

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