package.modules.organization.src.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of highcharts Show documentation
Show all versions of highcharts Show documentation
JavaScript charting framework
The newest version!
/**
* @license Highcharts JS v11.4.8 (2024-08-29)
* 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') {
Highcharts.win.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 version 10.0.0, 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'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Extensions/TextPath.js']], function (OrganizationPoint, OrganizationSeriesDefaults, SeriesRegistry, PathUtilities, U, SVGElement, TextPath) {
/* *
*
* 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, crisp, extend, isNumber, merge, pick } = U;
TextPath.compose(SVGElement);
/* *
*
* 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, 0), 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 = crisp((fromNode.shapeArgs.x || 0) +
(fromNode.shapeArgs.width || 0), linkWidth), y1 = crisp((fromNode.shapeArgs.y || 0) +
(fromNode.shapeArgs.height || 0) / 2, linkWidth), x2 = crisp(toNode.shapeArgs.x || 0, linkWidth), y2 = crisp((toNode.shapeArgs.y || 0) +
(toNode.shapeArgs.height || 0) / 2, linkWidth), xMiddle;
if (inverted) {
x1 -= (fromNode.shapeArgs.width || 0);
x2 += (toNode.shapeArgs.width || 0);
}
xMiddle = this.colDistance ?
crisp(x2 +
((inverted ? 1 : -1) *
(this.colDistance - this.nodeWidth)) /
2, linkWidth) :
crisp((x2 + x1) / 2, linkWidth);
// 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 = crisp(x2 + (inverted ? -0.5 : 0.5) *
(toNode.shapeArgs.width || 0), linkWidth);
y2 = toNode.shapeArgs.y || 0;
if (percentOffset > 0) {
y2 += toNode.shapeArgs.height || 0;
}
}
if (toNode.hangsFrom === fromNode) {
if (chart.inverted) {
y1 = !hangingRight ?
crisp((fromNode.shapeArgs.y || 0) +
(fromNode.shapeArgs.height || 0) -
hangingIndent / 2, linkWidth) :
crisp((fromNode.shapeArgs.y || 0) + hangingIndent / 2, linkWidth);
y2 = !hangingRight ? ((toNode.shapeArgs.y || 0) +
(toNode.shapeArgs.height || 0)) : (toNode.shapeArgs.y || 0) + hangingIndent / 2;
}
else {
y1 = crisp((fromNode.shapeArgs.y || 0) + hangingIndent / 2, linkWidth);
}
xMiddle = x2 = crisp((toNode.shapeArgs.x || 0) +
(toNode.shapeArgs.width || 0) / 2, linkWidth);
}
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;
});
}));