sankey.src.js 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742
  1. /**
  2. * @license Highcharts JS v9.1.1 (2021-06-04)
  3. *
  4. * Sankey diagram module
  5. *
  6. * (c) 2010-2021 Torstein Honsi
  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/sankey', ['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, 'Mixins/Nodes.js', [_modules['Core/Globals.js'], _modules['Core/Series/Point.js'], _modules['Core/Series/Series.js'], _modules['Core/Utilities.js']], function (H, Point, Series, U) {
  32. /* *
  33. *
  34. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  35. *
  36. * */
  37. var defined = U.defined,
  38. extend = U.extend,
  39. find = U.find,
  40. pick = U.pick;
  41. var NodesMixin = H.NodesMixin = {
  42. /* eslint-disable valid-jsdoc */
  43. /**
  44. * Create a single node that holds information on incoming and outgoing
  45. * links.
  46. * @private
  47. */
  48. createNode: function (id) {
  49. /**
  50. * @private
  51. */
  52. function findById(nodes,
  53. id) {
  54. return find(nodes,
  55. function (node) {
  56. return node.id === id;
  57. });
  58. }
  59. var node = findById(this.nodes,
  60. id),
  61. PointClass = this.pointClass,
  62. options;
  63. if (!node) {
  64. options = this.options.nodes && findById(this.options.nodes, id);
  65. node = (new PointClass()).init(this, extend({
  66. className: 'highcharts-node',
  67. isNode: true,
  68. id: id,
  69. y: 1 // Pass isNull test
  70. }, options));
  71. node.linksTo = [];
  72. node.linksFrom = [];
  73. node.formatPrefix = 'node';
  74. node.name = node.name || node.options.id || ''; // for use in formats
  75. // Mass is used in networkgraph:
  76. node.mass = pick(
  77. // Node:
  78. node.options.mass, node.options.marker && node.options.marker.radius,
  79. // Series:
  80. this.options.marker && this.options.marker.radius,
  81. // Default:
  82. 4);
  83. /**
  84. * Return the largest sum of either the incoming or outgoing links.
  85. * @private
  86. */
  87. node.getSum = function () {
  88. var sumTo = 0,
  89. sumFrom = 0;
  90. node.linksTo.forEach(function (link) {
  91. sumTo += link.weight;
  92. });
  93. node.linksFrom.forEach(function (link) {
  94. sumFrom += link.weight;
  95. });
  96. return Math.max(sumTo, sumFrom);
  97. };
  98. /**
  99. * Get the offset in weight values of a point/link.
  100. * @private
  101. */
  102. node.offset = function (point, coll) {
  103. var offset = 0;
  104. for (var i = 0; i < node[coll].length; i++) {
  105. if (node[coll][i] === point) {
  106. return offset;
  107. }
  108. offset += node[coll][i].weight;
  109. }
  110. };
  111. // Return true if the node has a shape, otherwise all links are
  112. // outgoing.
  113. node.hasShape = function () {
  114. var outgoing = 0;
  115. node.linksTo.forEach(function (link) {
  116. if (link.outgoing) {
  117. outgoing++;
  118. }
  119. });
  120. return (!node.linksTo.length ||
  121. outgoing !== node.linksTo.length);
  122. };
  123. this.nodes.push(node);
  124. }
  125. return node;
  126. },
  127. /**
  128. * Extend generatePoints by adding the nodes, which are Point objects
  129. * but pushed to the this.nodes array.
  130. */
  131. generatePoints: function () {
  132. var chart = this.chart,
  133. nodeLookup = {};
  134. Series.prototype.generatePoints.call(this);
  135. if (!this.nodes) {
  136. this.nodes = []; // List of Point-like node items
  137. }
  138. this.colorCounter = 0;
  139. // Reset links from previous run
  140. this.nodes.forEach(function (node) {
  141. node.linksFrom.length = 0;
  142. node.linksTo.length = 0;
  143. node.level = node.options.level;
  144. });
  145. // Create the node list and set up links
  146. this.points.forEach(function (point) {
  147. if (defined(point.from)) {
  148. if (!nodeLookup[point.from]) {
  149. nodeLookup[point.from] = this.createNode(point.from);
  150. }
  151. nodeLookup[point.from].linksFrom.push(point);
  152. point.fromNode = nodeLookup[point.from];
  153. // Point color defaults to the fromNode's color
  154. if (chart.styledMode) {
  155. point.colorIndex = pick(point.options.colorIndex, nodeLookup[point.from].colorIndex);
  156. }
  157. else {
  158. point.color =
  159. point.options.color || nodeLookup[point.from].color;
  160. }
  161. }
  162. if (defined(point.to)) {
  163. if (!nodeLookup[point.to]) {
  164. nodeLookup[point.to] = this.createNode(point.to);
  165. }
  166. nodeLookup[point.to].linksTo.push(point);
  167. point.toNode = nodeLookup[point.to];
  168. }
  169. point.name = point.name || point.id; // for use in formats
  170. }, this);
  171. // Store lookup table for later use
  172. this.nodeLookup = nodeLookup;
  173. },
  174. // Destroy all nodes on setting new data
  175. setData: function () {
  176. if (this.nodes) {
  177. this.nodes.forEach(function (node) {
  178. node.destroy();
  179. });
  180. this.nodes.length = 0;
  181. }
  182. Series.prototype.setData.apply(this, arguments);
  183. },
  184. // Destroy alll nodes and links
  185. destroy: function () {
  186. // Nodes must also be destroyed (#8682, #9300)
  187. this.data = []
  188. .concat(this.points || [], this.nodes);
  189. return Series.prototype.destroy.apply(this, arguments);
  190. },
  191. /**
  192. * When hovering node, highlight all connected links. When hovering a link,
  193. * highlight all connected nodes.
  194. */
  195. setNodeState: function (state) {
  196. var args = arguments,
  197. others = this.isNode ? this.linksTo.concat(this.linksFrom) :
  198. [this.fromNode,
  199. this.toNode];
  200. if (state !== 'select') {
  201. others.forEach(function (linkOrNode) {
  202. if (linkOrNode && linkOrNode.series) {
  203. Point.prototype.setState.apply(linkOrNode, args);
  204. if (!linkOrNode.isNode) {
  205. if (linkOrNode.fromNode.graphic) {
  206. Point.prototype.setState.apply(linkOrNode.fromNode, args);
  207. }
  208. if (linkOrNode.toNode && linkOrNode.toNode.graphic) {
  209. Point.prototype.setState.apply(linkOrNode.toNode, args);
  210. }
  211. }
  212. }
  213. });
  214. }
  215. Point.prototype.setState.apply(this, args);
  216. }
  217. /* eslint-enable valid-jsdoc */
  218. };
  219. return NodesMixin;
  220. });
  221. _registerModule(_modules, 'Series/Sankey/SankeyPoint.js', [_modules['Mixins/Nodes.js'], _modules['Core/Series/Point.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (NodesMixin, Point, SeriesRegistry, U) {
  222. /* *
  223. *
  224. * Sankey diagram module
  225. *
  226. * (c) 2010-2021 Torstein Honsi
  227. *
  228. * License: www.highcharts.com/license
  229. *
  230. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  231. *
  232. * */
  233. var __extends = (this && this.__extends) || (function () {
  234. var extendStatics = function (d,
  235. b) {
  236. extendStatics = Object.setPrototypeOf ||
  237. ({ __proto__: [] } instanceof Array && function (d,
  238. b) { d.__proto__ = b; }) ||
  239. function (d,
  240. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  241. return extendStatics(d, b);
  242. };
  243. return function (d, b) {
  244. extendStatics(d, b);
  245. function __() { this.constructor = d; }
  246. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  247. };
  248. })();
  249. var ColumnSeries = SeriesRegistry.seriesTypes.column;
  250. var defined = U.defined,
  251. extend = U.extend;
  252. /* *
  253. *
  254. * Class
  255. *
  256. * */
  257. var SankeyPoint = /** @class */ (function (_super) {
  258. __extends(SankeyPoint, _super);
  259. function SankeyPoint() {
  260. /* *
  261. *
  262. * Properties
  263. *
  264. * */
  265. var _this = _super !== null && _super.apply(this,
  266. arguments) || this;
  267. _this.className = void 0;
  268. _this.fromNode = void 0;
  269. _this.level = void 0;
  270. _this.linkBase = void 0;
  271. _this.linksFrom = void 0;
  272. _this.linksTo = void 0;
  273. _this.mass = void 0;
  274. _this.nodeX = void 0;
  275. _this.nodeY = void 0;
  276. _this.options = void 0;
  277. _this.series = void 0;
  278. _this.toNode = void 0;
  279. return _this;
  280. /* eslint-enable valid-jsdoc */
  281. }
  282. /* *
  283. *
  284. * Functions
  285. *
  286. * */
  287. /* eslint-disable valid-jsdoc */
  288. /**
  289. * @private
  290. */
  291. SankeyPoint.prototype.applyOptions = function (options, x) {
  292. Point.prototype.applyOptions.call(this, options, x);
  293. // Treat point.level as a synonym of point.column
  294. if (defined(this.options.level)) {
  295. this.options.column = this.column = this.options.level;
  296. }
  297. return this;
  298. };
  299. /**
  300. * @private
  301. */
  302. SankeyPoint.prototype.getClassName = function () {
  303. return (this.isNode ? 'highcharts-node ' : 'highcharts-link ') +
  304. Point.prototype.getClassName.call(this);
  305. };
  306. /**
  307. * @private
  308. */
  309. SankeyPoint.prototype.isValid = function () {
  310. return this.isNode || typeof this.weight === 'number';
  311. };
  312. return SankeyPoint;
  313. }(ColumnSeries.prototype.pointClass));
  314. extend(SankeyPoint.prototype, {
  315. setState: NodesMixin.setNodeState
  316. });
  317. /* *
  318. *
  319. * Default Export
  320. *
  321. * */
  322. return SankeyPoint;
  323. });
  324. _registerModule(_modules, 'Mixins/TreeSeries.js', [_modules['Core/Color/Color.js'], _modules['Core/Utilities.js']], function (Color, U) {
  325. /* *
  326. *
  327. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  328. *
  329. * */
  330. var extend = U.extend,
  331. isArray = U.isArray,
  332. isNumber = U.isNumber,
  333. isObject = U.isObject,
  334. merge = U.merge,
  335. pick = U.pick;
  336. var isBoolean = function (x) {
  337. return typeof x === 'boolean';
  338. }, isFn = function (x) {
  339. return typeof x === 'function';
  340. };
  341. /* eslint-disable valid-jsdoc */
  342. /**
  343. * @todo Combine buildTree and buildNode with setTreeValues
  344. * @todo Remove logic from Treemap and make it utilize this mixin.
  345. * @private
  346. */
  347. var setTreeValues = function setTreeValues(tree,
  348. options) {
  349. var before = options.before,
  350. idRoot = options.idRoot,
  351. mapIdToNode = options.mapIdToNode,
  352. nodeRoot = mapIdToNode[idRoot],
  353. levelIsConstant = (isBoolean(options.levelIsConstant) ?
  354. options.levelIsConstant :
  355. true),
  356. points = options.points,
  357. point = points[tree.i],
  358. optionsPoint = point && point.options || {},
  359. childrenTotal = 0,
  360. children = [],
  361. value;
  362. tree.levelDynamic = tree.level - (levelIsConstant ? 0 : nodeRoot.level);
  363. tree.name = pick(point && point.name, '');
  364. tree.visible = (idRoot === tree.id ||
  365. (isBoolean(options.visible) ? options.visible : false));
  366. if (isFn(before)) {
  367. tree = before(tree, options);
  368. }
  369. // First give the children some values
  370. tree.children.forEach(function (child, i) {
  371. var newOptions = extend({},
  372. options);
  373. extend(newOptions, {
  374. index: i,
  375. siblings: tree.children.length,
  376. visible: tree.visible
  377. });
  378. child = setTreeValues(child, newOptions);
  379. children.push(child);
  380. if (child.visible) {
  381. childrenTotal += child.val;
  382. }
  383. });
  384. tree.visible = childrenTotal > 0 || tree.visible;
  385. // Set the values
  386. value = pick(optionsPoint.value, childrenTotal);
  387. tree.children = children;
  388. tree.childrenTotal = childrenTotal;
  389. tree.isLeaf = tree.visible && !childrenTotal;
  390. tree.val = value;
  391. return tree;
  392. };
  393. /**
  394. * @private
  395. */
  396. var getColor = function getColor(node,
  397. options) {
  398. var index = options.index,
  399. mapOptionsToLevel = options.mapOptionsToLevel,
  400. parentColor = options.parentColor,
  401. parentColorIndex = options.parentColorIndex,
  402. series = options.series,
  403. colors = options.colors,
  404. siblings = options.siblings,
  405. points = series.points,
  406. getColorByPoint,
  407. chartOptionsChart = series.chart.options.chart,
  408. point,
  409. level,
  410. colorByPoint,
  411. colorIndexByPoint,
  412. color,
  413. colorIndex;
  414. /**
  415. * @private
  416. */
  417. function variation(color) {
  418. var colorVariation = level && level.colorVariation;
  419. if (colorVariation) {
  420. if (colorVariation.key === 'brightness') {
  421. return Color.parse(color).brighten(colorVariation.to * (index / siblings)).get();
  422. }
  423. }
  424. return color;
  425. }
  426. if (node) {
  427. point = points[node.i];
  428. level = mapOptionsToLevel[node.level] || {};
  429. getColorByPoint = point && level.colorByPoint;
  430. if (getColorByPoint) {
  431. colorIndexByPoint = point.index % (colors ?
  432. colors.length :
  433. chartOptionsChart.colorCount);
  434. colorByPoint = colors && colors[colorIndexByPoint];
  435. }
  436. // Select either point color, level color or inherited color.
  437. if (!series.chart.styledMode) {
  438. color = pick(point && point.options.color, level && level.color, colorByPoint, parentColor && variation(parentColor), series.color);
  439. }
  440. colorIndex = pick(point && point.options.colorIndex, level && level.colorIndex, colorIndexByPoint, parentColorIndex, options.colorIndex);
  441. }
  442. return {
  443. color: color,
  444. colorIndex: colorIndex
  445. };
  446. };
  447. /**
  448. * Creates a map from level number to its given options.
  449. *
  450. * @private
  451. * @function getLevelOptions
  452. * @param {object} params
  453. * Object containing parameters.
  454. * - `defaults` Object containing default options. The default options
  455. * are merged with the userOptions to get the final options for a
  456. * specific level.
  457. * - `from` The lowest level number.
  458. * - `levels` User options from series.levels.
  459. * - `to` The highest level number.
  460. * @return {Highcharts.Dictionary<object>|null}
  461. * Returns a map from level number to its given options.
  462. */
  463. var getLevelOptions = function getLevelOptions(params) {
  464. var result = null,
  465. defaults,
  466. converted,
  467. i,
  468. from,
  469. to,
  470. levels;
  471. if (isObject(params)) {
  472. result = {};
  473. from = isNumber(params.from) ? params.from : 1;
  474. levels = params.levels;
  475. converted = {};
  476. defaults = isObject(params.defaults) ? params.defaults : {};
  477. if (isArray(levels)) {
  478. converted = levels.reduce(function (obj, item) {
  479. var level,
  480. levelIsConstant,
  481. options;
  482. if (isObject(item) && isNumber(item.level)) {
  483. options = merge({}, item);
  484. levelIsConstant = (isBoolean(options.levelIsConstant) ?
  485. options.levelIsConstant :
  486. defaults.levelIsConstant);
  487. // Delete redundant properties.
  488. delete options.levelIsConstant;
  489. delete options.level;
  490. // Calculate which level these options apply to.
  491. level = item.level + (levelIsConstant ? 0 : from - 1);
  492. if (isObject(obj[level])) {
  493. extend(obj[level], options);
  494. }
  495. else {
  496. obj[level] = options;
  497. }
  498. }
  499. return obj;
  500. }, {});
  501. }
  502. to = isNumber(params.to) ? params.to : 1;
  503. for (i = 0; i <= to; i++) {
  504. result[i] = merge({}, defaults, isObject(converted[i]) ? converted[i] : {});
  505. }
  506. }
  507. return result;
  508. };
  509. /**
  510. * Update the rootId property on the series. Also makes sure that it is
  511. * accessible to exporting.
  512. *
  513. * @private
  514. * @function updateRootId
  515. *
  516. * @param {object} series
  517. * The series to operate on.
  518. *
  519. * @return {string}
  520. * Returns the resulting rootId after update.
  521. */
  522. var updateRootId = function (series) {
  523. var rootId,
  524. options;
  525. if (isObject(series)) {
  526. // Get the series options.
  527. options = isObject(series.options) ? series.options : {};
  528. // Calculate the rootId.
  529. rootId = pick(series.rootNode, options.rootId, '');
  530. // Set rootId on series.userOptions to pick it up in exporting.
  531. if (isObject(series.userOptions)) {
  532. series.userOptions.rootId = rootId;
  533. }
  534. // Set rootId on series to pick it up on next update.
  535. series.rootNode = rootId;
  536. }
  537. return rootId;
  538. };
  539. var result = {
  540. getColor: getColor,
  541. getLevelOptions: getLevelOptions,
  542. setTreeValues: setTreeValues,
  543. updateRootId: updateRootId
  544. };
  545. return result;
  546. });
  547. _registerModule(_modules, 'Series/Sankey/SankeySeries.js', [_modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Mixins/Nodes.js'], _modules['Series/Sankey/SankeyPoint.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Mixins/TreeSeries.js'], _modules['Core/Utilities.js']], function (Color, H, NodesMixin, SankeyPoint, SeriesRegistry, TreeSeriesMixin, U) {
  548. /* *
  549. *
  550. * Sankey diagram module
  551. *
  552. * (c) 2010-2021 Torstein Honsi
  553. *
  554. * License: www.highcharts.com/license
  555. *
  556. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  557. *
  558. * */
  559. var __extends = (this && this.__extends) || (function () {
  560. var extendStatics = function (d,
  561. b) {
  562. extendStatics = Object.setPrototypeOf ||
  563. ({ __proto__: [] } instanceof Array && function (d,
  564. b) { d.__proto__ = b; }) ||
  565. function (d,
  566. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  567. return extendStatics(d, b);
  568. };
  569. return function (d, b) {
  570. extendStatics(d, b);
  571. function __() { this.constructor = d; }
  572. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  573. };
  574. })();
  575. var Series = SeriesRegistry.series,
  576. ColumnSeries = SeriesRegistry.seriesTypes.column;
  577. var getLevelOptions = TreeSeriesMixin.getLevelOptions;
  578. var defined = U.defined,
  579. extend = U.extend,
  580. find = U.find,
  581. isObject = U.isObject,
  582. merge = U.merge,
  583. pick = U.pick,
  584. relativeLength = U.relativeLength,
  585. stableSort = U.stableSort;
  586. /* *
  587. *
  588. * Class
  589. *
  590. * */
  591. /**
  592. * @private
  593. * @class
  594. * @name Highcharts.seriesTypes.sankey
  595. *
  596. * @augments Highcharts.Series
  597. */
  598. var SankeySeries = /** @class */ (function (_super) {
  599. __extends(SankeySeries, _super);
  600. function SankeySeries() {
  601. /* *
  602. *
  603. * Static Properties
  604. *
  605. * */
  606. var _this = _super !== null && _super.apply(this,
  607. arguments) || this;
  608. /* *
  609. *
  610. * Properties
  611. *
  612. * */
  613. _this.colDistance = void 0;
  614. _this.data = void 0;
  615. _this.group = void 0;
  616. _this.nodeLookup = void 0;
  617. _this.nodePadding = void 0;
  618. _this.nodes = void 0;
  619. _this.nodeWidth = void 0;
  620. _this.options = void 0;
  621. _this.points = void 0;
  622. _this.translationFactor = void 0;
  623. return _this;
  624. /* eslint-enable valid-jsdoc */
  625. }
  626. /* *
  627. *
  628. * Static Functions
  629. *
  630. * */
  631. // eslint-disable-next-line valid-jsdoc
  632. /**
  633. * @private
  634. */
  635. SankeySeries.getDLOptions = function (params) {
  636. var optionsPoint = (isObject(params.optionsPoint) ?
  637. params.optionsPoint.dataLabels :
  638. {}),
  639. optionsLevel = (isObject(params.level) ?
  640. params.level.dataLabels :
  641. {}),
  642. options = merge({
  643. style: {}
  644. },
  645. optionsLevel,
  646. optionsPoint);
  647. return options;
  648. };
  649. /* *
  650. *
  651. * Functions
  652. *
  653. * */
  654. /* eslint-disable valid-jsdoc */
  655. /**
  656. * Create a node column.
  657. * @private
  658. */
  659. SankeySeries.prototype.createNodeColumn = function () {
  660. var series = this,
  661. chart = this.chart,
  662. column = [];
  663. column.sum = function () {
  664. return this.reduce(function (sum, node) {
  665. return sum + node.getSum();
  666. }, 0);
  667. };
  668. // Get the offset in pixels of a node inside the column.
  669. column.offset = function (node, factor) {
  670. var offset = 0,
  671. totalNodeOffset,
  672. nodePadding = series.nodePadding;
  673. for (var i = 0; i < column.length; i++) {
  674. var sum = column[i].getSum();
  675. var height = Math.max(sum * factor,
  676. series.options.minLinkWidth);
  677. if (sum) {
  678. totalNodeOffset = height + nodePadding;
  679. }
  680. else {
  681. // If node sum equals 0 nodePadding is missed #12453
  682. totalNodeOffset = 0;
  683. }
  684. if (column[i] === node) {
  685. return {
  686. relativeTop: offset + relativeLength(node.options.offset || 0, totalNodeOffset)
  687. };
  688. }
  689. offset += totalNodeOffset;
  690. }
  691. };
  692. // Get the top position of the column in pixels.
  693. column.top = function (factor) {
  694. var nodePadding = series.nodePadding;
  695. var height = this.reduce(function (height,
  696. node) {
  697. if (height > 0) {
  698. height += nodePadding;
  699. }
  700. var nodeHeight = Math.max(node.getSum() * factor,
  701. series.options.minLinkWidth);
  702. height += nodeHeight;
  703. return height;
  704. }, 0);
  705. return (chart.plotSizeY - height) / 2;
  706. };
  707. return column;
  708. };
  709. /**
  710. * Create node columns by analyzing the nodes and the relations between
  711. * incoming and outgoing links.
  712. * @private
  713. */
  714. SankeySeries.prototype.createNodeColumns = function () {
  715. var columns = [];
  716. this.nodes.forEach(function (node) {
  717. var fromColumn = -1,
  718. fromNode,
  719. i,
  720. point;
  721. if (!defined(node.options.column)) {
  722. // No links to this node, place it left
  723. if (node.linksTo.length === 0) {
  724. node.column = 0;
  725. // There are incoming links, place it to the right of the
  726. // highest order column that links to this one.
  727. }
  728. else {
  729. for (i = 0; i < node.linksTo.length; i++) {
  730. point = node.linksTo[0];
  731. if (point.fromNode.column > fromColumn) {
  732. fromNode = point.fromNode;
  733. fromColumn = fromNode.column;
  734. }
  735. }
  736. node.column = fromColumn + 1;
  737. // Hanging layout for organization chart
  738. if (fromNode &&
  739. fromNode.options.layout === 'hanging') {
  740. node.hangsFrom = fromNode;
  741. i = -1; // Reuse existing variable i
  742. find(fromNode.linksFrom, function (link, index) {
  743. var found = link.toNode === node;
  744. if (found) {
  745. i = index;
  746. }
  747. return found;
  748. });
  749. node.column += i;
  750. }
  751. }
  752. }
  753. if (!columns[node.column]) {
  754. columns[node.column] = this.createNodeColumn();
  755. }
  756. columns[node.column].push(node);
  757. }, this);
  758. // Fill in empty columns (#8865)
  759. for (var i = 0; i < columns.length; i++) {
  760. if (typeof columns[i] === 'undefined') {
  761. columns[i] = this.createNodeColumn();
  762. }
  763. }
  764. return columns;
  765. };
  766. /**
  767. * Extend generatePoints by adding the nodes, which are Point objects
  768. * but pushed to the this.nodes array.
  769. * @private
  770. */
  771. SankeySeries.prototype.generatePoints = function () {
  772. NodesMixin.generatePoints.apply(this, arguments);
  773. /**
  774. * Order the nodes, starting with the root node(s). (#9818)
  775. * @private
  776. */
  777. function order(node, level) {
  778. // Prevents circular recursion:
  779. if (typeof node.level === 'undefined') {
  780. node.level = level;
  781. node.linksFrom.forEach(function (link) {
  782. if (link.toNode) {
  783. order(link.toNode, level + 1);
  784. }
  785. });
  786. }
  787. }
  788. if (this.orderNodes) {
  789. this.nodes
  790. // Identify the root node(s)
  791. .filter(function (node) {
  792. return node.linksTo.length === 0;
  793. })
  794. // Start by the root node(s) and recursively set the level
  795. // on all following nodes.
  796. .forEach(function (node) {
  797. order(node, 0);
  798. });
  799. stableSort(this.nodes, function (a, b) {
  800. return a.level - b.level;
  801. });
  802. }
  803. };
  804. /**
  805. * Overridable function to get node padding, overridden in dependency
  806. * wheel series type.
  807. * @private
  808. */
  809. SankeySeries.prototype.getNodePadding = function () {
  810. var nodePadding = this.options.nodePadding || 0;
  811. // If the number of columns is so great that they will overflow with
  812. // the given nodePadding, we sacrifice the padding in order to
  813. // render all nodes within the plot area (#11917).
  814. if (this.nodeColumns) {
  815. var maxLength = this.nodeColumns.reduce(function (acc,
  816. col) { return Math.max(acc,
  817. col.length); }, 0);
  818. if (maxLength * nodePadding > this.chart.plotSizeY) {
  819. nodePadding = this.chart.plotSizeY / maxLength;
  820. }
  821. }
  822. return nodePadding;
  823. };
  824. /**
  825. * Define hasData function for non-cartesian series.
  826. * @private
  827. * @return {boolean}
  828. * Returns true if the series has points at all.
  829. */
  830. SankeySeries.prototype.hasData = function () {
  831. return !!this.processedXData.length; // != 0
  832. };
  833. /**
  834. * Return the presentational attributes.
  835. * @private
  836. */
  837. SankeySeries.prototype.pointAttribs = function (point, state) {
  838. if (!point) {
  839. return {};
  840. }
  841. var series = this, level = point.isNode ? point.level : point.fromNode.level, levelOptions = series.mapOptionsToLevel[level || 0] || {}, options = point.options, stateOptions = (levelOptions.states && levelOptions.states[state || '']) || {}, values = [
  842. 'colorByPoint', 'borderColor', 'borderWidth', 'linkOpacity'
  843. ].reduce(function (obj, key) {
  844. obj[key] = pick(stateOptions[key], options[key], levelOptions[key], series.options[key]);
  845. return obj;
  846. }, {}), color = pick(stateOptions.color, options.color, values.colorByPoint ? point.color : levelOptions.color);
  847. // Node attributes
  848. if (point.isNode) {
  849. return {
  850. fill: color,
  851. stroke: values.borderColor,
  852. 'stroke-width': values.borderWidth
  853. };
  854. }
  855. // Link attributes
  856. return {
  857. fill: Color.parse(color).setOpacity(values.linkOpacity).get()
  858. };
  859. };
  860. /**
  861. * Extend the render function to also render this.nodes together with
  862. * the points.
  863. * @private
  864. */
  865. SankeySeries.prototype.render = function () {
  866. var points = this.points;
  867. this.points = this.points.concat(this.nodes || []);
  868. ColumnSeries.prototype.render.call(this);
  869. this.points = points;
  870. };
  871. /**
  872. * Run pre-translation by generating the nodeColumns.
  873. * @private
  874. */
  875. SankeySeries.prototype.translate = function () {
  876. var _this = this;
  877. // Get the translation factor needed for each column to fill up the
  878. // plot height
  879. var getColumnTranslationFactor = function (column) {
  880. var nodes = column.slice();
  881. var minLinkWidth = _this.options.minLinkWidth || 0;
  882. var exceedsMinLinkWidth;
  883. var factor = 0;
  884. var i;
  885. var remainingHeight = chart.plotSizeY -
  886. options.borderWidth - (column.length - 1) * series.nodePadding;
  887. // Because the minLinkWidth option doesn't obey the direct
  888. // translation, we need to run translation iteratively, check
  889. // node heights, remove those nodes affected by minLinkWidth,
  890. // check again, etc.
  891. while (column.length) {
  892. factor = remainingHeight / column.sum();
  893. exceedsMinLinkWidth = false;
  894. i = column.length;
  895. while (i--) {
  896. if (column[i].getSum() * factor < minLinkWidth) {
  897. column.splice(i, 1);
  898. remainingHeight -= minLinkWidth;
  899. exceedsMinLinkWidth = true;
  900. }
  901. }
  902. if (!exceedsMinLinkWidth) {
  903. break;
  904. }
  905. }
  906. // Re-insert original nodes
  907. column.length = 0;
  908. nodes.forEach(function (node) { return column.push(node); });
  909. return factor;
  910. };
  911. if (!this.processedXData) {
  912. this.processData();
  913. }
  914. this.generatePoints();
  915. this.nodeColumns = this.createNodeColumns();
  916. this.nodeWidth = relativeLength(this.options.nodeWidth, this.chart.plotSizeX);
  917. var series = this,
  918. chart = this.chart,
  919. options = this.options,
  920. nodeWidth = this.nodeWidth,
  921. nodeColumns = this.nodeColumns;
  922. this.nodePadding = this.getNodePadding();
  923. // Find out how much space is needed. Base it on the translation
  924. // factor of the most spaceous column.
  925. this.translationFactor = nodeColumns.reduce(function (translationFactor, column) { return Math.min(translationFactor, getColumnTranslationFactor(column)); }, Infinity);
  926. this.colDistance =
  927. (chart.plotSizeX - nodeWidth -
  928. options.borderWidth) / Math.max(1, nodeColumns.length - 1);
  929. // Calculate level options used in sankey and organization
  930. series.mapOptionsToLevel = getLevelOptions({
  931. // NOTE: if support for allowTraversingTree is added, then from
  932. // should be the level of the root node.
  933. from: 1,
  934. levels: options.levels,
  935. to: nodeColumns.length - 1,
  936. defaults: {
  937. borderColor: options.borderColor,
  938. borderRadius: options.borderRadius,
  939. borderWidth: options.borderWidth,
  940. color: series.color,
  941. colorByPoint: options.colorByPoint,
  942. // NOTE: if support for allowTraversingTree is added, then
  943. // levelIsConstant should be optional.
  944. levelIsConstant: true,
  945. linkColor: options.linkColor,
  946. linkLineWidth: options.linkLineWidth,
  947. linkOpacity: options.linkOpacity,
  948. states: options.states
  949. }
  950. });
  951. // First translate all nodes so we can use them when drawing links
  952. nodeColumns.forEach(function (column) {
  953. column.forEach(function (node) {
  954. series.translateNode(node, column);
  955. });
  956. }, this);
  957. // Then translate links
  958. this.nodes.forEach(function (node) {
  959. // Translate the links from this node
  960. node.linksFrom.forEach(function (linkPoint) {
  961. // If weight is 0 - don't render the link path #12453,
  962. // render null points (for organization chart)
  963. if ((linkPoint.weight || linkPoint.isNull) && linkPoint.to) {
  964. series.translateLink(linkPoint);
  965. linkPoint.allowShadow = false;
  966. }
  967. });
  968. });
  969. };
  970. /**
  971. * Run translation operations for one link.
  972. * @private
  973. */
  974. SankeySeries.prototype.translateLink = function (point) {
  975. var getY = function (node,
  976. fromOrTo) {
  977. var linkTop = (node.offset(point,
  978. fromOrTo) *
  979. translationFactor);
  980. var y = Math.min(node.nodeY + linkTop,
  981. // Prevent links from spilling below the node (#12014)
  982. node.nodeY + (node.shapeArgs && node.shapeArgs.height || 0) - linkHeight);
  983. return y;
  984. };
  985. var fromNode = point.fromNode, toNode = point.toNode, chart = this.chart, translationFactor = this.translationFactor, linkHeight = Math.max(point.weight * translationFactor, this.options.minLinkWidth), options = this.options, curvy = ((chart.inverted ? -this.colDistance : this.colDistance) *
  986. options.curveFactor), fromY = getY(fromNode, 'linksFrom'), toY = getY(toNode, 'linksTo'), nodeLeft = fromNode.nodeX, nodeW = this.nodeWidth, right = toNode.column * this.colDistance, outgoing = point.outgoing, straight = right > nodeLeft + nodeW;
  987. if (chart.inverted) {
  988. fromY = chart.plotSizeY - fromY;
  989. toY = (chart.plotSizeY || 0) - toY;
  990. right = chart.plotSizeX - right;
  991. nodeW = -nodeW;
  992. linkHeight = -linkHeight;
  993. straight = nodeLeft > right;
  994. }
  995. point.shapeType = 'path';
  996. point.linkBase = [
  997. fromY,
  998. fromY + linkHeight,
  999. toY,
  1000. toY + linkHeight
  1001. ];
  1002. // Links going from left to right
  1003. if (straight && typeof toY === 'number') {
  1004. point.shapeArgs = {
  1005. d: [
  1006. ['M', nodeLeft + nodeW, fromY],
  1007. [
  1008. 'C',
  1009. nodeLeft + nodeW + curvy,
  1010. fromY,
  1011. right - curvy,
  1012. toY,
  1013. right,
  1014. toY
  1015. ],
  1016. ['L', right + (outgoing ? nodeW : 0), toY + linkHeight / 2],
  1017. ['L', right, toY + linkHeight],
  1018. [
  1019. 'C',
  1020. right - curvy,
  1021. toY + linkHeight,
  1022. nodeLeft + nodeW + curvy,
  1023. fromY + linkHeight,
  1024. nodeLeft + nodeW, fromY + linkHeight
  1025. ],
  1026. ['Z']
  1027. ]
  1028. };
  1029. // Experimental: Circular links pointing backwards. In
  1030. // v6.1.0 this breaks the rendering completely, so even
  1031. // this experimental rendering is an improvement. #8218.
  1032. // @todo
  1033. // - Make room for the link in the layout
  1034. // - Automatically determine if the link should go up or
  1035. // down.
  1036. }
  1037. else if (typeof toY === 'number') {
  1038. var bend = 20,
  1039. vDist = chart.plotHeight - fromY - linkHeight,
  1040. x1 = right - bend - linkHeight,
  1041. x2 = right - bend,
  1042. x3 = right,
  1043. x4 = nodeLeft + nodeW,
  1044. x5 = x4 + bend,
  1045. x6 = x5 + linkHeight,
  1046. fy1 = fromY,
  1047. fy2 = fromY + linkHeight,
  1048. fy3 = fy2 + bend,
  1049. y4 = fy3 + vDist,
  1050. y5 = y4 + bend,
  1051. y6 = y5 + linkHeight,
  1052. ty1 = toY,
  1053. ty2 = ty1 + linkHeight,
  1054. ty3 = ty2 + bend,
  1055. cfy1 = fy2 - linkHeight * 0.7,
  1056. cy2 = y5 + linkHeight * 0.7,
  1057. cty1 = ty2 - linkHeight * 0.7,
  1058. cx1 = x3 - linkHeight * 0.7,
  1059. cx2 = x4 + linkHeight * 0.7;
  1060. point.shapeArgs = {
  1061. d: [
  1062. ['M', x4, fy1],
  1063. ['C', cx2, fy1, x6, cfy1, x6, fy3],
  1064. ['L', x6, y4],
  1065. ['C', x6, cy2, cx2, y6, x4, y6],
  1066. ['L', x3, y6],
  1067. ['C', cx1, y6, x1, cy2, x1, y4],
  1068. ['L', x1, ty3],
  1069. ['C', x1, cty1, cx1, ty1, x3, ty1],
  1070. ['L', x3, ty2],
  1071. ['C', x2, ty2, x2, ty2, x2, ty3],
  1072. ['L', x2, y4],
  1073. ['C', x2, y5, x2, y5, x3, y5],
  1074. ['L', x4, y5],
  1075. ['C', x5, y5, x5, y5, x5, y4],
  1076. ['L', x5, fy3],
  1077. ['C', x5, fy2, x5, fy2, x4, fy2],
  1078. ['Z']
  1079. ]
  1080. };
  1081. }
  1082. // Place data labels in the middle
  1083. point.dlBox = {
  1084. x: nodeLeft + (right - nodeLeft + nodeW) / 2,
  1085. y: fromY + (toY - fromY) / 2,
  1086. height: linkHeight,
  1087. width: 0
  1088. };
  1089. // And set the tooltip anchor in the middle
  1090. point.tooltipPos = chart.inverted ? [
  1091. chart.plotSizeY - point.dlBox.y - linkHeight / 2,
  1092. chart.plotSizeX - point.dlBox.x
  1093. ] : [
  1094. point.dlBox.x,
  1095. point.dlBox.y + linkHeight / 2
  1096. ];
  1097. // Pass test in drawPoints
  1098. point.y = point.plotY = 1;
  1099. if (!point.color) {
  1100. point.color = fromNode.color;
  1101. }
  1102. };
  1103. /**
  1104. * Run translation operations for one node.
  1105. * @private
  1106. */
  1107. SankeySeries.prototype.translateNode = function (node, column) {
  1108. var translationFactor = this.translationFactor,
  1109. chart = this.chart,
  1110. options = this.options,
  1111. sum = node.getSum(),
  1112. nodeHeight = Math.max(Math.round(sum * translationFactor),
  1113. this.options.minLinkWidth),
  1114. crisp = Math.round(options.borderWidth) % 2 / 2,
  1115. nodeOffset = column.offset(node,
  1116. translationFactor),
  1117. fromNodeTop = Math.floor(pick(nodeOffset.absoluteTop, (column.top(translationFactor) +
  1118. nodeOffset.relativeTop))) + crisp,
  1119. left = Math.floor(this.colDistance * node.column +
  1120. options.borderWidth / 2) + crisp,
  1121. nodeLeft = chart.inverted ?
  1122. chart.plotSizeX - left :
  1123. left,
  1124. nodeWidth = Math.round(this.nodeWidth);
  1125. node.sum = sum;
  1126. // If node sum is 0, don't render the rect #12453
  1127. if (sum) {
  1128. // Draw the node
  1129. node.shapeType = 'rect';
  1130. node.nodeX = nodeLeft;
  1131. node.nodeY = fromNodeTop;
  1132. var x = nodeLeft,
  1133. y = fromNodeTop,
  1134. width = node.options.width || options.width || nodeWidth,
  1135. height = node.options.height || options.height || nodeHeight;
  1136. if (chart.inverted) {
  1137. x = nodeLeft - nodeWidth;
  1138. y = chart.plotSizeY - fromNodeTop - nodeHeight;
  1139. width = node.options.height || options.height || nodeWidth;
  1140. height = node.options.width || options.width || nodeHeight;
  1141. }
  1142. // Calculate data label options for the point
  1143. node.dlOptions = SankeySeries.getDLOptions({
  1144. level: this.mapOptionsToLevel[node.level],
  1145. optionsPoint: node.options
  1146. });
  1147. // Pass test in drawPoints
  1148. node.plotX = 1;
  1149. node.plotY = 1;
  1150. // Set the anchor position for tooltips
  1151. node.tooltipPos = chart.inverted ? [
  1152. chart.plotSizeY - y - height / 2,
  1153. chart.plotSizeX - x - width / 2
  1154. ] : [
  1155. x + width / 2,
  1156. y + height / 2
  1157. ];
  1158. node.shapeArgs = {
  1159. x: x,
  1160. y: y,
  1161. width: width,
  1162. height: height,
  1163. display: node.hasShape() ? '' : 'none'
  1164. };
  1165. }
  1166. else {
  1167. node.dlOptions = {
  1168. enabled: false
  1169. };
  1170. }
  1171. };
  1172. /**
  1173. * A sankey diagram is a type of flow diagram, in which the width of the
  1174. * link between two nodes is shown proportionally to the flow quantity.
  1175. *
  1176. * @sample highcharts/demo/sankey-diagram/
  1177. * Sankey diagram
  1178. * @sample highcharts/plotoptions/sankey-inverted/
  1179. * Inverted sankey diagram
  1180. * @sample highcharts/plotoptions/sankey-outgoing
  1181. * Sankey diagram with outgoing links
  1182. *
  1183. * @extends plotOptions.column
  1184. * @since 6.0.0
  1185. * @product highcharts
  1186. * @excluding animationLimit, boostThreshold, borderRadius,
  1187. * crisp, cropThreshold, colorAxis, colorKey, depth, dragDrop,
  1188. * edgeColor, edgeWidth, findNearestPointBy, grouping,
  1189. * groupPadding, groupZPadding, maxPointWidth, negativeColor,
  1190. * pointInterval, pointIntervalUnit, pointPadding,
  1191. * pointPlacement, pointRange, pointStart, pointWidth,
  1192. * shadow, softThreshold, stacking, threshold, zoneAxis,
  1193. * zones, minPointLength, dataSorting, boostBlending
  1194. * @requires modules/sankey
  1195. * @optionparent plotOptions.sankey
  1196. */
  1197. SankeySeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  1198. borderWidth: 0,
  1199. colorByPoint: true,
  1200. /**
  1201. * Higher numbers makes the links in a sankey diagram or dependency
  1202. * wheelrender more curved. A `curveFactor` of 0 makes the lines
  1203. * straight.
  1204. *
  1205. * @private
  1206. */
  1207. curveFactor: 0.33,
  1208. /**
  1209. * Options for the data labels appearing on top of the nodes and links.
  1210. * For sankey charts, data labels are visible for the nodes by default,
  1211. * but hidden for links. This is controlled by modifying the
  1212. * `nodeFormat`, and the `format` that applies to links and is an empty
  1213. * string by default.
  1214. *
  1215. * @declare Highcharts.SeriesSankeyDataLabelsOptionsObject
  1216. *
  1217. * @private
  1218. */
  1219. dataLabels: {
  1220. enabled: true,
  1221. backgroundColor: 'none',
  1222. crop: false,
  1223. /**
  1224. * The
  1225. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  1226. * specifying what to show for _nodes_ in the sankey diagram. By
  1227. * default the `nodeFormatter` returns `{point.name}`.
  1228. *
  1229. * @sample highcharts/plotoptions/sankey-link-datalabels/
  1230. * Node and link data labels
  1231. *
  1232. * @type {string}
  1233. */
  1234. nodeFormat: void 0,
  1235. // eslint-disable-next-line valid-jsdoc
  1236. /**
  1237. * Callback to format data labels for _nodes_ in the sankey diagram.
  1238. * The `nodeFormat` option takes precedence over the
  1239. * `nodeFormatter`.
  1240. *
  1241. * @type {Highcharts.SeriesSankeyDataLabelsFormatterCallbackFunction}
  1242. * @since 6.0.2
  1243. */
  1244. nodeFormatter: function () {
  1245. return this.point.name;
  1246. },
  1247. format: void 0,
  1248. // eslint-disable-next-line valid-jsdoc
  1249. /**
  1250. * @type {Highcharts.SeriesSankeyDataLabelsFormatterCallbackFunction}
  1251. */
  1252. formatter: function () {
  1253. return;
  1254. },
  1255. inside: true
  1256. },
  1257. /**
  1258. * @ignore-option
  1259. *
  1260. * @private
  1261. */
  1262. inactiveOtherPoints: true,
  1263. /**
  1264. * Set options on specific levels. Takes precedence over series options,
  1265. * but not node and link options.
  1266. *
  1267. * @sample highcharts/demo/sunburst
  1268. * Sunburst chart
  1269. *
  1270. * @type {Array<*>}
  1271. * @since 7.1.0
  1272. * @apioption plotOptions.sankey.levels
  1273. */
  1274. /**
  1275. * Can set `borderColor` on all nodes which lay on the same level.
  1276. *
  1277. * @type {Highcharts.ColorString}
  1278. * @apioption plotOptions.sankey.levels.borderColor
  1279. */
  1280. /**
  1281. * Can set `borderWidth` on all nodes which lay on the same level.
  1282. *
  1283. * @type {number}
  1284. * @apioption plotOptions.sankey.levels.borderWidth
  1285. */
  1286. /**
  1287. * Can set `color` on all nodes which lay on the same level.
  1288. *
  1289. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  1290. * @apioption plotOptions.sankey.levels.color
  1291. */
  1292. /**
  1293. * Can set `colorByPoint` on all nodes which lay on the same level.
  1294. *
  1295. * @type {boolean}
  1296. * @default true
  1297. * @apioption plotOptions.sankey.levels.colorByPoint
  1298. */
  1299. /**
  1300. * Can set `dataLabels` on all points which lay on the same level.
  1301. *
  1302. * @extends plotOptions.sankey.dataLabels
  1303. * @apioption plotOptions.sankey.levels.dataLabels
  1304. */
  1305. /**
  1306. * Decides which level takes effect from the options set in the levels
  1307. * object.
  1308. *
  1309. * @type {number}
  1310. * @apioption plotOptions.sankey.levels.level
  1311. */
  1312. /**
  1313. * Can set `linkOpacity` on all points which lay on the same level.
  1314. *
  1315. * @type {number}
  1316. * @default 0.5
  1317. * @apioption plotOptions.sankey.levels.linkOpacity
  1318. */
  1319. /**
  1320. * Can set `states` on all nodes and points which lay on the same level.
  1321. *
  1322. * @extends plotOptions.sankey.states
  1323. * @apioption plotOptions.sankey.levels.states
  1324. */
  1325. /**
  1326. * Opacity for the links between nodes in the sankey diagram.
  1327. *
  1328. * @private
  1329. */
  1330. linkOpacity: 0.5,
  1331. /**
  1332. * The minimal width for a line of a sankey. By default,
  1333. * 0 values are not shown.
  1334. *
  1335. * @sample highcharts/plotoptions/sankey-minlinkwidth
  1336. * Sankey diagram with minimal link height
  1337. *
  1338. * @type {number}
  1339. * @since 7.1.3
  1340. * @default 0
  1341. * @apioption plotOptions.sankey.minLinkWidth
  1342. *
  1343. * @private
  1344. */
  1345. minLinkWidth: 0,
  1346. /**
  1347. * The pixel width of each node in a sankey diagram or dependency wheel,
  1348. * or the height in case the chart is inverted.
  1349. *
  1350. * @private
  1351. */
  1352. nodeWidth: 20,
  1353. /**
  1354. * The padding between nodes in a sankey diagram or dependency wheel, in
  1355. * pixels.
  1356. *
  1357. * If the number of nodes is so great that it is possible to lay them
  1358. * out within the plot area with the given `nodePadding`, they will be
  1359. * rendered with a smaller padding as a strategy to avoid overflow.
  1360. *
  1361. * @private
  1362. */
  1363. nodePadding: 10,
  1364. showInLegend: false,
  1365. states: {
  1366. hover: {
  1367. /**
  1368. * Opacity for the links between nodes in the sankey diagram in
  1369. * hover mode.
  1370. */
  1371. linkOpacity: 1
  1372. },
  1373. /**
  1374. * The opposite state of a hover for a single point node/link.
  1375. *
  1376. * @declare Highcharts.SeriesStatesInactiveOptionsObject
  1377. */
  1378. inactive: {
  1379. /**
  1380. * Opacity for the links between nodes in the sankey diagram in
  1381. * inactive mode.
  1382. */
  1383. linkOpacity: 0.1,
  1384. /**
  1385. * Opacity of inactive markers.
  1386. *
  1387. * @type {number}
  1388. * @apioption plotOptions.series.states.inactive.opacity
  1389. */
  1390. opacity: 0.1,
  1391. /**
  1392. * Animation when not hovering over the marker.
  1393. *
  1394. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  1395. * @apioption plotOptions.series.states.inactive.animation
  1396. */
  1397. animation: {
  1398. /** @internal */
  1399. duration: 50
  1400. }
  1401. }
  1402. },
  1403. tooltip: {
  1404. /**
  1405. * A callback for defining the format for _nodes_ in the chart's
  1406. * tooltip, as opposed to links.
  1407. *
  1408. * @type {Highcharts.FormatterCallbackFunction<Highcharts.SankeyNodeObject>}
  1409. * @since 6.0.2
  1410. * @apioption plotOptions.sankey.tooltip.nodeFormatter
  1411. */
  1412. /**
  1413. * Whether the tooltip should follow the pointer or stay fixed on
  1414. * the item.
  1415. */
  1416. followPointer: true,
  1417. headerFormat: '<span style="font-size: 10px">{series.name}</span><br/>',
  1418. pointFormat: '{point.fromNode.name} \u2192 {point.toNode.name}: <b>{point.weight}</b><br/>',
  1419. /**
  1420. * The
  1421. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  1422. * specifying what to show for _nodes_ in tooltip of a diagram
  1423. * series, as opposed to links.
  1424. */
  1425. nodeFormat: '{point.name}: <b>{point.sum}</b><br/>'
  1426. }
  1427. });
  1428. return SankeySeries;
  1429. }(ColumnSeries));
  1430. extend(SankeySeries.prototype, {
  1431. animate: Series.prototype.animate,
  1432. // Create a single node that holds information on incoming and outgoing
  1433. // links.
  1434. createNode: NodesMixin.createNode,
  1435. destroy: NodesMixin.destroy,
  1436. forceDL: true,
  1437. invertible: true,
  1438. isCartesian: false,
  1439. orderNodes: true,
  1440. pointArrayMap: ['from', 'to'],
  1441. pointClass: SankeyPoint,
  1442. searchPoint: H.noop,
  1443. setData: NodesMixin.setData
  1444. });
  1445. SeriesRegistry.registerSeriesType('sankey', SankeySeries);
  1446. /* *
  1447. *
  1448. * Default Export
  1449. *
  1450. * */
  1451. /* *
  1452. *
  1453. * API Declarations
  1454. *
  1455. * */
  1456. /**
  1457. * A node in a sankey diagram.
  1458. *
  1459. * @interface Highcharts.SankeyNodeObject
  1460. * @extends Highcharts.Point
  1461. * @product highcharts
  1462. */ /**
  1463. * The color of the auto generated node.
  1464. *
  1465. * @name Highcharts.SankeyNodeObject#color
  1466. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  1467. */ /**
  1468. * The color index of the auto generated node, especially for use in styled
  1469. * mode.
  1470. *
  1471. * @name Highcharts.SankeyNodeObject#colorIndex
  1472. * @type {number}
  1473. */ /**
  1474. * An optional column index of where to place the node. The default behaviour is
  1475. * to place it next to the preceding node.
  1476. *
  1477. * @see {@link https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/sankey-node-column/|Highcharts-Demo:}
  1478. * Specified node column
  1479. *
  1480. * @name Highcharts.SankeyNodeObject#column
  1481. * @type {number}
  1482. * @since 6.0.5
  1483. */ /**
  1484. * The id of the auto-generated node, refering to the `from` or `to` setting of
  1485. * the link.
  1486. *
  1487. * @name Highcharts.SankeyNodeObject#id
  1488. * @type {string}
  1489. */ /**
  1490. * The name to display for the node in data labels and tooltips. Use this when
  1491. * the name is different from the `id`. Where the id must be unique for each
  1492. * node, this is not necessary for the name.
  1493. *
  1494. * @see {@link https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/sankey/|Highcharts-Demo:}
  1495. * Sankey diagram with node options
  1496. *
  1497. * @name Highcharts.SankeyNodeObject#name
  1498. * @type {string}
  1499. * @product highcharts
  1500. */ /**
  1501. * The vertical offset of a node in terms of weight. Positive values shift the
  1502. * node downwards, negative shift it upwards.
  1503. *
  1504. * @see {@link https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/sankey-node-column/|Highcharts-Demo:}
  1505. * Specified node offset
  1506. *
  1507. * @name Highcharts.SankeyNodeObject#offset
  1508. * @type {number}
  1509. * @default 0
  1510. * @since 6.0.5
  1511. */
  1512. /**
  1513. * Formatter callback function.
  1514. *
  1515. * @callback Highcharts.SeriesSankeyDataLabelsFormatterCallbackFunction
  1516. *
  1517. * @param {Highcharts.SeriesSankeyDataLabelsFormatterContextObject|Highcharts.PointLabelObject} this
  1518. * Data label context to format
  1519. *
  1520. * @return {string|undefined}
  1521. * Formatted data label text
  1522. */
  1523. /**
  1524. * Context for the node formatter function.
  1525. *
  1526. * @interface Highcharts.SeriesSankeyDataLabelsFormatterContextObject
  1527. * @extends Highcharts.PointLabelObject
  1528. */ /**
  1529. * The node object. The node name, if defined, is available through
  1530. * `this.point.name`.
  1531. * @name Highcharts.SeriesSankeyDataLabelsFormatterContextObject#point
  1532. * @type {Highcharts.SankeyNodeObject}
  1533. */
  1534. ''; // detach doclets above
  1535. /* *
  1536. *
  1537. * API Options
  1538. *
  1539. * */
  1540. /**
  1541. * A `sankey` series. If the [type](#series.sankey.type) option is not
  1542. * specified, it is inherited from [chart.type](#chart.type).
  1543. *
  1544. * @extends series,plotOptions.sankey
  1545. * @excluding animationLimit, boostBlending, boostThreshold, borderColor,
  1546. * borderRadius, borderWidth, crisp, cropThreshold, dataParser,
  1547. * dataURL, depth, dragDrop, edgeColor, edgeWidth,
  1548. * findNearestPointBy, getExtremesFromAll, grouping, groupPadding,
  1549. * groupZPadding, label, maxPointWidth, negativeColor, pointInterval,
  1550. * pointIntervalUnit, pointPadding, pointPlacement, pointRange,
  1551. * pointStart, pointWidth, shadow, softThreshold, stacking,
  1552. * threshold, zoneAxis, zones, dataSorting
  1553. * @product highcharts
  1554. * @requires modules/sankey
  1555. * @apioption series.sankey
  1556. */
  1557. /**
  1558. * A collection of options for the individual nodes. The nodes in a sankey
  1559. * diagram are auto-generated instances of `Highcharts.Point`, but options can
  1560. * be applied here and linked by the `id`.
  1561. *
  1562. * @sample highcharts/css/sankey/
  1563. * Sankey diagram with node options
  1564. *
  1565. * @declare Highcharts.SeriesSankeyNodesOptionsObject
  1566. * @type {Array<*>}
  1567. * @product highcharts
  1568. * @apioption series.sankey.nodes
  1569. */
  1570. /**
  1571. * The id of the auto-generated node, refering to the `from` or `to` setting of
  1572. * the link.
  1573. *
  1574. * @type {string}
  1575. * @product highcharts
  1576. * @apioption series.sankey.nodes.id
  1577. */
  1578. /**
  1579. * The color of the auto generated node.
  1580. *
  1581. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  1582. * @product highcharts
  1583. * @apioption series.sankey.nodes.color
  1584. */
  1585. /**
  1586. * The color index of the auto generated node, especially for use in styled
  1587. * mode.
  1588. *
  1589. * @type {number}
  1590. * @product highcharts
  1591. * @apioption series.sankey.nodes.colorIndex
  1592. */
  1593. /**
  1594. * An optional column index of where to place the node. The default behaviour is
  1595. * to place it next to the preceding node. Note that this option name is
  1596. * counter intuitive in inverted charts, like for example an organization chart
  1597. * rendered top down. In this case the "columns" are horizontal.
  1598. *
  1599. * @sample highcharts/plotoptions/sankey-node-column/
  1600. * Specified node column
  1601. *
  1602. * @type {number}
  1603. * @since 6.0.5
  1604. * @product highcharts
  1605. * @apioption series.sankey.nodes.column
  1606. */
  1607. /**
  1608. * Individual data label for each node. The options are the same as
  1609. * the ones for [series.sankey.dataLabels](#series.sankey.dataLabels).
  1610. *
  1611. * @extends plotOptions.sankey.dataLabels
  1612. * @apioption series.sankey.nodes.dataLabels
  1613. */
  1614. /**
  1615. * An optional level index of where to place the node. The default behaviour is
  1616. * to place it next to the preceding node. Alias of `nodes.column`, but in
  1617. * inverted sankeys and org charts, the levels are laid out as rows.
  1618. *
  1619. * @type {number}
  1620. * @since 7.1.0
  1621. * @product highcharts
  1622. * @apioption series.sankey.nodes.level
  1623. */
  1624. /**
  1625. * The name to display for the node in data labels and tooltips. Use this when
  1626. * the name is different from the `id`. Where the id must be unique for each
  1627. * node, this is not necessary for the name.
  1628. *
  1629. * @sample highcharts/css/sankey/
  1630. * Sankey diagram with node options
  1631. *
  1632. * @type {string}
  1633. * @product highcharts
  1634. * @apioption series.sankey.nodes.name
  1635. */
  1636. /**
  1637. * In a horizontal layout, the vertical offset of a node in terms of weight.
  1638. * Positive values shift the node downwards, negative shift it upwards. In a
  1639. * vertical layout, like organization chart, the offset is horizontal.
  1640. *
  1641. * If a percantage string is given, the node is offset by the percentage of the
  1642. * node size plus `nodePadding`.
  1643. *
  1644. * @sample highcharts/plotoptions/sankey-node-column/
  1645. * Specified node offset
  1646. *
  1647. * @type {number|string}
  1648. * @default 0
  1649. * @since 6.0.5
  1650. * @product highcharts
  1651. * @apioption series.sankey.nodes.offset
  1652. */
  1653. /**
  1654. * An array of data points for the series. For the `sankey` series type,
  1655. * points can be given in the following way:
  1656. *
  1657. * An array of objects with named values. The following snippet shows only a
  1658. * few settings, see the complete options set below. If the total number of data
  1659. * points exceeds the series' [turboThreshold](#series.area.turboThreshold),
  1660. * this option is not available.
  1661. *
  1662. * ```js
  1663. * data: [{
  1664. * from: 'Category1',
  1665. * to: 'Category2',
  1666. * weight: 2
  1667. * }, {
  1668. * from: 'Category1',
  1669. * to: 'Category3',
  1670. * weight: 5
  1671. * }]
  1672. * ```
  1673. *
  1674. * @sample {highcharts} highcharts/series/data-array-of-objects/
  1675. * Config objects
  1676. *
  1677. * @declare Highcharts.SeriesSankeyPointOptionsObject
  1678. * @type {Array<*>}
  1679. * @extends series.line.data
  1680. * @excluding dragDrop, drilldown, marker, x, y
  1681. * @product highcharts
  1682. * @apioption series.sankey.data
  1683. */
  1684. /**
  1685. * The color for the individual _link_. By default, the link color is the same
  1686. * as the node it extends from. The `series.fillOpacity` option also applies to
  1687. * the points, so when setting a specific link color, consider setting the
  1688. * `fillOpacity` to 1.
  1689. *
  1690. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  1691. * @product highcharts
  1692. * @apioption series.sankey.data.color
  1693. */
  1694. /**
  1695. * @type {Highcharts.SeriesSankeyDataLabelsOptionsObject|Array<Highcharts.SeriesSankeyDataLabelsOptionsObject>}
  1696. * @product highcharts
  1697. * @apioption series.sankey.data.dataLabels
  1698. */
  1699. /**
  1700. * The node that the link runs from.
  1701. *
  1702. * @type {string}
  1703. * @product highcharts
  1704. * @apioption series.sankey.data.from
  1705. */
  1706. /**
  1707. * The node that the link runs to.
  1708. *
  1709. * @type {string}
  1710. * @product highcharts
  1711. * @apioption series.sankey.data.to
  1712. */
  1713. /**
  1714. * Whether the link goes out of the system.
  1715. *
  1716. * @sample highcharts/plotoptions/sankey-outgoing
  1717. * Sankey chart with outgoing links
  1718. *
  1719. * @type {boolean}
  1720. * @default false
  1721. * @product highcharts
  1722. * @apioption series.sankey.data.outgoing
  1723. */
  1724. /**
  1725. * The weight of the link.
  1726. *
  1727. * @type {number|null}
  1728. * @product highcharts
  1729. * @apioption series.sankey.data.weight
  1730. */
  1731. ''; // adds doclets above to transpiled file
  1732. return SankeySeries;
  1733. });
  1734. _registerModule(_modules, 'masters/modules/sankey.src.js', [], function () {
  1735. });
  1736. }));