highcharts
Version:
JavaScript charting framework
13 lines • 16.8 kB
JavaScript
/**
* Highcharts JS v13.0.1 (2026-08-17)
* @module highcharts/modules/sankey
* @requires highcharts
*
* Sankey diagram module
*
* (c) 2010-2026 Highsoft AS
* Author: Torstein Hønsi
*
* A commercial license may be required depending on use,
* see www.highcharts.com/license
*/import*as t from"../highcharts.js";let e={};e.n=t=>{let o=t&&t.__esModule?()=>t.default:()=>t;return e.d(o,{a:o}),o},e.d=(t,o)=>{if(Array.isArray(o))for(var i=0;i<o.length;){var s=o[i++],n=o[i++];e.o(t,s)?0===n&&i++:0===n?Object.defineProperty(t,s,{enumerable:!0,value:o[i++]}):Object.defineProperty(t,s,{enumerable:!0,get:n})}else for(var s in o)e.o(o,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:o[s]})},e.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);let o=t.default;var i,s,n,r=e.n(o);let l=t.default.SeriesRegistry;var a=e.n(l);let{series:{prototype:d,prototype:{pointClass:{prototype:h}}}}=a();!function(t){function e(){if(!this.hasDataLabels?.()&&this.nodes)for(let t of this.nodes)t.destroyElements({dataLabel:1})}function i(){return this.data=[].concat(this.points||[],this.nodes),d.destroy.apply(this,arguments)}function s(){this.nodes&&(this.nodes.forEach(t=>{t.destroy()}),this.nodes.length=0),d.setData.apply(this,arguments)}function n(t){let e=arguments,o=this.isNode?this.linksTo.concat(this.linksFrom):[this.fromNode,this.toNode];"select"!==t&&o.forEach(t=>{t&&t.series&&(h.setState.apply(t,e),!t.isNode&&(t.fromNode.graphic&&h.setState.apply(t.fromNode,e),t.toNode&&t.toNode.graphic&&h.setState.apply(t.toNode,e)))}),h.setState.apply(this,e)}function r(t,e,i,s){let n=this.series.options.nodes,r=this.series.options.data,l=r?.length||0,a=r?.[this.index];if(h.update.call(this,t,!this.isNode&&e,i,s),this.isNode){let t=(n||[]).reduce((t,e,o)=>this.id===e.id?o:t,-1),s=(0,o.merge)(n&&n[t]||{},r?.[this.index]||{});r&&(a?r[this.index]=a:r.length=l),n?t>=0?n[t]=s:n.push(s):this.series.options.nodes=[s],(0,o.pick)(e,!0)&&this.series.chart.redraw(i)}}t.compose=function(t,l){let a=t.prototype,d=l.prototype;return a.setNodeState=n,a.setState=n,a.update=r,d.destroy=i,d.setData=s,(0,o.addEvent)(l,"afterUpdate",e),l},t.createNode=function(t){let e=this.pointClass,i=(t,e)=>(0,o.find)(t,t=>t.id===e),s=i(this.nodes,t),n;if(!s){n=this.options.nodes&&i(this.options.nodes,t);let r=new e(this,(0,o.extend)({className:"highcharts-node",isNode:!0,id:t,y:1},n));r.linksTo=[],r.linksFrom=[],r.getSum=function(){let t=0,e=0;return r.linksTo.forEach(e=>{t+=e.weight||0}),r.linksFrom.forEach(t=>{e+=t.weight||0}),Math.max(t,e)},r.offset=function(t,e){let o=0;for(let i=0;i<r[e].length;i++){if(r[e][i]===t)return o;o+=r[e][i].weight}},r.hasShape=function(){let t=0;return r.linksTo.forEach(e=>{e.outgoing&&t++}),!r.linksTo.length||t!==r.linksTo.length},r.index=this.nodes.push(r)-1,s=r}return s.formatPrefix="node",s.name=s.name||s.options.id||"",s.mass=(0,o.pick)(s.options.mass,s.options.marker&&s.options.marker.radius,this.options.marker&&this.options.marker.radius,4),s},t.destroy=i,t.generatePoints=function(){let t=this.chart,e={};d.generatePoints.call(this),this.nodes||(this.nodes=[]),this.colorCounter=0,this.nodes.forEach(t=>{t.linksFrom.length=0,t.linksTo.length=0,t.level=t.options.level}),this.points.forEach(i=>{(0,o.defined)(i.from)&&(e[i.from]||(e[i.from]=this.createNode(i.from)),e[i.from].linksFrom.push(i),i.fromNode=e[i.from],t.styledMode?i.colorIndex=(0,o.pick)(i.options.colorIndex,e[i.from].colorIndex):i.color=i.options.color||e[i.from].color),(0,o.defined)(i.to)&&(e[i.to]||(e[i.to]=this.createNode(i.to)),e[i.to].linksTo.push(i),i.toNode=e[i.to]),i.name=i.name||i.id},this),this.nodeLookup=e},t.setNodeState=n,t.updateNode=r}(s||(s={}));let p=s,c=t.default.Point;var f=e.n(c);let{column:u}=a().seriesTypes;class m extends u.prototype.pointClass{applyOptions(t,e){return f().prototype.applyOptions.call(this,t,e),(0,o.defined)(this.options.level)&&(this.options.column=this.column=this.options.level),this}getClassName(){return(this.isNode?"highcharts-node ":"highcharts-link ")+f().prototype.getClassName.call(this)}getFromNode(){let t=-1,e;for(let o=0;o<this.linksTo.length;o++){let i=this.linksTo[o];i.fromNode.column>t&&i.fromNode!==this&&(t=(e=i.fromNode).column)}return{fromNode:e,fromColumn:t}}setNodeColumn(){(0,o.defined)(this.options.column)||(0===this.linksTo.length?this.column=0:this.column=this.getFromNode().fromColumn+1)}isValid(){return this.isNode||"number"==typeof this.weight}}var g=n||(n={});g.compose=function(t,e){return t.sankeyColumn=new y(t,e),t};class y{constructor(t,e){this.points=t,this.series=e}getTranslationFactor(t){let e=this.points,o=e.slice(),i=t.chart,s=t.options.minLinkWidth||0,n,r=0,l,a=(i.plotSizeY||0)-(t.options.borderWidth||0)-(e.length-1)*t.nodePadding;for(;e.length;){for(r=a/e.sankeyColumn.sum(),n=!1,l=e.length;l--;)e[l].getSum()*r<s&&(e.splice(l,1),a=Math.max(0,a-s),n=!0);if(!n)break}for(let t of(e.length=0,o))e.push(t);return r}top(t){let e=this.series,i=e.nodePadding,s=this.points.reduce((o,s)=>(o>0&&(o+=i),o+=Math.max(s.getSum()*t,e.options.minLinkWidth||0)),0);return(0,o.getAlignFactor)(e.options.nodeAlignment||"center")*((e.chart.plotSizeY||0)-s)}left(t){let e=this.series,o=e.chart,i=e.options.equalNodes,s=o.inverted?o.plotHeight:o.plotWidth,n=e.nodePadding,r=this.points.reduce((o,r)=>(o>0&&(o+=n),o+=i?s/r.series.nodes.length-n:Math.max(r.getSum()*t,e.options.minLinkWidth||0)),0);return((o.plotSizeX||0)-Math.round(r))/2}sum(){return this.points.reduce((t,e)=>t+e.getSum(),0)}offset(t,e){let i=this.points,s=this.series,n=s.nodePadding,r=0,l;if(s.is("organization")&&t.hangsFrom)return{absoluteTop:t.hangsFrom.nodeY};for(let a=0;a<i.length;a++){let d=i[a].getSum(),h=Math.max(d*e,s.options.minLinkWidth||0),p=t.options[s.chart.inverted?"offsetHorizontal":"offsetVertical"],c=t.options.offset||0;if(l=d?h+n:0,i[a]===t)return{relativeTop:r+((0,o.defined)(p)?(0,o.relativeLength)(p,h):(0,o.relativeLength)(c,l))};r+=l}}}g.SankeyColumnAdditions=y;let b=n,v=t.default.Color;var k=e.n(v);let x=t.default.SVGElement;var N=e.n(x);let{composed:C,deg2rad:P}=r(),{column:L,line:O}=a().seriesTypes,{parse:T}=k(),{getLevelOptions:S,getNodeWidth:w}={getColor:function(t,e){let i,s,n,r,l,a,d=e.index,h=e.mapOptionsToLevel,p=e.parentColor,c=e.parentColorIndex,f=e.series,u=e.colors,m=e.siblings,g=f.points,y=f.chart.options.chart;if(t){let b;i=g[t.i],s=h[t.level]||{},i&&s.colorByPoint&&(r=i.index%(u?u.length:y.colorCount),n=u&&u[r]),f.chart.styledMode||(l=(0,o.pick)(i&&i.options.color,s&&s.color,n,p&&((b=s&&s.colorVariation)&&"brightness"===b.key&&d&&m?k().parse(p).brighten(b.to*(d/m)).get():p),f.color)),a=(0,o.pick)(i&&i.options.colorIndex,s&&s.colorIndex,r,c,e.colorIndex)}return{color:l,colorIndex:a}},getLevelOptions:function(t){let e,i,s,n,r,l,a={};if((0,o.isObject)(t))for(n=(0,o.isNumber)(t.from)?t.from:1,l=t.levels,i={},e=(0,o.isObject)(t.defaults)?t.defaults:{},(0,o.isArray)(l)&&(i=l.reduce((t,i)=>{let s,r,l;return(0,o.isObject)(i)&&(0,o.isNumber)(i.level)&&(l=(0,o.merge)({},i),r=(0,o.pick)(l.levelIsConstant,e.levelIsConstant),delete l.levelIsConstant,delete l.level,s=i.level+(r?0:n-1),(0,o.isObject)(t[s])?(0,o.merge)(!0,t[s],l):t[s]=l),t},{})),r=(0,o.isNumber)(t.to)?t.to:1,s=0;s<=r;s++)a[s]=(0,o.merge)({},e,(0,o.isObject)(i[s])?i[s]:{});return a},getNodeWidth:function(t,e){let{chart:i,options:s}=t,{nodeDistance:n=0,nodeWidth:r=0}=s,{plotSizeX:l=1}=i;if("auto"===r){if("string"==typeof n&&/%$/.test(n))return l/(e+parseFloat(n)/100*(e-1));let t=Number(n);return(l+t)/(e||1)-t}return(0,o.relativeLength)(r,l)},setTreeValues:function t(e,i){let s=i.before,n=i.idRoot,r=i.mapIdToNode[n],l=!1!==i.levelIsConstant,a=i.points[e.i],d=a&&a.options||{},h=[],p=0;e.levelDynamic=e.level-(l?0:r.level),e.name=(0,o.pick)(a&&a.name,""),e.visible=n===e.id||!0===i.visible,"function"==typeof s&&(e=s(e,i)),e.children.forEach((s,n)=>{let r=(0,o.extend)({},i);(0,o.extend)(r,{index:n,siblings:e.children.length,visible:e.visible}),s=t(s,r),h.push(s),s.visible&&(p+=s.val)});let c=(0,o.pick)(d.value,p);return e.visible=c>=0&&(p>0||e.visible),e.children=h,e.childrenTotal=p,e.isLeaf=e.visible&&!p,e.val=c,e},updateRootId:function(t){let e,i;return(0,o.isObject)(t)&&(i=(0,o.isObject)(t.options)?t.options:{},e=(0,o.pick)(t.rootNode,i.rootId,""),(0,o.isObject)(t.userOptions)&&(t.userOptions.rootId=e),t.rootNode=e),e}};i=N(),(0,o.pushUnique)(C,"TextPath")&&((0,o.addEvent)(i,"afterGetBBox",function(t){let e=t.bBox,o=this.element?.querySelector("textPath");if(o){let t=[],{b:i,h:s}=this.renderer.fontMetrics(this.element),n=s-i,r=RegExp('(<tspan>|<tspan(?!\\sclass="highcharts-br")[^>]*>|<\\/tspan>)',"g"),l=o.innerHTML.replace(r,"").split(/<tspan class="highcharts-br"[^>]*>/),a=l.length,d=(t,e)=>{let{x:s,y:r}=e,l=(o.getRotationOfChar(t)-90)*P,a=Math.cos(l),d=Math.sin(l);return[[s-n*a,r-n*d],[s+i*a,r+i*d]]};for(let e=0,i=0;i<a;i++){let s=l[i].length;for(let n=0;n<s;n+=5)try{let s=e+n+i,[r,l]=d(s,o.getStartPositionOfChar(s));0===n?(t.push(l),t.push(r)):(0===i&&t.unshift(l),i===a-1&&t.push(r))}catch{break}e+=s-1;try{let s=e+i,n=o.getEndPositionOfChar(s),[r,l]=d(s,n);t.unshift(l),t.unshift(r)}catch{break}}t.length&&t.push(t[0].slice()),e.polygon=t}return e}),(0,o.addEvent)(i,"beforeAddingDataLabel",function(t){let e=t.labelOptions,o=t.point,i=e[o.formatPrefix+"TextPath"]||e.textPath;i&&!e.useHTML&&(this.setTextPath(o.getDataLabelPath?.(this)||o.graphic,i),o.dataLabelPath&&!i.enabled&&(o.dataLabelPath=o.dataLabelPath.destroy()))}),i.prototype.setTextPath=i.prototype.setTextPath??function(t,e){let i=this.renderer.url,s=this.text||this,n=s.textPath,{attributes:r,enabled:l}=(0,o.merge)({enabled:!0,attributes:{dy:-5,startOffset:"50%",textAnchor:"middle"}},e);if(t=t||n&&n.path,n?.undo(),t&&l){let e=(0,o.addEvent)(s,"afterModifyTree",e=>{if(t&&l){let n=t.attr("id");n||t.attr("id",n=(0,o.uniqueKey)());let l={x:0,y:0};(0,o.defined)(r.dx)&&(l.dx=r.dx,delete r.dx),(0,o.defined)(r.dy)&&(l.dy=r.dy,delete r.dy),s.attr(l),this.attr({transform:""}),this.box&&(this.box=this.box.destroy());let a=e.nodes.slice(0);e.nodes.length=0,e.nodes[0]={tagName:"textPath",attributes:(0,o.extend)(r,{"text-anchor":r.textAnchor,href:`${i}#${n}`}),children:a}}});s.textPath={path:t,undo:e}}else s.attr({dx:0,dy:0}),delete s.textPath;return this.added&&(s.textCache="",this.renderer.buildText(s)),this});class M extends L{static getDLOptions(t){let e=(0,o.isObject)(t.optionsPoint)?t.optionsPoint.dataLabels:{},i=(0,o.isObject)(t.level)?t.level.dataLabels:{};return(0,o.merge)({style:{}},i,e,{zIndex:i?.zIndex})}createNodeColumns(){let t=[];for(let e of this.nodes)e.setNodeColumn(),t[e.column]||(t[e.column]=b.compose([],this)),t[e.column].push(e);for(let e=0;e<t.length;e++)void 0===t[e]&&(t[e]=b.compose([],this));return t}order(t,e,o){if(o||(o=new Set),void 0===t.level||t.level<e){for(let i of(t.level=e,o.add(t),t.linksFrom))i.toNode&&!o.has(i.toNode)&&this.order(i.toNode,e+1,o);o.delete(t)}}generatePoints(){if(p.generatePoints.apply(this,arguments),this.orderNodes){for(let t of this.nodes)0===t.linksTo.length&&this.order(t,0);(0,o.stableSort)(this.nodes,(t,e)=>t.level-e.level)}}getNodePadding(){let t=this.options.nodePadding||0;if(this.nodeColumns){let e=this.nodeColumns.reduce((t,e)=>Math.max(t,e.length),0);e*t>this.chart.plotSizeY&&(t=this.chart.plotSizeY/e)}return t}hasData(){return!!this.dataTable.rowCount}pointAttribs(t,e){if(!t)return{};let i=this,s=t.isNode?t.level:t.fromNode.level,n=i.mapOptionsToLevel[s||0]||{},r=t.options,l=n.states&&n.states[e||""]||{},a=["colorByPoint","borderColor","borderWidth","linkOpacity","opacity"].reduce((t,e)=>(t[e]=(0,o.pick)(l[e],r[e],n[e],i.options[e]),t),{}),d=(0,o.pick)(l.color,r.color,a.colorByPoint?t.color:n.color);return t.isNode?{fill:d,stroke:a.borderColor,"stroke-width":a.borderWidth,opacity:a.opacity}:{fill:d,"fill-opacity":a.linkOpacity}}drawTracker(){L.prototype.drawTracker.call(this,this.points),L.prototype.drawTracker.call(this,this.nodes)}drawPoints(){L.prototype.drawPoints.call(this,this.points),L.prototype.drawPoints.call(this,this.nodes)}drawDataLabels(){L.prototype.drawDataLabels.call(this,this.points),L.prototype.drawDataLabels.call(this,this.nodes)}translate(){this.generatePoints(),this.nodeColumns=this.createNodeColumns();let t=this,e=this.chart,o=this.options,i=this.nodeColumns,s=i.length;for(let n of(this.nodeWidth=w(this,s),this.nodePadding=this.getNodePadding(),this.translationFactor=i.reduce((e,o)=>Math.min(e,o.sankeyColumn.getTranslationFactor(t)),1/0),this.colDistance=(e.plotSizeX-this.nodeWidth-o.borderWidth)/Math.max(1,i.length-1),t.mapOptionsToLevel=S({from:1,levels:o.levels,to:i.length-1,defaults:{borderColor:o.borderColor,borderRadius:o.borderRadius,borderWidth:o.borderWidth,color:t.color,colorByPoint:o.colorByPoint,levelIsConstant:!0,linkColor:o.linkColor,linkLineWidth:o.linkLineWidth,linkOpacity:o.linkOpacity,states:o.states}}),i))for(let e of n)t.translateNode(e,n);for(let e of this.nodes)for(let o of e.linksFrom)(o.weight||o.isNull)&&o.to&&(t.translateLink(o),o.allowShadow=!1)}getY(t,e,o,i){let s=(e.offset(t,o)||0)*this.translationFactor;return Math.min(e.nodeY+s,e.nodeY+(e.shapeArgs&&e.shapeArgs.height||0)-i)}translateLink(t,e){let i=t.fromNode,s=t.toNode,n=this.chart,{inverted:r}=n,l=this.translationFactor,a=this.options,d=(0,o.pick)(t.linkColorMode,a.linkColorMode),h=(n.inverted?-this.colDistance:this.colDistance)*a.curveFactor,p=i.nodeX,c=s.nodeX,f=t.outgoing,u=Math.max((t.weight||0)*l,this.options.minLinkWidth||0),m=this.getY(t,i,"linksFrom",u),g=e||this.getY(t,s,"linksTo",u),y=this.nodeWidth,b=c>p+y;if(n.inverted&&(m=n.plotSizeY-m,g=(n.plotSizeY||0)-g,y=-y,u=-u,b=p>c),t.shapeType="path",t.linkBase=[m,m+u,g,g+u],b&&"number"==typeof g)t.shapeArgs={d:[["M",p+y,m],["C",p+y+h,m,c-h,g,c,g],["L",c+(f?y:0),g+u/2],["L",c,g+u],["C",c-h,g+u,p+y+h,m+u,p+y,m+u],["Z"]]};else if("number"==typeof g){let e=n.plotHeight-m-u,o=c-20-u,i=c-20,s=p+y,r=s+20,l=r+u,a=m,d=m+u,h=d+20,f=h+e,b=f+20,v=b+u,k=g,x=k+u,N=x+20,C=d-.7*u,P=b+.7*u,L=x-.7*u,O=c-.7*u,T=s+.7*u;t.shapeArgs={d:[["M",s,a],["C",T,a,l,C,l,h],["L",l,f],["C",l,P,T,v,s,v],["L",c,v],["C",O,v,o,P,o,f],["L",o,N],["C",o,L,O,k,c,k],["L",c,x],["C",i,x,i,x,i,N],["L",i,f],["C",i,b,i,b,c,b],["L",s,b],["C",r,b,r,b,r,f],["L",r,h],["C",r,d,r,d,s,d],["Z"]]}}if(t.dlBox={x:p+(c-p+y)/2,y:m+(g-m)/2,height:u,width:0},t.tooltipPos=n.inverted?[n.plotSizeY-t.dlBox.y-u/2,n.plotSizeX-t.dlBox.x]:[t.dlBox.x,t.dlBox.y+u/2],t.y=t.plotY=1,t.x=t.plotX=1,!t.options.color){if("from"===d)t.color=i.color;else if("to"===d)t.color=s.color;else if("gradient"===d){let e=T(i.color).get(),o=T(s.color).get();t.color={linearGradient:{x1:1,x2:0,y1:0,y2:0},stops:[[0,r?e:o],[1,r?o:e]]}}}}translateNode(t,e){let i=this.translationFactor,s=this.chart,n=this.options,{borderRadius:r,borderWidth:l=0}=n,a=t.getSum(),d=Math.max(Math.round(a*i),this.options.minLinkWidth),h=Math.round(this.nodeWidth),p=e.sankeyColumn.offset(t,i),c=(0,o.crisp)((0,o.pick)(p.absoluteTop,e.sankeyColumn.top(i)+p.relativeTop),l),f=(0,o.crisp)(this.colDistance*t.column+l/2,l)+(0,o.relativeLength)(t.options[s.inverted?"offsetVertical":"offsetHorizontal"]||0,h),u=s.inverted?s.plotSizeX-f:f;if(t.sum=a,a){t.shapeType="roundedRect",t.nodeX=u,t.nodeY=c;let e=u,i=c,l=t.options.width||n.width||h,a=t.options.height||n.height||d,p=(0,o.clamp)((0,o.relativeLength)(((0,o.isObject)(r)?r.radius:r)||0,l),0,d/2);s.inverted&&(e=u-h,i=s.plotSizeY-c-d,l=t.options.height||n.height||h,a=t.options.width||n.width||d),t.dlOptions={...M.getDLOptions({level:this.mapOptionsToLevel[t.level],optionsPoint:t.options}),zIndex:void 0},delete t.dlOptions.zIndex,t.plotX=1,t.plotY=1,t.tooltipPos=s.inverted?[s.plotSizeY-i-a/2,s.plotSizeX-e-l/2]:[e+l/2,i+a/2],t.shapeArgs={x:e,y:i,width:l,height:a,r:p,display:t.hasShape()?"":"none"}}else t.dlOptions={enabled:!1}}}M.defaultOptions=(0,o.merge)(L.defaultOptions,{borderWidth:0,colorByPoint:!0,curveFactor:.33,dataLabels:{enabled:!0,backgroundColor:"none",crop:!1,nodeFormat:void 0,nodeFormatter:function(){return this.point.name},format:void 0,formatter:function(){},inside:!0},inactiveOtherPoints:!0,linkColorMode:"from",linkOpacity:.5,opacity:1,minLinkWidth:0,nodeAlignment:"center",nodeWidth:20,nodePadding:10,nodeDistance:30,showInLegend:!1,states:{hover:{linkOpacity:1,opacity:1},inactive:{linkOpacity:.1,opacity:.1,animation:{duration:50}}},tooltip:{followPointer:!0,headerFormat:'<span style="font-size: 0.8em">{series.name}</span><br/>',pointFormat:"{point.fromNode.name} → {point.toNode.name}: <b>{point.weight}</b><br/>",nodeFormat:"{point.name}: <b>{point.sum}</b><br/>"}}),p.compose(m,M),(0,o.extend)(M.prototype,{animate:O.prototype.animate,createNode:p.createNode,forceDL:!0,invertible:!0,isCartesian:!1,orderNodes:!0,noSharedTooltip:!0,pointArrayMap:["from","to","weight"],pointClass:m,searchPoint:r().noop}),a().registerSeriesType("sankey",M);let F=r();export{F as default};