/** * @license Highcharts JS v11.4.1 (2024-04-04) * Organization chart series type * * (c) 2019-2024 Torstein Honsi * * License: www.highcharts.com/license */ (function (factory) { if (typeof module === 'object' && module.exports) { factory['default'] = factory; module.exports = factory; } else if (typeof define === 'function' && define.amd) { define('highcharts/modules/organization', ['highcharts', 'highcharts/modules/sankey'], function (Highcharts) { factory(Highcharts); factory.Highcharts = Highcharts; return factory; }); } else { factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined); } }(function (Highcharts) { 'use strict'; var _modules = Highcharts ? Highcharts._modules : {}; function _registerModule(obj, path, args, fn) { if (!obj.hasOwnProperty(path)) { obj[path] = fn.apply(null, args); if (typeof CustomEvent === 'function') { window.dispatchEvent(new CustomEvent( 'HighchartsModuleLoaded', { detail: { path: path, module: obj[path] } } )); } } } _registerModule(_modules, 'Series/Organization/OrganizationPoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) { /* * * * Organization chart module * * (c) 2018-2024 Torstein Honsi * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ const { sankey: { prototype: { pointClass: SankeyPointClass } } } = SeriesRegistry.seriesTypes; const { defined, find, pick } = U; /* * * * Functions * * */ /** * Get columns offset including all sibling and cousins etc. * @private */ function getOffset(node) { let offset = node.linksFrom.length; node.linksFrom.forEach((link) => { if (link.id === link.toNode.linksTo[0].id) { // Node has children, that hangs directly from it: offset += getOffset(link.toNode); } else { // If the node hangs from multiple parents, and this is not // the last one, ignore it: offset--; } }); return offset; } /* * * * Class * * */ class OrganizationPoint extends SankeyPointClass { /* * * * Functions * * */ constructor(series, options, x) { super(series, options, x); if (!this.isNode) { this.dataLabelOnNull = true; this.formatPrefix = 'link'; } } /** * All nodes in an org chart are equal width. * @private */ getSum() { return 1; } /** * Set node.column for hanging layout * @private */ setNodeColumn() { super.setNodeColumn(); const node = this, fromNode = node.getFromNode().fromNode; // Hanging layout if ( // Not defined by user !defined(node.options.column) && // Has links to node.linksTo.length !== 0 && // And parent uses hanging layout fromNode && fromNode.options.layout === 'hanging') { let i = -1, link; // Default all children of the hanging node // to have hanging layout node.options.layout = pick(node.options.layout, 'hanging'); node.hangsFrom = fromNode; find(fromNode.linksFrom, (link, index) => { const found = link.toNode === node; if (found) { i = index; } return found; }); // For all siblings' children (recursively) // increase the column offset to prevent overlapping for (let j = 0; j < fromNode.linksFrom.length; ++j) { link = fromNode.linksFrom[j]; if (link.toNode.id === node.id) { // Break j = fromNode.linksFrom.length; } else { i += getOffset(link.toNode); } } node.column = (node.column || 0) + i; } } } /* * * * Default Export * * */ return OrganizationPoint; }); _registerModule(_modules, 'Series/Organization/OrganizationSeriesDefaults.js', [], function () { /* * * * Organization chart module * * (c) 2018-2024 Torstein Honsi * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ /* * * * API Options * * */ /** * An organization chart is a diagram that shows the structure of an * organization and the relationships and relative ranks of its parts and * positions. * * @sample highcharts/demo/organization-chart/ * Organization chart * @sample highcharts/series-organization/horizontal/ * Horizontal organization chart * @sample highcharts/series-organization/borderless * Borderless design * @sample highcharts/series-organization/center-layout * Centered layout * * @extends plotOptions.sankey * @excluding allowPointSelect, curveFactor, dataSorting * @since 7.1.0 * @product highcharts * @requires modules/organization * @optionparent plotOptions.organization */ const OrganizationSeriesDefaults = { /** * The border color of the node cards. * * @type {Highcharts.ColorString} */ borderColor: "#666666" /* Palette.neutralColor60 */, /** * The border radius of the node cards. * * @private */ borderRadius: 3, /** * Radius for the rounded corners of the links between nodes. This * option is now deprecated, and moved to * [link.radius](#plotOptions.organization.link.radius). * * @sample highcharts/series-organization/link-options * Square links * * @deprecated * @apioption series.organization.linkRadius */ /** * Link Styling options * @since 10.3.0 * @product highcharts */ link: { /** * Modifier of the shape of the curved link. Works best for values * between 0 and 1, where 0 is a straight line, and 1 is a shape * close to the default one. * * @default 0.5 * @type {number} * @since 10.3.0 * @product highcharts * @apioption series.organization.link.offset */ /** * The color of the links between nodes. * * @type {Highcharts.ColorString} */ color: "#666666" /* Palette.neutralColor60 */, /** * The line width of the links connecting nodes, in pixels. * * @sample highcharts/series-organization/link-options * Square links */ lineWidth: 1, /** * Radius for the rounded corners of the links between nodes. * Works for `default` link type. * * @sample highcharts/series-organization/link-options * Square links */ radius: 10, /** * Type of the link shape. * * @sample highcharts/series-organization/different-link-types * Different link types * * @declare Highcharts.OrganizationLinkTypeValue * @type {'default' | 'curved' | 'straight'} * @default 'default' * @product highcharts */ type: 'default' }, borderWidth: 1, /** * @declare Highcharts.SeriesOrganizationDataLabelsOptionsObject * * @private */ dataLabels: { /* eslint-disable valid-jsdoc */ /** * A callback for defining the format for _nodes_ in the * organization chart. The `nodeFormat` option takes precedence * over `nodeFormatter`. * * In an organization chart, the `nodeFormatter` is a quite complex * function of the available options, striving for a good default * layout of cards with or without images. In organization chart, * the data labels come with `useHTML` set to true, meaning they * will be rendered as true HTML above the SVG. * * @sample highcharts/series-organization/datalabels-nodeformatter * Modify the default label format output * * @type {Highcharts.SeriesSankeyDataLabelsFormatterCallbackFunction} * @since 6.0.2 */ nodeFormatter: function () { const outerStyle = { width: '100%', height: '100%', display: 'flex', 'flex-direction': 'row', 'align-items': 'center', 'justify-content': 'center' }, imageStyle = { 'max-height': '100%', 'border-radius': '50%' }, innerStyle = { width: '100%', padding: 0, 'text-align': 'center', 'white-space': 'normal' }, nameStyle = { margin: 0 }, titleStyle = { margin: 0 }, descriptionStyle = { opacity: 0.75, margin: '5px' }; // eslint-disable-next-line valid-jsdoc /** * @private */ function styleAttr(style) { return Object.keys(style).reduce(function (str, key) { return str + key + ':' + style[key] + ';'; }, 'style="') + '"'; } const { description, image, title } = this.point; if (image) { imageStyle['max-width'] = '30%'; innerStyle.width = '70%'; } // PhantomJS doesn't support flex, roll back to absolute // positioning if (this .series.chart.renderer.forExport) { outerStyle.display = 'block'; innerStyle.position = 'absolute'; innerStyle.left = image ? '30%' : 0; innerStyle.top = 0; } let html = '
'; if (image) { html += ''; } html += '
'; if (this.point.name) { html += '

' + this.point.name + '

'; } if (title) { html += '

' + (title || '') + '

'; } if (description) { html += '

' + description + '

'; } html += '
' + '
'; return html; }, /* eslint-enable valid-jsdoc */ style: { /** @internal */ fontWeight: 'normal', /** @internal */ fontSize: '0.9em' }, useHTML: true, linkTextPath: { attributes: { startOffset: '95%', textAnchor: 'end' } } }, /** * The indentation in pixels of hanging nodes, nodes which parent has * [layout](#series.organization.nodes.layout) set to `hanging`. * * @private */ hangingIndent: 20, /** * Defines the indentation of a `hanging` layout parent's children. * Possible options: * * - `inherit` (default): Only the first child adds the indentation, * children of a child with indentation inherit the indentation. * - `cumulative`: All children of a child with indentation add its * own indent. The option may cause overlapping of nodes. * Then use `shrink` option: * - `shrink`: Nodes shrink by the * [hangingIndent](#plotOptions.organization.hangingIndent) * value until they reach the * [minNodeLength](#plotOptions.organization.minNodeLength). * * @sample highcharts/series-organization/hanging-cumulative * Every indent increases the indentation * * @sample highcharts/series-organization/hanging-shrink * Every indent decreases the nodes' width * * @type {Highcharts.OrganizationHangingIndentTranslationValue} * @since 10.0.0 * @default inherit * * @private */ hangingIndentTranslation: 'inherit', /** * Whether links connecting hanging nodes should be drawn on the left * or right side. Useful for RTL layouts. * **Note:** Only effects inverted charts (vertical layout). * * @sample highcharts/series-organization/hanging-side * Nodes hanging from right side. * * @type {'left'|'right'} * @since 11.3.0 * @default 'left' */ hangingSide: 'left', /** * * The color of the links between nodes. This option is moved to * [link.color](#plotOptions.organization.link.color). * * @type {Highcharts.ColorString} * @deprecated * @apioption series.organization.linkColor * @private */ /** * The line width of the links connecting nodes, in pixels. This option * is now deprecated and moved to the * [link.radius](#plotOptions.organization.link.lineWidth). * * @sample highcharts/series-organization/link-options * Square links * * @deprecated * @apioption series.organization.linkLineWidth * @private */ /** * In a horizontal chart, the minimum width of the **hanging** nodes * only, in pixels. In a vertical chart, the minimum height of the * **haning** nodes only, in pixels too. * * Note: Used only when * [hangingIndentTranslation](#plotOptions.organization.hangingIndentTranslation) * is set to `shrink`. * * @see [nodeWidth](#plotOptions.organization.nodeWidth) * * @private */ minNodeLength: 10, /** * In a horizontal chart, the width of the nodes in pixels. Note that * most organization charts are inverted (vertical), so the name of this * option is counterintuitive. * * @see [minNodeLength](#plotOptions.organization.minNodeLength) * * @private */ nodeWidth: 50, tooltip: { nodeFormat: '{point.name}
{point.title}
{point.description}' } }; /** * An `organization` series. If the [type](#series.organization.type) option is * not specified, it is inherited from [chart.type](#chart.type). * * @extends series,plotOptions.organization * @exclude dataSorting, boostThreshold, boostBlending * @product highcharts * @requires modules/sankey * @requires modules/organization * @apioption series.organization */ /** * @type {Highcharts.SeriesOrganizationDataLabelsOptionsObject|Array} * @product highcharts * @apioption series.organization.data.dataLabels */ /** * A collection of options for the individual nodes. The nodes in an org chart * are auto-generated instances of `Highcharts.Point`, but options can be * applied here and linked by the `id`. * * @extends series.sankey.nodes * @type {Array<*>} * @product highcharts * @apioption series.organization.nodes */ /** * Individual data label for each node. The options are the same as * the ones for [series.organization.dataLabels](#series.organization.dataLabels). * * @type {Highcharts.SeriesOrganizationDataLabelsOptionsObject|Array} * * @apioption series.organization.nodes.dataLabels */ /** * The job description for the node card, will be inserted by the default * `dataLabel.nodeFormatter`. * * @sample highcharts/demo/organization-chart * Org chart with job descriptions * * @type {string} * @product highcharts * @apioption series.organization.nodes.description */ /** * An image for the node card, will be inserted by the default * `dataLabel.nodeFormatter`. * * @sample highcharts/demo/organization-chart * Org chart with images * * @type {string} * @product highcharts * @apioption series.organization.nodes.image */ /** * The format string specifying what to show for *links* in the * organization chart. * * Best to use with [`linkTextPath`](#series.organization.dataLabels.linkTextPath) enabled. * * @sample highcharts/series-organization/link-labels * Organization chart with link labels * * @type {string} * @product highcharts * @apioption series.organization.dataLabels.linkFormat * @since 11.0.0 */ /** * Callback to format data labels for _links_ in the * organization chart. The `linkFormat` option takes * precedence over the `linkFormatter`. * * @type {OrganizationDataLabelsFormatterCallbackFunction} * @product highcharts * @apioption series.organization.dataLabels.linkFormatter * @since 11.0.0 */ /** * Options for a _link_ label text which should follow link * connection. * * @sample highcharts/series-organization/link-labels * Organization chart with link labels * * @type { DataLabelTextPathOptions } * @product highcharts * @apioption series.organization.dataLabels.linkTextPath * @since 11.0.0 */ /** * Layout for the node's children. If `hanging`, this node's children will hang * below their parent, allowing a tighter packing of nodes in the diagram. * * Note: Since @next version, the `hanging` layout is set by default for * children of a parent using `hanging` layout. * * @sample highcharts/demo/organization-chart * Hanging layout * * @type {Highcharts.SeriesOrganizationNodesLayoutValue} * @default normal * @product highcharts * @apioption series.organization.nodes.layout */ /** * The job title for the node card, will be inserted by the default * `dataLabel.nodeFormatter`. * * @sample highcharts/demo/organization-chart * Org chart with job titles * * @type {string} * @product highcharts * @apioption series.organization.nodes.title */ /** * An array of data points for the series. For the `organization` series * type, points can be given in the following way: * * An array of objects with named values. The following snippet shows only a * few settings, see the complete options set below. If the total number of data * points exceeds the series' [turboThreshold](#series.area.turboThreshold), * this option is not available. * * ```js * data: [{ * from: 'Category1', * to: 'Category2', * weight: 2 * }, { * from: 'Category1', * to: 'Category3', * weight: 5 * }] * ``` * * @type {Array<*>} * @extends series.sankey.data * @product highcharts * @apioption series.organization.data */ ''; // Keeps doclets above in JS file /* * * * Default Export * * */ return OrganizationSeriesDefaults; }); _registerModule(_modules, 'Series/PathUtilities.js', [], function () { /* * * * (c) 2010-2024 Pawel Lysy * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ const getLinkPath = { 'default': getDefaultPath, straight: getStraightPath, curved: getCurvedPath }; /** * */ function getDefaultPath(pathParams) { const { x1, y1, x2, y2, width = 0, inverted = false, radius, parentVisible } = pathParams; const path = [ ['M', x1, y1], ['L', x1, y1], ['C', x1, y1, x1, y2, x1, y2], ['L', x1, y2], ['C', x1, y1, x1, y2, x1, y2], ['L', x1, y2] ]; return parentVisible ? applyRadius([ ['M', x1, y1], ['L', x1 + width * (inverted ? -0.5 : 0.5), y1], ['L', x1 + width * (inverted ? -0.5 : 0.5), y2], ['L', x2, y2] ], radius) : path; } /** * */ function getStraightPath(pathParams) { const { x1, y1, x2, y2, width = 0, inverted = false, parentVisible } = pathParams; return parentVisible ? [ ['M', x1, y1], ['L', x1 + width * (inverted ? -1 : 1), y2], ['L', x2, y2] ] : [ ['M', x1, y1], ['L', x1, y2], ['L', x1, y2] ]; } /** * */ function getCurvedPath(pathParams) { const { x1, y1, x2, y2, offset = 0, width = 0, inverted = false, parentVisible } = pathParams; return parentVisible ? [ ['M', x1, y1], [ 'C', x1 + offset, y1, x1 - offset + width * (inverted ? -1 : 1), y2, x1 + width * (inverted ? -1 : 1), y2 ], ['L', x2, y2] ] : [ ['M', x1, y1], ['C', x1, y1, x1, y2, x1, y2], ['L', x2, y2] ]; } /** * General function to apply corner radius to a path * @private */ function applyRadius(path, r) { const d = []; for (let i = 0; i < path.length; i++) { const x = path[i][1]; const y = path[i][2]; if (typeof x === 'number' && typeof y === 'number') { // MoveTo if (i === 0) { d.push(['M', x, y]); } else if (i === path.length - 1) { d.push(['L', x, y]); // CurveTo } else if (r) { const prevSeg = path[i - 1]; const nextSeg = path[i + 1]; if (prevSeg && nextSeg) { const x1 = prevSeg[1], y1 = prevSeg[2], x2 = nextSeg[1], y2 = nextSeg[2]; // Only apply to breaks if (typeof x1 === 'number' && typeof x2 === 'number' && typeof y1 === 'number' && typeof y2 === 'number' && x1 !== x2 && y1 !== y2) { const directionX = x1 < x2 ? 1 : -1, directionY = y1 < y2 ? 1 : -1; d.push([ 'L', x - directionX * Math.min(Math.abs(x - x1), r), y - directionY * Math.min(Math.abs(y - y1), r) ], [ 'C', x, y, x, y, x + directionX * Math.min(Math.abs(x - x2), r), y + directionY * Math.min(Math.abs(y - y2), r) ]); } } // LineTo } else { d.push(['L', x, y]); } } } return d; } const PathUtilities = { applyRadius, getLinkPath }; return PathUtilities; }); _registerModule(_modules, 'Series/Organization/OrganizationSeries.js', [_modules['Series/Organization/OrganizationPoint.js'], _modules['Series/Organization/OrganizationSeriesDefaults.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Series/PathUtilities.js'], _modules['Core/Utilities.js']], function (OrganizationPoint, OrganizationSeriesDefaults, SeriesRegistry, PathUtilities, U) { /* * * * Organization chart module * * (c) 2018-2024 Torstein Honsi * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ const { sankey: SankeySeries } = SeriesRegistry.seriesTypes; const { css, extend, isNumber, merge, pick } = U; /* * * * Class * * */ /** * @private * @class * @name Highcharts.seriesTypes.organization * * @augments Highcharts.seriesTypes.sankey */ class OrganizationSeries extends SankeySeries { /* * * * Functions * * */ alignDataLabel(point, dataLabel, options) { // Align the data label to the point graphic const shapeArgs = point.shapeArgs; if (options.useHTML && shapeArgs) { const padjust = (this.options.borderWidth + 2 * this.options.dataLabels.padding); let width = shapeArgs.width || 0, height = shapeArgs.height || 0; if (this.chart.inverted) { width = height; height = shapeArgs.width || 0; } height -= padjust; width -= padjust; // Set the size of the surrounding div emulating `g` const text = dataLabel.text; if (text) { css(text.element.parentNode, { width: width + 'px', height: height + 'px' }); // Set properties for the span emulating `text` css(text.element, { left: 0, top: 0, width: '100%', height: '100%', overflow: 'hidden' }); } // The getBBox function is used in `alignDataLabel` to align // inside the box dataLabel.getBBox = () => ({ width, height, x: 0, y: 0 }); // Overwrite dataLabel dimensions (#13100). dataLabel.width = width; dataLabel.height = height; } super.alignDataLabel.apply(this, arguments); } createNode(id) { const node = super.createNode.call(this, id); // All nodes in an org chart are equal width node.getSum = () => 1; return node; } pointAttribs(point, state) { const series = this, attribs = SankeySeries.prototype.pointAttribs.call(series, point, state), level = point.isNode ? point.level : point.fromNode.level, levelOptions = series.mapOptionsToLevel[level || 0] || {}, options = point.options, stateOptions = (levelOptions.states && levelOptions.states[state]) || {}, borderRadius = pick(stateOptions.borderRadius, options.borderRadius, levelOptions.borderRadius, series.options.borderRadius), linkColor = pick(stateOptions.linkColor, options.linkColor, levelOptions.linkColor, series.options.linkColor, stateOptions.link && stateOptions.link.color, options.link && options.link.color, levelOptions.link && levelOptions.link.color, series.options.link && series.options.link.color), linkLineWidth = pick(stateOptions.linkLineWidth, options.linkLineWidth, levelOptions.linkLineWidth, series.options.linkLineWidth, stateOptions.link && stateOptions.link.lineWidth, options.link && options.link.lineWidth, levelOptions.link && levelOptions.link.lineWidth, series.options.link && series.options.link.lineWidth), linkOpacity = pick(stateOptions.linkOpacity, options.linkOpacity, levelOptions.linkOpacity, series.options.linkOpacity, stateOptions.link && stateOptions.link.linkOpacity, options.link && options.link.linkOpacity, levelOptions.link && levelOptions.link.linkOpacity, series.options.link && series.options.link.linkOpacity); if (!point.isNode) { attribs.stroke = linkColor; attribs['stroke-width'] = linkLineWidth; attribs.opacity = linkOpacity; delete attribs.fill; } else { if (isNumber(borderRadius)) { attribs.r = borderRadius; } } return attribs; } translateLink(point) { const chart = this.chart, options = this.options, fromNode = point.fromNode, toNode = point.toNode, linkWidth = pick(options.linkLineWidth, options.link.lineWidth), crisp = (Math.round(linkWidth) % 2) / 2, factor = pick(options.link.offset, 0.5), type = pick(point.options.link && point.options.link.type, options.link.type); if (fromNode.shapeArgs && toNode.shapeArgs) { const hangingIndent = options.hangingIndent, hangingRight = options.hangingSide === 'right', toOffset = toNode.options.offset, percentOffset = /%$/.test(toOffset) && parseInt(toOffset, 10), inverted = chart.inverted; let x1 = Math.floor((fromNode.shapeArgs.x || 0) + (fromNode.shapeArgs.width || 0)) + crisp, y1 = Math.floor((fromNode.shapeArgs.y || 0) + (fromNode.shapeArgs.height || 0) / 2) + crisp, x2 = Math.floor(toNode.shapeArgs.x || 0) + crisp, y2 = Math.floor((toNode.shapeArgs.y || 0) + (toNode.shapeArgs.height || 0) / 2) + crisp, xMiddle; if (inverted) { x1 -= (fromNode.shapeArgs.width || 0); x2 += (toNode.shapeArgs.width || 0); } xMiddle = this.colDistance ? Math.floor(x2 + ((inverted ? 1 : -1) * (this.colDistance - this.nodeWidth)) / 2) + crisp : Math.floor((x2 + x1) / 2) + crisp; // Put the link on the side of the node when an offset is given. HR // node in the main demo. if (percentOffset && (percentOffset >= 50 || percentOffset <= -50)) { xMiddle = x2 = Math.floor(x2 + (inverted ? -0.5 : 0.5) * (toNode.shapeArgs.width || 0)) + crisp; y2 = toNode.shapeArgs.y || 0; if (percentOffset > 0) { y2 += toNode.shapeArgs.height || 0; } } if (toNode.hangsFrom === fromNode) { if (chart.inverted) { y1 = !hangingRight ? Math.floor((fromNode.shapeArgs.y || 0) + (fromNode.shapeArgs.height || 0) - hangingIndent / 2) + crisp : Math.floor((fromNode.shapeArgs.y || 0) + hangingIndent / 2) + crisp; y2 = !hangingRight ? ((toNode.shapeArgs.y || 0) + (toNode.shapeArgs.height || 0)) : (toNode.shapeArgs.y || 0) + hangingIndent / 2; } else { y1 = Math.floor((fromNode.shapeArgs.y || 0) + hangingIndent / 2) + crisp; } xMiddle = x2 = Math.floor((toNode.shapeArgs.x || 0) + (toNode.shapeArgs.width || 0) / 2) + crisp; } point.plotX = xMiddle; point.plotY = (y1 + y2) / 2; point.shapeType = 'path'; if (type === 'straight') { point.shapeArgs = { d: [ ['M', x1, y1], ['L', x2, y2] ] }; } else if (type === 'curved') { const offset = Math.abs(x2 - x1) * factor * (inverted ? -1 : 1); point.shapeArgs = { d: [ ['M', x1, y1], ['C', x1 + offset, y1, x2 - offset, y2, x2, y2] ] }; } else { point.shapeArgs = { d: PathUtilities.applyRadius([ ['M', x1, y1], ['L', xMiddle, y1], ['L', xMiddle, y2], ['L', x2, y2] ], pick(options.linkRadius, options.link.radius)) }; } point.dlBox = { x: (x1 + x2) / 2, y: (y1 + y2) / 2, height: linkWidth, width: 0 }; } } translateNode(node, column) { super.translateNode(node, column); const chart = this.chart, options = this.options, sum = node.getSum(), translationFactor = this.translationFactor, nodeHeight = Math.max(Math.round(sum * translationFactor), options.minLinkWidth || 0), hangingRight = options.hangingSide === 'right', indent = options.hangingIndent || 0, indentLogic = options.hangingIndentTranslation, minLength = options.minNodeLength || 10, nodeWidth = Math.round(this.nodeWidth), shapeArgs = node.shapeArgs, sign = chart.inverted ? -1 : 1; let parentNode = node.hangsFrom; if (parentNode) { if (indentLogic === 'cumulative') { // Move to the right: shapeArgs.height -= indent; // If hanging right, first indent is handled by shrinking. if (chart.inverted && !hangingRight) { shapeArgs.y -= sign * indent; } while (parentNode) { // Hanging right is the same direction as non-inverted. shapeArgs.y += (hangingRight ? 1 : sign) * indent; parentNode = parentNode.hangsFrom; } } else if (indentLogic === 'shrink') { // Resize the node: while (parentNode && shapeArgs.height > indent + minLength) { shapeArgs.height -= indent; // Fixes nodes not dropping in non-inverted charts. // Hanging right is the same as non-inverted. if (!chart.inverted || hangingRight) { shapeArgs.y += indent; } parentNode = parentNode.hangsFrom; } } else { // Option indentLogic === "inherit" // Do nothing (v9.3.2 and prev versions): shapeArgs.height -= indent; if (!chart.inverted || hangingRight) { shapeArgs.y += indent; } } } node.nodeHeight = chart.inverted ? shapeArgs.width : shapeArgs.height; // Calculate shape args correctly to align nodes to center (#19946) if (node.shapeArgs && !node.hangsFrom) { node.shapeArgs = merge(node.shapeArgs, { x: (node.shapeArgs.x || 0) + (nodeWidth / 2) - ((node.shapeArgs.width || 0) / 2), y: (node.shapeArgs.y || 0) + (nodeHeight / 2) - ((node.shapeArgs.height || 0) / 2) }); } } drawDataLabels() { const dlOptions = this.options.dataLabels; if (dlOptions.linkTextPath && dlOptions.linkTextPath.enabled) { for (const link of this.points) { link.options.dataLabels = merge(link.options.dataLabels, { useHTML: false }); } } super.drawDataLabels(); } } /* * * * Static Properties * * */ OrganizationSeries.defaultOptions = merge(SankeySeries.defaultOptions, OrganizationSeriesDefaults); extend(OrganizationSeries.prototype, { pointClass: OrganizationPoint }); SeriesRegistry.registerSeriesType('organization', OrganizationSeries); /* * * * Default Export * * */ /* * * * API Declarations * * */ /** * Layout value for the child nodes in an organization chart. If `hanging`, this * node's children will hang below their parent, allowing a tighter packing of * nodes in the diagram. * * @typedef {"normal"|"hanging"} Highcharts.SeriesOrganizationNodesLayoutValue */ /** * Indent translation value for the child nodes in an organization chart, when * parent has `hanging` layout. Option can shrink nodes (for tight charts), * translate children to the left, or render nodes directly under the parent. * * @typedef {"inherit"|"cumulative"|"shrink"} Highcharts.OrganizationHangingIndentTranslationValue */ ''; // Detach doclets above return OrganizationSeries; }); _registerModule(_modules, 'masters/modules/organization.src.js', [_modules['Core/Globals.js']], function (Highcharts) { return Highcharts; }); }));