UNPKG

highcharts

Version:
1,473 lines (1,451 loc) 115 kB
/** * @license Highcharts JS v12.2.0 (2025-04-07) * @module highcharts/modules/networkgraph * @requires highcharts * * Force directed graph module * * (c) 2010-2025 Torstein Honsi * * License: www.highcharts.com/license */ import * as __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__ from "../highcharts.src.js"; /******/ // The require scope /******/ var __webpack_require__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = (module) => { /******/ var getter = module && module.__esModule ? /******/ () => (module['default']) : /******/ () => (module); /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /************************************************************************/ ;// external ["../highcharts.src.js","default"] const external_highcharts_src_js_default_namespaceObject = __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__["default"]; var external_highcharts_src_js_default_default = /*#__PURE__*/__webpack_require__.n(external_highcharts_src_js_default_namespaceObject); ;// external ["../highcharts.src.js","default","SVGElement"] const external_highcharts_src_js_default_SVGElement_namespaceObject = __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__["default"].SVGElement; var external_highcharts_src_js_default_SVGElement_default = /*#__PURE__*/__webpack_require__.n(external_highcharts_src_js_default_SVGElement_namespaceObject); ;// ./code/es-modules/Series/DragNodesComposition.js /* * * * Networkgraph series * * (c) 2010-2025 Paweł Fus * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ const { composed } = (external_highcharts_src_js_default_default()); const { addEvent, pushUnique } = (external_highcharts_src_js_default_default()); /* * * * Functions * * */ /** * @private */ function compose(ChartClass) { if (pushUnique(composed, 'DragNodes')) { addEvent(ChartClass, 'load', onChartLoad); } } /** * Draggable mode: * @private */ function onChartLoad() { const chart = this; let mousedownUnbinder, mousemoveUnbinder, mouseupUnbinder, point; if (chart.container) { mousedownUnbinder = addEvent(chart.container, 'mousedown', (event) => { if (mousemoveUnbinder) { mousemoveUnbinder(); } if (mouseupUnbinder) { mouseupUnbinder(); } point = chart.hoverPoint; if (point && point.series && point.series.hasDraggableNodes && point.series.options.draggable) { point.series.onMouseDown(point, event); mousemoveUnbinder = addEvent(chart.container, 'mousemove', (e) => (point && point.series && point.series.onMouseMove(point, e))); mouseupUnbinder = addEvent(chart.container.ownerDocument, 'mouseup', (e) => { mousemoveUnbinder(); mouseupUnbinder(); return point && point.series && point.series.onMouseUp(point, e); }); } }); } addEvent(chart, 'destroy', function () { mousedownUnbinder(); }); } /** * Mouse down action, initializing drag&drop mode. * * @private * @param {Highcharts.Point} point * The point that event occurred. * @param {Highcharts.PointerEventObject} event * Browser event, before normalization. */ function onMouseDown(point, event) { const normalizedEvent = this.chart.pointer?.normalize(event) || event; point.fixedPosition = { chartX: normalizedEvent.chartX, chartY: normalizedEvent.chartY, plotX: point.plotX, plotY: point.plotY }; point.inDragMode = true; } /** * Mouse move action during drag&drop. * * @private * * @param {Highcharts.Point} point * The point that event occurred. * @param {global.Event} event * Browser event, before normalization. */ function onMouseMove(point, event) { if (point.fixedPosition && point.inDragMode) { const series = this, chart = series.chart, normalizedEvent = chart.pointer?.normalize(event) || event, diffX = point.fixedPosition.chartX - normalizedEvent.chartX, diffY = point.fixedPosition.chartY - normalizedEvent.chartY, graphLayoutsLookup = chart.graphLayoutsLookup; let newPlotX, newPlotY; // At least 5px to apply change (avoids simple click): if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) { newPlotX = point.fixedPosition.plotX - diffX; newPlotY = point.fixedPosition.plotY - diffY; if (chart.isInsidePlot(newPlotX, newPlotY)) { point.plotX = newPlotX; point.plotY = newPlotY; point.hasDragged = true; this.redrawHalo(point); graphLayoutsLookup.forEach((layout) => { layout.restartSimulation(); }); } } } } /** * Mouse up action, finalizing drag&drop. * * @private * @param {Highcharts.Point} point * The point that event occurred. */ function onMouseUp(point) { if (point.fixedPosition) { if (point.hasDragged) { if (this.layout.enableSimulation) { this.layout.start(); } else { this.chart.redraw(); } } point.inDragMode = point.hasDragged = false; if (!this.options.fixedDraggable) { delete point.fixedPosition; } } } /** * Redraw halo on mousemove during the drag&drop action. * * @private * @param {Highcharts.Point} point * The point that should show halo. */ function redrawHalo(point) { if (point && this.halo) { this.halo.attr({ d: point.haloPath(this.options.states.hover.halo.size) }); } } /* * * * Default Export * * */ const DragNodesComposition = { compose, onMouseDown, onMouseMove, onMouseUp, redrawHalo }; /* harmony default export */ const Series_DragNodesComposition = (DragNodesComposition); ;// ./code/es-modules/Series/GraphLayoutComposition.js /* * * * Networkgraph series * * (c) 2010-2025 Paweł Fus * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ const { setAnimation } = (external_highcharts_src_js_default_default()); const { composed: GraphLayoutComposition_composed } = (external_highcharts_src_js_default_default()); const { addEvent: GraphLayoutComposition_addEvent, pushUnique: GraphLayoutComposition_pushUnique } = (external_highcharts_src_js_default_default()); /* * * * Constants * * */ const integrations = {}; const layouts = {}; /* * * * Functions * * */ /** * @private */ function GraphLayoutComposition_compose(ChartClass) { if (GraphLayoutComposition_pushUnique(GraphLayoutComposition_composed, 'GraphLayout')) { GraphLayoutComposition_addEvent(ChartClass, 'afterPrint', onChartAfterPrint); GraphLayoutComposition_addEvent(ChartClass, 'beforePrint', onChartBeforePrint); GraphLayoutComposition_addEvent(ChartClass, 'predraw', onChartPredraw); GraphLayoutComposition_addEvent(ChartClass, 'render', onChartRender); } } /** * Re-enable simulation after print. * @private */ function onChartAfterPrint() { if (this.graphLayoutsLookup) { this.graphLayoutsLookup.forEach((layout) => { // Return to default simulation layout.updateSimulation(); }); this.redraw(); } } /** * Disable simulation before print if enabled. * @private */ function onChartBeforePrint() { if (this.graphLayoutsLookup) { this.graphLayoutsLookup.forEach((layout) => { layout.updateSimulation(false); }); this.redraw(); } } /** * Clear previous layouts. * @private */ function onChartPredraw() { if (this.graphLayoutsLookup) { this.graphLayoutsLookup.forEach((layout) => { layout.stop(); }); } } /** * @private */ function onChartRender() { let systemsStable, afterRender = false; const layoutStep = (layout) => { if (layout.maxIterations-- && isFinite(layout.temperature) && !layout.isStable() && !layout.enableSimulation) { // Hook similar to build-in addEvent, but instead of // creating whole events logic, use just a function. // It's faster which is important for rAF code. // Used e.g. in packed-bubble series for bubble radius // calculations if (layout.beforeStep) { layout.beforeStep(); } layout.step(); systemsStable = false; afterRender = true; } }; if (this.graphLayoutsLookup) { setAnimation(false, this); // Start simulation this.graphLayoutsLookup.forEach((layout) => layout.start()); // Just one sync step, to run different layouts similar to // async mode. while (!systemsStable) { systemsStable = true; this.graphLayoutsLookup.forEach(layoutStep); } if (afterRender) { this.series.forEach((series) => { if (series && series.layout) { series.render(); } }); } } } /* * * * Default Export * * */ const GraphLayoutComposition = { compose: GraphLayoutComposition_compose, integrations, layouts }; /* harmony default export */ const Series_GraphLayoutComposition = (GraphLayoutComposition); ;// external ["../highcharts.src.js","default","SeriesRegistry"] const external_highcharts_src_js_default_SeriesRegistry_namespaceObject = __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__["default"].SeriesRegistry; var external_highcharts_src_js_default_SeriesRegistry_default = /*#__PURE__*/__webpack_require__.n(external_highcharts_src_js_default_SeriesRegistry_namespaceObject); ;// ./code/es-modules/Series/NodesComposition.js /* * * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ const { series: { prototype: seriesProto, prototype: { pointClass: { prototype: pointProto } } } } = (external_highcharts_src_js_default_SeriesRegistry_default()); const { defined, extend, find, merge, pick } = (external_highcharts_src_js_default_default()); /* * * * Composition * * */ var NodesComposition; (function (NodesComposition) { /* * * * Declarations * * */ /* * * * Functions * * */ /** * @private */ function compose(PointClass, SeriesClass) { const pointProto = PointClass.prototype, seriesProto = SeriesClass.prototype; pointProto.setNodeState = setNodeState; pointProto.setState = setNodeState; pointProto.update = updateNode; seriesProto.destroy = destroy; seriesProto.setData = setData; return SeriesClass; } NodesComposition.compose = compose; /** * Create a single node that holds information on incoming and outgoing * links. * @private */ function createNode(id) { const PointClass = this.pointClass, findById = (nodes, id) => find(nodes, (node) => node.id === id); let node = findById(this.nodes, id), options; if (!node) { options = this.options.nodes && findById(this.options.nodes, id); const newNode = new PointClass(this, extend({ className: 'highcharts-node', isNode: true, id: id, y: 1 // Pass isNull test }, options)); newNode.linksTo = []; newNode.linksFrom = []; /** * Return the largest sum of either the incoming or outgoing links. * @private */ newNode.getSum = function () { let sumTo = 0, sumFrom = 0; newNode.linksTo.forEach((link) => { sumTo += link.weight || 0; }); newNode.linksFrom.forEach((link) => { sumFrom += link.weight || 0; }); return Math.max(sumTo, sumFrom); }; /** * Get the offset in weight values of a point/link. * @private */ newNode.offset = function (point, coll) { let offset = 0; for (let i = 0; i < newNode[coll].length; i++) { if (newNode[coll][i] === point) { return offset; } offset += newNode[coll][i].weight; } }; // Return true if the node has a shape, otherwise all links are // outgoing. newNode.hasShape = function () { let outgoing = 0; newNode.linksTo.forEach((link) => { if (link.outgoing) { outgoing++; } }); return (!newNode.linksTo.length || outgoing !== newNode.linksTo.length); }; newNode.index = this.nodes.push(newNode) - 1; node = newNode; } node.formatPrefix = 'node'; // For use in formats node.name = node.name || node.options.id || ''; // Mass is used in networkgraph: node.mass = pick( // Node: node.options.mass, node.options.marker && node.options.marker.radius, // Series: this.options.marker && this.options.marker.radius, // Default: 4); return node; } NodesComposition.createNode = createNode; /** * Destroy all nodes and links. * @private */ function destroy() { // Nodes must also be destroyed (#8682, #9300) this.data = [] .concat(this.points || [], this.nodes); return seriesProto.destroy.apply(this, arguments); } NodesComposition.destroy = destroy; /** * Extend generatePoints by adding the nodes, which are Point objects but * pushed to the this.nodes array. * @private */ function generatePoints() { const chart = this.chart, nodeLookup = {}; seriesProto.generatePoints.call(this); if (!this.nodes) { this.nodes = []; // List of Point-like node items } this.colorCounter = 0; // Reset links from previous run this.nodes.forEach((node) => { node.linksFrom.length = 0; node.linksTo.length = 0; node.level = node.options.level; }); // Create the node list and set up links this.points.forEach((point) => { if (defined(point.from)) { if (!nodeLookup[point.from]) { nodeLookup[point.from] = this.createNode(point.from); } nodeLookup[point.from].linksFrom.push(point); point.fromNode = nodeLookup[point.from]; // Point color defaults to the fromNode's color if (chart.styledMode) { point.colorIndex = pick(point.options.colorIndex, nodeLookup[point.from].colorIndex); } else { point.color = point.options.color || nodeLookup[point.from].color; } } if (defined(point.to)) { if (!nodeLookup[point.to]) { nodeLookup[point.to] = this.createNode(point.to); } nodeLookup[point.to].linksTo.push(point); point.toNode = nodeLookup[point.to]; } point.name = point.name || point.id; // For use in formats }, this); // Store lookup table for later use this.nodeLookup = nodeLookup; } NodesComposition.generatePoints = generatePoints; /** * Destroy all nodes on setting new data * @private */ function setData() { if (this.nodes) { this.nodes.forEach((node) => { node.destroy(); }); this.nodes.length = 0; } seriesProto.setData.apply(this, arguments); } /** * When hovering node, highlight all connected links. When hovering a link, * highlight all connected nodes. * @private */ function setNodeState(state) { const args = arguments, others = this.isNode ? this.linksTo.concat(this.linksFrom) : [this.fromNode, this.toNode]; if (state !== 'select') { others.forEach((linkOrNode) => { if (linkOrNode && linkOrNode.series) { pointProto.setState.apply(linkOrNode, args); if (!linkOrNode.isNode) { if (linkOrNode.fromNode.graphic) { pointProto.setState.apply(linkOrNode.fromNode, args); } if (linkOrNode.toNode && linkOrNode.toNode.graphic) { pointProto.setState.apply(linkOrNode.toNode, args); } } } }); } pointProto.setState.apply(this, args); } NodesComposition.setNodeState = setNodeState; /** * When updating a node, don't update `series.options.data`, but * `series.options.nodes` * @private */ function updateNode(options, redraw, animation, runEvent) { const nodes = this.series.options.nodes, data = this.series.options.data, dataLength = data?.length || 0, linkConfig = data?.[this.index]; pointProto.update.call(this, options, this.isNode ? false : redraw, // Hold the redraw for nodes animation, runEvent); if (this.isNode) { // `this.index` refers to `series.nodes`, not `options.nodes` array const nodeIndex = (nodes || []) .reduce(// Array.findIndex needs a polyfill (prevIndex, n, index) => (this.id === n.id ? index : prevIndex), -1), // Merge old config with new config. New config is stored in // options.data, because of default logic in point.update() nodeConfig = merge(nodes && nodes[nodeIndex] || {}, data?.[this.index] || {}); // Restore link config if (data) { if (linkConfig) { data[this.index] = linkConfig; } else { // Remove node from config if there's more nodes than links data.length = dataLength; } } // Set node config if (nodes) { if (nodeIndex >= 0) { nodes[nodeIndex] = nodeConfig; } else { nodes.push(nodeConfig); } } else { this.series.options.nodes = [nodeConfig]; } if (pick(redraw, true)) { this.series.chart.redraw(animation); } } } NodesComposition.updateNode = updateNode; })(NodesComposition || (NodesComposition = {})); /* * * * Default Export * * */ /* harmony default export */ const Series_NodesComposition = (NodesComposition); ;// ./code/es-modules/Series/Networkgraph/NetworkgraphPoint.js /* * * * Networkgraph series * * (c) 2010-2025 Paweł Fus * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ const { series: { prototype: NetworkgraphPoint_seriesProto, prototype: { pointClass: Point } } } = (external_highcharts_src_js_default_SeriesRegistry_default()); const { addEvent: NetworkgraphPoint_addEvent, css, defined: NetworkgraphPoint_defined, extend: NetworkgraphPoint_extend, pick: NetworkgraphPoint_pick } = (external_highcharts_src_js_default_default()); /* * * * Class * * */ class NetworkgraphPoint extends Point { /* * * * Functions * * */ /** * Destroy point. If it's a node, remove all links coming out of this * node. Then remove point from the layout. * @private */ destroy() { if (this.isNode) { this.linksFrom.concat(this.linksTo).forEach(function (link) { // Removing multiple nodes at the same time // will try to remove link between nodes twice if (link.destroyElements) { link.destroyElements(); } }); } this.series.layout.removeElementFromCollection(this, this.series.layout[this.isNode ? 'nodes' : 'links']); return Point.prototype.destroy.apply(this, arguments); } /** * Return degree of a node. If node has no connections, it still has * deg=1. * @private */ getDegree() { const deg = this.isNode ? this.linksFrom.length + this.linksTo.length : 0; return deg === 0 ? 1 : deg; } /** * Get presentational attributes of link connecting two nodes. * @private */ getLinkAttributes() { const linkOptions = this.series.options.link, pointOptions = this.options; return { 'stroke-width': NetworkgraphPoint_pick(pointOptions.width, linkOptions.width), stroke: (pointOptions.color || linkOptions.color), dashstyle: (pointOptions.dashStyle || linkOptions.dashStyle), opacity: NetworkgraphPoint_pick(pointOptions.opacity, linkOptions.opacity, 1) }; } /** * Get link path connecting two nodes. * @private * @return {Array<Highcharts.SVGPathArray>} * Path: `['M', x, y, 'L', x, y]` */ getLinkPath() { let left = this.fromNode, right = this.toNode; // Start always from left to the right node, to prevent rendering // labels upside down if (left.plotX > right.plotX) { left = this.toNode; right = this.fromNode; } return [ ['M', left.plotX || 0, left.plotY || 0], ['L', right.plotX || 0, right.plotY || 0] ]; /* IDEA: different link shapes? return [ 'M', from.plotX, from.plotY, 'Q', (to.plotX + from.plotX) / 2, (to.plotY + from.plotY) / 2 + 15, to.plotX, to.plotY ];*/ } /** * Get mass fraction applied on two nodes connected to each other. By * default, when mass is equal to `1`, mass fraction for both nodes * equal to 0.5. * @private * @return {Highcharts.Dictionary<number>} * For example `{ fromNode: 0.5, toNode: 0.5 }` */ getMass() { const m1 = this.fromNode.mass, m2 = this.toNode.mass, sum = m1 + m2; return { fromNode: 1 - m1 / sum, toNode: 1 - m2 / sum }; } /** * Basic `point.init()` and additional styles applied when * `series.draggable` is enabled. * @private */ constructor(series, options, x) { super(series, options, x); if (this.series.options.draggable && !this.series.chart.styledMode) { NetworkgraphPoint_addEvent(this, 'mouseOver', function () { css(this.series.chart.container, { cursor: 'move' }); }); NetworkgraphPoint_addEvent(this, 'mouseOut', function () { css(this.series.chart.container, { cursor: 'default' }); }); } } /** * @private */ isValid() { return !this.isNode || NetworkgraphPoint_defined(this.id); } /** * Redraw link's path. * @private */ redrawLink() { const path = this.getLinkPath(); let attribs; if (this.graphic) { this.shapeArgs = { d: path }; if (!this.series.chart.styledMode) { attribs = this.series.pointAttribs(this); this.graphic.attr(attribs); (this.dataLabels || []).forEach(function (label) { if (label) { label.attr({ opacity: attribs.opacity }); } }); } this.graphic.animate(this.shapeArgs); // Required for dataLabels const start = path[0]; const end = path[1]; if (start[0] === 'M' && end[0] === 'L') { this.plotX = (start[1] + end[1]) / 2; this.plotY = (start[2] + end[2]) / 2; } } } /** * Common method for removing points and nodes in networkgraph. To * remove `link`, use `series.data[index].remove()`. To remove `node` * with all connections, use `series.nodes[index].remove()`. * @private * @param {boolean} [redraw=true] * Whether to redraw the chart or wait for an explicit call. When * doing more operations on the chart, for example running * `point.remove()` in a loop, it is best practice to set * `redraw` to false and call `chart.redraw()` after. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=false] * Whether to apply animation, and optionally animation * configuration. */ remove(redraw, animation) { const point = this, series = point.series, nodesOptions = series.options.nodes || []; let index, i = nodesOptions.length; // For nodes, remove all connected links: if (point.isNode) { // Temporary disable series.points array, because // Series.removePoint() modifies it series.points = []; // Remove link from all nodes collections: [] .concat(point.linksFrom) .concat(point.linksTo) .forEach(function (linkFromTo) { // Incoming links index = linkFromTo.fromNode.linksFrom.indexOf(linkFromTo); if (index > -1) { linkFromTo.fromNode.linksFrom.splice(index, 1); } // Outcoming links index = linkFromTo.toNode.linksTo.indexOf(linkFromTo); if (index > -1) { linkFromTo.toNode.linksTo.splice(index, 1); } // Remove link from data/points collections NetworkgraphPoint_seriesProto.removePoint.call(series, series.data.indexOf(linkFromTo), false, false); }); // Restore points array, after links are removed series.points = series.data.slice(); // Proceed with removing node. It's similar to // Series.removePoint() method, but doesn't modify other arrays series.nodes.splice(series.nodes.indexOf(point), 1); // Remove node options from config while (i--) { if (nodesOptions[i].id === point.options.id) { series.options.nodes.splice(i, 1); break; } } if (point) { point.destroy(); } // Run redraw if requested series.isDirty = true; series.isDirtyData = true; if (redraw) { series.chart.redraw(redraw); } } else { series.removePoint(series.data.indexOf(point), redraw, animation); } } /** * Render link and add it to the DOM. * @private */ renderLink() { let attribs; if (!this.graphic) { this.graphic = this.series.chart.renderer .path(this.getLinkPath()) .addClass(this.getClassName(), true) .add(this.series.group); if (!this.series.chart.styledMode) { attribs = this.series.pointAttribs(this); this.graphic.attr(attribs); (this.dataLabels || []).forEach(function (label) { if (label) { label.attr({ opacity: attribs.opacity }); } }); } } } } NetworkgraphPoint_extend(NetworkgraphPoint.prototype, { setState: Series_NodesComposition.setNodeState }); /* * * * Default Export * * */ /* harmony default export */ const Networkgraph_NetworkgraphPoint = (NetworkgraphPoint); ;// ./code/es-modules/Series/Networkgraph/NetworkgraphSeriesDefaults.js /* * * * Networkgraph series * * (c) 2010-2025 Paweł Fus * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ /* * * * Constants * * */ /** * A networkgraph is a type of relationship chart, where connnections * (links) attracts nodes (points) and other nodes repulse each other. * * @extends plotOptions.line * @product highcharts * @sample highcharts/demo/network-graph/ * Networkgraph * @since 7.0.0 * @excluding boostThreshold, animation, animationLimit, connectEnds, * colorAxis, colorKey, connectNulls, cropThreshold, dragDrop, * getExtremesFromAll, label, linecap, negativeColor, * pointInterval, pointIntervalUnit, pointPlacement, * pointStart, softThreshold, stack, stacking, step, * threshold, xAxis, yAxis, zoneAxis, dataSorting, * boostBlending * @requires modules/networkgraph * @optionparent plotOptions.networkgraph * * @private */ const NetworkgraphSeriesDefaults = { stickyTracking: false, /** * @default true * @extends plotOptions.series.inactiveOtherPoints * @private */ inactiveOtherPoints: true, marker: { enabled: true, states: { /** * The opposite state of a hover for a single point node. * Applied to all not connected nodes to the hovered one. * * @declare Highcharts.PointStatesInactiveOptionsObject */ inactive: { /** * Opacity of inactive markers. */ opacity: 0.3, /** * Animation when not hovering over the node. * * @type {boolean|Partial<Highcharts.AnimationOptionsObject>} */ animation: { /** @internal */ duration: 50 } } } }, states: { /** * The opposite state of a hover for a single point link. Applied * to all links that are not coming from the hovered node. * * @declare Highcharts.SeriesStatesInactiveOptionsObject */ inactive: { /** * Opacity of inactive links. */ linkOpacity: 0.3, /** * Animation when not hovering over the node. * * @type {boolean|Partial<Highcharts.AnimationOptionsObject>} */ animation: { /** @internal */ duration: 50 } } }, /** * @sample highcharts/series-networkgraph/link-datalabels * Networkgraph with labels on links * @sample highcharts/series-networkgraph/textpath-datalabels * Networkgraph with labels around nodes * @sample highcharts/series-networkgraph/link-datalabels * Data labels moved into the nodes * @sample highcharts/series-networkgraph/link-datalabels * Data labels moved under the links * * @declare Highcharts.SeriesNetworkgraphDataLabelsOptionsObject * * @private */ dataLabels: { /** * The * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting) * specifying what to show for _node_ in the networkgraph. In v7.0 * defaults to `{key}`, since v7.1 defaults to `undefined` and * `formatter` is used instead. * * @type {string} * @since 7.0.0 * @apioption plotOptions.networkgraph.dataLabels.format */ // eslint-disable-next-line valid-jsdoc /** * Callback JavaScript function to format the data label for a node. * Note that if a `format` is defined, the format takes precedence * and the formatter is ignored. * * @since 7.0.0 */ formatter: function () { return String(this.key ?? ''); }, /** * The * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting) * specifying what to show for _links_ in the networkgraph. * (Default: `undefined`) * * @type {string} * @since 7.1.0 * @apioption plotOptions.networkgraph.dataLabels.linkFormat */ // eslint-disable-next-line valid-jsdoc /** * Callback to format data labels for _links_ in the sankey diagram. * The `linkFormat` option takes precedence over the * `linkFormatter`. * * @since 7.1.0 */ linkFormatter: function () { return (this.fromNode.name + '<br>' + this.toNode.name); }, /** * Options for a _link_ label text which should follow link * connection. Border and background are disabled for a label that * follows a path. * * **Note:** Only SVG-based renderer supports this option. Setting * `useHTML` to true will disable this option. * * @extends plotOptions.networkgraph.dataLabels.textPath * @since 7.1.0 */ linkTextPath: { enabled: true }, textPath: { enabled: false }, style: { transition: 'opacity 2000ms' }, defer: true, animation: { defer: 1000 } }, /** * Link style options * @private */ link: { /** * A name for the dash style to use for links. * * @type {string} * @apioption plotOptions.networkgraph.link.dashStyle */ /** * Opacity of the link between two nodes. * * @type {number} * @default 1 * @apioption plotOptions.networkgraph.link.opacity */ /** * Color of the link between two nodes. */ color: 'rgba(100, 100, 100, 0.5)', /** * Width (px) of the link between two nodes. */ width: 1 }, /** * Flag to determine if nodes are draggable or not. * @private */ draggable: true, layoutAlgorithm: { /** * Repulsive force applied on a node. Passed are two arguments: * - `d` - which is current distance between two nodes * - `k` - which is desired distance between two nodes * * In `verlet` integration, defaults to: * `function (d, k) { return (k - d) / d * (k > d ? 1 : 0) }` * * @see [layoutAlgorithm.integration](#series.networkgraph.layoutAlgorithm.integration) * * @sample highcharts/series-networkgraph/forces/ * Custom forces with Euler integration * @sample highcharts/series-networkgraph/cuboids/ * Custom forces with Verlet integration * * @type {Function} * @default function (d, k) { return k * k / d; } * @apioption plotOptions.networkgraph.layoutAlgorithm.repulsiveForce */ /** * Attraction force applied on a node which is conected to another * node by a link. Passed are two arguments: * - `d` - which is current distance between two nodes * - `k` - which is desired distance between two nodes * * In `verlet` integration, defaults to: * `function (d, k) { return (k - d) / d; }` * * @see [layoutAlgorithm.integration](#series.networkgraph.layoutAlgorithm.integration) * * @sample highcharts/series-networkgraph/forces/ * Custom forces with Euler integration * @sample highcharts/series-networkgraph/cuboids/ * Custom forces with Verlet integration * * @type {Function} * @default function (d, k) { return k * k / d; } * @apioption plotOptions.networkgraph.layoutAlgorithm.attractiveForce */ /** * Ideal length (px) of the link between two nodes. When not * defined, length is calculated as: * `Math.pow(availableWidth * availableHeight / nodesLength, 0.4);` * * Note: Because of the algorithm specification, length of each link * might be not exactly as specified. * * @sample highcharts/series-networkgraph/styled-links/ * Numerical values * * @type {number} * @apioption plotOptions.networkgraph.layoutAlgorithm.linkLength */ /** * Initial layout algorithm for positioning nodes. Can be one of * built-in options ("circle", "random") or a function where * positions should be set on each node (`this.nodes`) as * `node.plotX` and `node.plotY` * * @sample highcharts/series-networkgraph/initial-positions/ * Initial positions with callback * * @type {"circle"|"random"|Function} */ initialPositions: 'circle', /** * When `initialPositions` are set to 'circle', * `initialPositionRadius` is a distance from the center of circle, * in which nodes are created. * * @type {number} * @default 1 * @since 7.1.0 */ initialPositionRadius: 1, /** * Experimental. Enables live simulation of the algorithm * implementation. All nodes are animated as the forces applies on * them. * * @sample highcharts/demo/network-graph/ * Live simulation enabled */ enableSimulation: false, /** * Barnes-Hut approximation only. * Deteremines when distance between cell and node is small enough * to calculate forces. Value of `theta` is compared directly with * quotient `s / d`, where `s` is the size of the cell, and `d` is * distance between center of cell's mass and currently compared * node. * * @see [layoutAlgorithm.approximation](#series.networkgraph.layoutAlgorithm.approximation) * * @since 7.1.0 */ theta: 0.5, /** * Verlet integration only. * Max speed that node can get in one iteration. In terms of * simulation, it's a maximum translation (in pixels) that node can * move (in both, x and y, dimensions). While `friction` is applied * on all nodes, max speed is applied only for nodes that move very * fast, for example small or disconnected ones. * * @see [layoutAlgorithm.integration](#series.networkgraph.layoutAlgorithm.integration) * @see [layoutAlgorithm.friction](#series.networkgraph.layoutAlgorithm.friction) * * @since 7.1.0 */ maxSpeed: 10, /** * Approximation used to calculate repulsive forces affecting nodes. * By default, when calculating net force, nodes are compared * against each other, which gives O(N^2) complexity. Using * Barnes-Hut approximation, we decrease this to O(N log N), but the * resulting graph will have different layout. Barnes-Hut * approximation divides space into rectangles via quad tree, where * forces exerted on nodes are calculated directly for nearby cells, * and for all others, cells are treated as a separate node with * center of mass. * * @see [layoutAlgorithm.theta](#series.networkgraph.layoutAlgorithm.theta) * * @sample highcharts/series-networkgraph/barnes-hut-approximation/ * A graph with Barnes-Hut approximation * * @type {string} * @validvalue ["barnes-hut", "none"] * @since 7.1.0 */ approximation: 'none', /** * Type of the algorithm used when positioning nodes. * * @type {string} * @validvalue ["reingold-fruchterman"] */ type: 'reingold-fruchterman', /** * Integration type. Available options are `'euler'` and `'verlet'`. * Integration determines how forces are applied on particles. In * Euler integration, force is applied direct as * `newPosition += velocity;`. * In Verlet integration, new position is based on a previous * position without velocity: * `newPosition += previousPosition - newPosition`. * * Note that different integrations give different results as forces * are different. * * In Highcharts v7.0.x only `'euler'` integration was supported. * * @sample highcharts/series-networkgraph/integration-comparison/ * Comparison of Verlet and Euler integrations * * @type {string} * @validvalue ["euler", "verlet"] * @since 7.1.0 */ integration: 'euler', /** * Max number of iterations before algorithm will stop. In general, * algorithm should find positions sooner, but when rendering huge * number of nodes, it is recommended to increase this value as * finding perfect graph positions can require more time. */ maxIterations: 1000, /** * Gravitational const used in the barycenter force of the * algorithm. * * @sample highcharts/series-networkgraph/forces/ * Custom forces with Euler integration */ gravitationalConstant: 0.0625, /** * Friction applied on forces to prevent nodes rushing to fast to * the desired positions. */ friction: -0.981 }, showInLegend: false }; /* * * * Default Export * * */ /* harmony default export */ const Networkgraph_NetworkgraphSeriesDefaults = (NetworkgraphSeriesDefaults); /* * * * API Options * * */ /** * Fires after the simulation is ended and the layout is stable. * * @type {Highcharts.NetworkgraphAfterSimulationCallbackFunction} * @product highcharts * @apioption series.networkgraph.events.afterSimulation */ /** * A `networkgraph` series. If the [type](#series.networkgraph.type) option is * not specified, it is inherited from [chart.type](#chart.type). * * @extends series,plotOptions.networkgraph * @excluding boostThreshold, animation, animationLimit, connectEnds, * connectNulls, cropThreshold, dragDrop, getExtremesFromAll, label, * linecap, negativeColor, pointInterval, pointIntervalUnit, * pointPlacement, pointStart, softThreshold, stack, stacking, * step, threshold, xAxis, yAxis, zoneAxis, dataSorting, * boostBlending * @product highcharts * @requires modules/networkgraph * @apioption series.networkgraph */ /** * An array of data points for the series. For the `networkgraph` 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' * }, { * from: 'Category1', * to: 'Category3' * }] * ``` * * @type {Array<Object|Array|number>} * @extends series.line.data * @excluding drilldown,marker,x,y,dragDrop * @sample {highcharts} highcharts/chart/reflow-true/ * Numerical values * @sample {highcharts} highcharts/series/data-array-of-arrays/ * Arrays of numeric x and y * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ * Arrays of datetime x and y * @sample {highcharts} highcharts/series/data-array-of-name-value/ * Arrays of point.name and y * @sample {highcharts} highcharts/series/data-array-of-objects/ * Config objects * @product highcharts * @apioption series.networkgraph.data */ /** * @type {Highcharts.SeriesNetworkgraphDataLabelsOptionsObject|Array<Highcharts.SeriesNetworkgraphDataLabelsOptionsObject>} * @product highcharts * @apioption series.networkgraph.data.dataLabels */ /** * The node that the link runs from. * * @type {string} * @product highcharts * @apioption series.networkgraph.data.from */ /** * The node that the link runs to. * * @type {string} * @product highcharts * @apioption series.networkgraph.data.to */ /** * A collection of options for the individual nodes. The nodes in a * networkgraph diagram are auto-generated instances of `Highcharts.Point`, * but options can be applied here and linked by the `id`. * * @sample highcharts/series-networkgraph/data-options/ * Networkgraph diagram with node options * * @type {Array<*>} * @product highcharts * @apioption series.networkgraph.nodes */ /** * The id of the auto-generated node, referring to the `from` or `to` setting of * the link. * * @type {string} * @product highcharts * @apioption series.networkgraph.nodes.id */ /** * The color of the auto generated node. * * @type {Highcharts.ColorString} * @product highcharts * @apioption series.networkgraph.nodes.color */ /** * The color index of the auto generated node, especially for use in styled * mode. * * @type {number} * @product highcharts * @apioption series.networkgraph.nodes.colorIndex */ /** * The name to display for the node in data labels and tooltips. Use this when * the name is different from the `id`. Where the id must be unique for each * node, this is not necessary for the name. * * @sample highcharts/series-networkgraph/data-options/ * Networkgraph diagram with node options * * @type {string} * @product highcharts * @apioption series.networkgraph.nodes.name */ /** * Mass of the node. By default, each node has mass equal to it's marker radius * . Mass is used to determine how two connected nodes should affect * each other: * * Attractive force is multiplied by the ratio of two connected * nodes; if a big node has weights twice as the small one, then the small one * will move towards the big one twice faster than the big one to the small one * . * * @sample highcharts/series-networkgraph/ragdoll/ * Mass determined by marker.radius * * @type {number} * @product highcharts * @apioption series.networkgraph.nodes.mass */ /** * Options for the node markers. * * @extends plotOptions.networkgraph.marker * @apioption series.networkgraph.nodes.marker */ /** * Individual data label for each node. The options are the same as * the ones for [series.networkgraph.dataLabels](#series.networkgraph.dataLabels). * * @type {Highcharts.SeriesNetworkgraphDataLabelsOptionsObject|Array<Highcharts.SeriesNetworkgraphDataLabelsOptionsObject>} * * @apioption series.networkgraph.nodes.dataLabels */ ''; // Adds doclets above to transpiled file ;// ./code/es-modules/Series/Networkgraph/EulerIntegration.js /* * * * Networkgraph series * * (c) 2010-2025 Paweł Fus * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */