chartjs-chart-sankey 0.14.0 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * chartjs-chart-sankey v0.14.0
3
- * https://github.com/kurkle/chartjs-chart-sankey#readme
4
- * (c) 2024 Jukka Kurkela
2
+ * chartjs-chart-sankey v0.0.0-development
3
+ * https://chartjs-chart-sankey.pages.dev/
4
+ * (c) 2026 Jukka Kurkela
5
5
  * Released under the MIT license
6
6
  */
7
- !function(t,o){"object"==typeof exports&&"undefined"!=typeof module?o(require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["chart.js","chart.js/helpers"],o):o((t="undefined"!=typeof globalThis?globalThis:t||self).Chart,t.Chart.helpers)}(this,(function(t,o){"use strict";const e=t=>void 0!==t;function r(t){return t&&-1!==["min","max"].indexOf(t)?t:"max"}const n=(t,o)=>o.flow===t.flow?t.index-o.index:o.flow-t.flow;function s(t,{size:o,priority:e,column:s}){const i=new Map;for(let o=0;o<t.length;o++){const{from:e,to:r,flow:n}=t[o],s=i.get(e)??{key:e,in:0,out:0,size:0,from:[],to:[]},a=(e===r?s:i.get(r))??{key:r,in:0,out:0,size:0,from:[],to:[]};s.out+=n,s.to.push({key:r,flow:n,index:o,node:a,addY:0}),1===s.to.length&&i.set(e,s),a.in+=n,a.from.push({key:e,flow:n,index:o,node:s,addY:0}),1===a.from.length&&i.set(r,a)}return((t,o)=>{const e=r(o);for(const o of t.values())o.from.sort(n),o.to.sort(n),o.size=Math[e](o.in||o.out,o.out||o.in)})(i,o),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.priority=o[e.key])})(i,e),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.column=!0,e.x=o[e.key])})(i,s),i}const i=1e-6,a=(t,o=new Set)=>{const e=[];for(const r of t)o.has(r.key)||(o.add(r.key),e.push(r.key,...a(r.to.map((t=>t.node)),o)));return e},l=(t,o)=>{const e=o.filter((t=>0===t.from.length)),r=e.map((t=>t.key)),n=a(e),s=new Set(n);for(const o of t)s.has(o.from)||s.has(o.to)||(r.push(o.from),s.add(o.from)),s.add(o.to);return r},c=(t,o)=>{const e=new Set(t.filter((t=>o.has(t.from))).map((t=>t.to))),r=[...o],n=r.filter((t=>!e.has(t)));return n.length?n:r.slice(0,1)};let h=-1;function f(t,o,e=function(){return h=h<100?h+1:0,h}()){let r=0;for(const n of t)n.node._visited!==e&&(n.node._visited=e,r+=n.node[o].length+f(n.node[o],o,e));return r}const d=t=>(o,e)=>f(o.node[t],t)-f(e.node[t],t)||o.node[t].length-e.node[t].length;function u(t,o){if(!t.from.length)return o;t.from.sort(d("from"));for(const r of t.from){const t=r.node;e(t.y)||(t.y=o,u(t,o?o+i:0)),o=Math.max(t.y+t.out,o)}return t.y+t.size}function y(t,o){if(!t.to.length)return o;t.to.sort(d("to"));for(const r of t.to){const t=r.node;e(t.y)||(t.y=o,y(t,o?o+i:0)),o=Math.max(t.y+Math.max(t.in,t.out),o)}return t.y+t.size}function p(t,o){return e(t.y)?t.y:(t.y=o,o)}function x(t,o){if(!t.length)return 0;const r=((t,o)=>{const e=[...t].sort(((t,o)=>t.size-o.size)).pop().size,r=t.filter((t=>t.size===e));return 1===r.length?r[0]:(r.sort(((t,o)=>t.x-o.x)),0===r[0].x?r[0]:r[r.length-1].x===o?r.pop():r[Math.floor(r.length/2)])})(t,o);return r.y=0,u(r,0),y(r,0),function(t,o){const r=t.filter((t=>0===t.x)),n=t.filter((t=>t.x===o)),s=r.filter((t=>!e(t.y))),a=n.filter((t=>!e(t.y))),l=t.filter((t=>t.x>0&&t.x<o&&!e(t.y)));let c=r.reduce(((t,o)=>Math.max(t,o.y+o.out||0)),0)+i,h=n.reduce(((t,o)=>Math.max(t,o.y+o.in||0)),0)+i,f=0;c>=h?(s.forEach((t=>{c=p(t,c),c=Math.max(c+t.out,y(t,c))})),a.forEach((t=>{h=p(t,h),h=Math.max(h+t.in,u(t,h))}))):(s.forEach((t=>{c=p(t,c)})),a.forEach((t=>{h=p(t,h),h=Math.max(h+t.in,u(t,h))}))),l.forEach((o=>{let r=t.filter((t=>t.x===o.x&&e(t.y))).reduce(((t,o)=>Math.max(t,o.y+Math.max(o.in,o.out))),0);r=p(o,r),r=Math.max(r+o.in,u(o,r)),r=Math.max(r+o.out,y(o,r)),f=Math.max(f,r)})),Math.max(c,h,f)}(t,o),((t,o)=>{let e=0;for(let r=0;r<=o;r++){const o=t.filter((t=>t.x===r)).sort(((t,o)=>t.y-o.y));let n=0;for(const t of o)t.y<n&&(t.y=n),n=t.y+t.size;e=Math.max(e,n)}return e})(t,o)}const m=(t,o)=>t.x!==o.x?t.x-o.x:t.y===o.y?t.size-o.size:t.y-o.y;function g(t,o,{priority:r,height:n,nodePadding:s,modeX:i}){const a=[...t.values()],h=function(t,o,r){const n=o.filter((t=>t.from!==t.to)),s=[...t.keys()],i=[...t.values()],a=new Set(s);let h=0;for(;a.size;){const r=0===h?l(o,i):c(n,a);if(!r.length)throw new Error("Fatal error: Unable to place nodes to columns. Please report this issue.");for(const o of r){const r=t.get(o);r&&!e(r.x)&&(r.x=h),a.delete(o)}a.size&&h++}const f=i.reduce(((t,o)=>Math.max(t,o.x)),0);if("edge"===r){const e=new Set(o.map((t=>t.from)));s.filter((t=>!e.has(t))).forEach((o=>{const e=t.get(o);e&&!e.column&&(e.x=f)}))}return f}(t,o,i),f=r?function(t,o){let e=0,r=0;for(let n=0;n<=o;n++){let o=r;const s=t.filter((t=>t.x===n)).sort(((t,o)=>(t.priority??0)-(o.priority??0)));r=s.length&&s[0].to.filter((t=>t.node.x>n+1)).reduce(((t,o)=>t+o.flow),0)||0;for(const t of s)t.y=o,o+=Math.max(t.out,t.in);e=Math.max(o,e)}return e}(a,h):x(a,h),d=function(t,o){let e=0;const r=new Map,n=[];t.sort(m);for(const i of t){const t=(s=i.x,r.has(s)||(r.set(s,n.length),n.push([])),r.get(s)),a=n[t];if(i.y){a.push(i.y);let e=a.length;if(i.in){for(let o=0;o<t;o++){const t=n[o];for(let o=0;o<t.length&&!(t[o]>i.y);o++)e=Math.max(o+1,e)}for(;a.length<e;)a.push(i.y)}i.y+=e*o}e=Math.max(e,i.y+Math.max(i.in,i.out))}var s;return e}(a,f/n*s);return function(t){t.forEach((t=>{const o=t.size,e=o<t.in,r=o<t.out;let n=0,s=t.from.length;t.from.sort(((t,o)=>t.node.y+t.node.out/2-(o.node.y+o.node.out/2))).forEach(((t,r)=>{e?t.addY=r*(o-t.flow)/(s-1):(t.addY=n,n+=t.flow)})),n=0,s=t.to.length,t.to.sort(((t,o)=>t.node.y+t.node.in/2-(o.node.y+o.node.in/2))).forEach(((t,e)=>{r?t.addY=e*(o-t.flow)/(s-1):(t.addY=n,n+=t.flow)}))}))}(a),{maxX:h,maxY:d}}function M(t,o,e){for(const r of t)if(r.key===o&&r.index===e)return r.addY;return 0}class w extends t.DatasetController{parseObjectData(t,o,e,r){const n=((t,o)=>{const{from:e="from",to:r="to",flow:n="flow"}=o;return t.map((({[e]:t,[r]:o,[n]:s})=>({from:t,to:o,flow:s})))})(o,this.options.parsing),{xScale:i,yScale:a}=t,l=[],c=this._nodes=s(n,this.options),{maxX:h,maxY:f}=g(c,n,{priority:!!this.options.priority,height:this.chart.canvas.height,nodePadding:this.options.nodePadding,modeX:this.options.modeX});if(this._maxX=h,this._maxY=f,!i||!a)return[];for(let t=0,o=n.length;t<o;++t){const o=n[t],e=c.get(o.from),r=c.get(o.to);if(!e||!r)continue;const s=(e.y??0)+M(e.to,o.to,t),h=(r.y??0)+M(r.from,o.from,t);l.push({x:i.parse(e.x,t),y:a.parse(s,t),_custom:{from:e,to:r,x:i.parse(r.x,t),y:a.parse(h,t),height:a.parse(o.flow,t),flow:o.flow}})}return l.slice(e,e+r)}getMinMax(t){return{min:0,max:t===this._cachedMeta.xScale?this._maxX:this._maxY}}update(t){const{data:o}=this._cachedMeta;this.updateElements(o,0,o.length,t)}updateElements(t,o,e,r){const{xScale:n,yScale:s}=this._cachedMeta;if(!n||!s)return;const i=this.resolveDataElementOptions(o,r),a=this.getSharedOptions(i),{borderWidth:l,nodeWidth:c=10}=this.options,h=l?l/2+.5:0;for(let i=o;i<o+e;i++){const o=this.getParsed(i),e=o._custom,a=s.getPixelForValue(o.y);this.updateElement(t[i],i,{x:n.getPixelForValue(o.x)+c+h,y:a,x2:n.getPixelForValue(e.x)-h,y2:s.getPixelForValue(e.y),from:e.from,to:e.to,progress:"reset"===r?0:1,height:Math.abs(s.getPixelForValue(o.y+e.height)-a),options:this.resolveDataElementOptions(i,r)},r)}this.updateSharedOptions(a,r,i)}_drawLabels(){const t=this.chart.ctx,o=this.options,e=this._nodes||new Map,n=r(o.size),s=o.borderWidth??1,i=o.nodeWidth??10,a=o.labels,{xScale:l,yScale:c}=this._cachedMeta;if(!l||!c)return;t.save();const h=this.chart.chartArea;for(const r of e.values()){const e=l.getPixelForValue(r.x),f=c.getPixelForValue(r.y),d=Math[n](r.in||r.out,r.out||r.in),u=Math.abs(c.getPixelForValue(r.y+d)-f),y=a?.[r.key]??r.key;let p=e;t.fillStyle=o.color??"black",t.textBaseline="middle",e<h.width/2?(t.textAlign="left",p+=i+s+4):(t.textAlign="right",p-=s+4),this._drawLabel(y,f,u,t,p)}t.restore()}_drawLabel(t,e,r,n,s){const i=o.toFont(this.options.font,this.chart.options.font),a=function(t){if(!t)return[];const o=[],e=Array.isArray(t)?t:[t];for(;e.length;){const t=e.pop();"string"==typeof t?o.unshift(...t.split("\n")):Array.isArray(t)?e.push(...t):t&&o.unshift(`${t}`)}return o}(t),l=a.length,c=e+r/2,h=i.lineHeight,f=o.valueOrDefault(this.options.padding,h/2);if(n.font=i.string,l>1){const t=c-h*l/2+f;for(let o=0;o<l;o++)n.fillText(a[o],s,t+o*h)}else n.fillText(t,s,c)}_drawNodes(){const t=this.chart.ctx,o=this._nodes||new Map,{borderColor:e,borderWidth:n=0,nodeWidth:s=10,size:i}=this.options,a=r(i),{xScale:l,yScale:c}=this._cachedMeta;t.save(),e&&n&&(t.strokeStyle=e,t.lineWidth=n);for(const e of o.values()){t.fillStyle=e.color??"black";const o=l.getPixelForValue(e.x),r=c.getPixelForValue(e.y),i=Math[a](e.in||e.out,e.out||e.in),h=Math.abs(c.getPixelForValue(e.y+i)-r);n&&t.strokeRect(o,r,s,h),t.fillRect(o,r,s,h)}t.restore()}draw(){const t=this.chart.ctx,o=this.getMeta().data??[],e=[];for(let t=0,r=o.length;t<r;++t){const r=o[t];r.from.color=r.options.colorFrom,r.to.color=r.options.colorTo,r.active&&e.push(r)}for(const t of e)t.from.color=t.options.colorFrom,t.to.color=t.options.colorTo;this._drawNodes();for(let e=0,r=o.length;e<r;++e)o[e].draw(t);this._drawLabels()}}w.id="sankey",w.defaults={dataElementType:"flow",animations:{numbers:{type:"number",properties:["x","y","x2","y2","height"]},progress:{easing:"linear",duration:t=>"data"===t.type?200*(t.parsed._custom.x-t.parsed.x):void 0,delay:t=>"data"===t.type?500*t.parsed.x+20*t.dataIndex:void 0},colors:{type:"color",properties:["colorFrom","colorTo"]}},color:"black",borderColor:"black",borderWidth:1,modeX:"edge",nodeWidth:10,nodePadding:10,transitions:{hide:{animations:{colors:{type:"color",properties:["colorFrom","colorTo"],to:"transparent"}}},show:{animations:{colors:{type:"color",properties:["colorFrom","colorTo"],from:"transparent"}}}}},w.overrides={interaction:{mode:"nearest",intersect:!0},datasets:{clip:!1,parsing:{from:"from",to:"to",flow:"flow"}},plugins:{tooltip:{callbacks:{title:()=>"",label(t){const o=t.parsed._custom;return o.from.key+" -> "+o.to.key+": "+o.flow}}},legend:{display:!1}},scales:{x:{type:"linear",bounds:"data",display:!1,min:0,offset:!1},y:{type:"linear",bounds:"data",display:!1,min:0,reverse:!0,offset:!1}},layout:{padding:{top:3,left:3,right:13,bottom:3}}};const b=(t,o,e,r)=>t<e?{cp1:{x:t+(e-t)/3*2,y:o},cp2:{x:t+(e-t)/3,y:r}}:{cp1:{x:t-(t-e)/3,y:0},cp2:{x:e+(t-e)/3,y:0}},v=(t,o,e)=>({x:t.x+e*(o.x-t.x),y:t.y+e*(o.y-t.y)}),k=(t,e)=>o.color(t).alpha(e).rgbString(),P=(t,o)=>"string"==typeof t?k(t,o):t;class _ extends t.Element{draw(t){const{x:o,x2:e,y:r,y2:n,height:s,progress:i}=this,{cp1:a,cp2:l}=b(o,r,e,n);0!==i&&(t.save(),i<1&&(t.beginPath(),t.rect(o,Math.min(r,n),(e-o)*i+1,Math.abs(n-r)+s+1),t.clip()),function(t,{x:o,x2:e,options:r}){let n="black";"from"===r.colorMode?n=P(r.colorFrom,r.alpha):"to"===r.colorMode?n=P(r.colorTo,r.alpha):"string"==typeof r.colorFrom&&"string"==typeof r.colorTo&&(n=t.createLinearGradient(o,0,e,0),n.addColorStop(0,k(r.colorFrom,r.alpha)),n.addColorStop(1,k(r.colorTo,r.alpha))),t.fillStyle=n,t.strokeStyle=n,t.lineWidth=.5}(t,this),t.beginPath(),t.moveTo(o,r),t.bezierCurveTo(a.x,a.y,l.x,l.y,e,n),t.lineTo(e,n+s),t.bezierCurveTo(l.x,l.y+s,a.x,a.y+s,o,r+s),t.lineTo(o,r),t.stroke(),t.closePath(),t.fill(),t.restore())}inRange(t,o,e){const{x:r,y:n,x2:s,y2:i,height:a}=this.getProps(["x","y","x2","y2","height"],e);if(t<r||t>s)return!1;const{cp1:l,cp2:c}=b(r,n,s,i),h=(t-r)/(s-r),f={x:s,y:i},d=v({x:r,y:n},l,h),u=v(l,c,h),y=v(c,f,h),p=v(d,u,h),x=v(u,y,h),m=v(p,x,h).y;return o>=m&&o<=m+a}inXRange(t,o){const{x:e,x2:r}=this.getProps(["x","x2"],o);return t>=e&&t<=r}inYRange(t,o){const{y:e,y2:r,height:n}=this.getProps(["y","y2","height"],o),s=Math.min(e,r),i=Math.max(e,r)+n;return t>=s&&t<=i}getCenterPoint(t){const{x:o,y:e,x2:r,y2:n,height:s}=this.getProps(["x","y","x2","y2","height"],t);return{x:(o+r)/2,y:(e+n+s)/2}}tooltipPosition(t){return this.getCenterPoint(t)}getRange(t){return"x"===t?this.width/2:this.height/2}constructor(t){super(),t&&Object.assign(this,t)}}_.id="flow",_.defaults={colorFrom:"red",colorTo:"green",colorMode:"gradient",alpha:.5,hoverColorFrom:(t,e)=>o.getHoverColor(e.colorFrom),hoverColorTo:(t,e)=>o.getHoverColor(e.colorTo)},_.descriptors={_scriptable:!0},t.Chart.register(w,_)}));
7
+ !function(t,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports,require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["exports","chart.js","chart.js/helpers"],o):o((t="undefined"!=typeof globalThis?globalThis:t||self)["chartjs-chart-sankey"]={},t.Chart,t.Chart.helpers)}(this,function(t,o,e){"use strict";const r=t=>void 0!==t;function n(t){return t&&-1!==["min","max"].indexOf(t)?t:"max"}const s=(t,o)=>o.flow===t.flow?t.index-o.index:o.flow-t.flow;function i(t,{size:o,priority:e,column:r}){const i=new Map;for(let o=0;o<t.length;o++){const{from:e,to:r,flow:n}=t[o],s=i.get(e)??{from:[],in:0,key:e,out:0,size:0,to:[]},a=(e===r?s:i.get(r))??{from:[],in:0,key:r,out:0,size:0,to:[]};s.out+=n,s.to.push({addY:0,flow:n,index:o,key:r,node:a}),1===s.to.length&&i.set(e,s),a.in+=n,a.from.push({addY:0,flow:n,index:o,key:e,node:s}),1===a.from.length&&i.set(r,a)}return((t,o)=>{const e=n(o);for(const o of t.values())o.from.sort(s),o.to.sort(s),o.size=Math[e](o.in||o.out,o.out||o.in)})(i,o),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.priority=o[e.key])})(i,e),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.column=!0,e.x=o[e.key])})(i,r),i}const a=1e-6,l=(t,o=new Set)=>{const e=[];for(const r of t)o.has(r.key)||(o.add(r.key),e.push(r.key,...l(r.to.map(t=>t.node),o)));return e},c=(t,o)=>{const e=o.filter(t=>0===t.from.length),r=e.map(t=>t.key),n=l(e),s=new Set(n);for(const o of t)s.has(o.from)||s.has(o.to)||(r.push(o.from),s.add(o.from)),s.add(o.to);return r},h=(t,o)=>{const e=new Set(t.filter(t=>o.has(t.from)).map(t=>t.to)),r=[...o],n=r.filter(t=>!e.has(t));return n.length?n:r.slice(0,1)};let f=-1;function d(t,o,e=function(){return f=f<100?f+1:0,f}()){let r=0;for(const n of t)n.node._visited!==e&&(n.node._visited=e,r+=n.node[o].length+d(n.node[o],o,e));return r}const u=t=>(o,e)=>d(o.node[t],t)-d(e.node[t],t)||o.node[t].length-e.node[t].length;function y(t,o){if(!t.from.length)return o;t.from.sort(u("from"));for(const e of t.from){const t=e.node;r(t.y)||(t.y=o,y(t,o?o+a:0)),o=Math.max(t.y+t.out,o)}return t.y+t.size}function p(t,o){if(!t.to.length)return o;t.to.sort(u("to"));for(const e of t.to){const t=e.node;r(t.y)||(t.y=o,p(t,o?o+a:0)),o=Math.max(t.y+Math.max(t.in,t.out),o)}return t.y+t.size}function x(t,o){return r(t.y)?t.y:(t.y=o,o)}function m(t,o){if(!t.length)return 0;const e=((t,o)=>{const e=[...t].sort((t,o)=>t.size-o.size).pop().size,r=t.filter(t=>t.size===e);return 1===r.length?r[0]:(r.sort((t,o)=>t.x-o.x),0===r[0].x?r[0]:r[r.length-1].x===o?r.pop():r[Math.floor(r.length/2)])})(t,o);return e.y=0,y(e,0),p(e,0),function(t,o){const e=t.filter(t=>0===t.x),n=t.filter(t=>t.x===o),s=e.filter(t=>!r(t.y)),i=n.filter(t=>!r(t.y)),l=t.filter(t=>t.x>0&&t.x<o&&!r(t.y));let c=e.reduce((t,o)=>Math.max(t,o.y+o.out||0),0)+a,h=n.reduce((t,o)=>Math.max(t,o.y+o.in||0),0)+a,f=0;c>=h?(s.forEach(t=>{c=x(t,c),c=Math.max(c+t.out,p(t,c))}),i.forEach(t=>{h=x(t,h),h=Math.max(h+t.in,y(t,h))})):(s.forEach(t=>{c=x(t,c)}),i.forEach(t=>{h=x(t,h),h=Math.max(h+t.in,y(t,h))})),l.forEach(o=>{let e=t.filter(t=>t.x===o.x&&r(t.y)).reduce((t,o)=>Math.max(t,o.y+Math.max(o.in,o.out)),0);e=x(o,e),e=Math.max(e+o.in,y(o,e)),e=Math.max(e+o.out,p(o,e)),f=Math.max(f,e)}),Math.max(c,h,f)}(t,o),((t,o)=>{let e=0;for(let r=0;r<=o;r++){const o=t.filter(t=>t.x===r).sort((t,o)=>t.y-o.y);let n=0;for(const t of o)t.y<n&&(t.y=n),n=t.y+t.size;e=Math.max(e,n)}return e})(t,o)}const g=(t,o)=>t.x!==o.x?t.x-o.x:t.y===o.y?t.size-o.size:t.y-o.y;function w(t,o,{priority:e,height:n,nodePadding:s,modeX:i}){const a=[...t.values()],l=function(t,o,e){const n=o.filter(t=>t.from!==t.to),s=[...t.keys()],i=[...t.values()],a=new Set(s);let l=0;for(;a.size;){const e=0===l?c(o,i):h(n,a);if(!e.length)throw new Error("Fatal error: Unable to place nodes to columns. Please report this issue.");for(const o of e){const e=t.get(o);e&&!r(e.x)&&(e.x=l),a.delete(o)}a.size&&l++}const f=i.reduce((t,o)=>Math.max(t,o.x),0);if("edge"===e){const e=new Set(o.map(t=>t.from));s.filter(t=>!e.has(t)).forEach(o=>{const e=t.get(o);e&&!e.column&&(e.x=f)})}return f}(t,o,i),f=e?function(t,o){let e=0,r=0;for(let n=0;n<=o;n++){let o=r;const s=t.filter(t=>t.x===n).sort((t,o)=>(t.priority??0)-(o.priority??0));r=s.length&&s[0].to.filter(t=>t.node.x>n+1).reduce((t,o)=>t+o.flow,0)||0;for(const t of s)t.y=o,o+=Math.max(t.out,t.in);e=Math.max(o,e)}return e}(a,l):m(a,l),d=function(t,o){let e=0;const r=new Map,n=[],s=t=>(r.has(t)||(r.set(t,n.length),n.push([])),r.get(t));t.sort(g);for(const r of t){const t=s(r.x),i=n[t];if(r.y){i.push(r.y);let e=i.length;if(r.in){for(let o=0;o<t;o++){const t=n[o];for(let o=0;o<t.length&&!(t[o]>r.y);o++)e=Math.max(o+1,e)}for(;i.length<e;)i.push(r.y)}r.y+=e*o}e=Math.max(e,r.y+Math.max(r.in,r.out))}return e}(a,f/n*s);return function(t){t.forEach(t=>{const o=t.size,e=o<t.in,r=o<t.out;let n=0,s=t.from.length;t.from.sort((t,o)=>t.node.y+t.node.out/2-(o.node.y+o.node.out/2)).forEach((t,r)=>{e?t.addY=r*(o-t.flow)/(s-1):(t.addY=n,n+=t.flow)}),n=0,s=t.to.length,t.to.sort((t,o)=>t.node.y+t.node.in/2-(o.node.y+o.node.in/2)).forEach((t,e)=>{r?t.addY=e*(o-t.flow)/(s-1):(t.addY=n,n+=t.flow)})})}(a),{maxX:l,maxY:d}}function M(t,o,e){for(const r of t)if(r.key===o&&r.index===e)return r.addY;return 0}class b extends o.DatasetController{parseObjectData(t,o,e,r){const n=((t,o)=>{const{from:e="from",to:r="to",flow:n="flow"}=o;return t.map(({[e]:t,[r]:o,[n]:s})=>({flow:s,from:t,to:o}))})(o,this.options.parsing),{xScale:s,yScale:a}=t,l=[],c=i(n,this.options);this._nodes=c;const{maxX:h,maxY:f}=w(c,n,{height:this.chart.canvas.height,modeX:this.options.modeX,nodePadding:this.options.nodePadding,priority:!!this.options.priority});if(this._maxX=h,this._maxY=f,!s||!a)return[];for(let t=0,o=n.length;t<o;++t){const o=n[t],e=c.get(o.from),r=c.get(o.to);if(!e||!r)continue;const i=(e.y??0)+M(e.to,o.to,t),h=(r.y??0)+M(r.from,o.from,t);l.push({_custom:{flow:o.flow,from:e,height:a.parse(o.flow,t),to:r,x:s.parse(r.x,t),y:a.parse(h,t)},x:s.parse(e.x,t),y:a.parse(i,t)})}return l.slice(e,e+r)}getMinMax(t){return{max:t===this._cachedMeta.xScale?this._maxX:this._maxY,min:0}}update(t){const{data:o}=this._cachedMeta;this.updateElements(o,0,o.length,t)}updateElements(t,o,e,r){const{xScale:n,yScale:s}=this._cachedMeta;if(!n||!s)return;const i=this.resolveDataElementOptions(o,r),a=this.getSharedOptions(i),{borderWidth:l,nodeWidth:c=10}=this.options,h=l?l/2+.5:0;for(let i=o;i<o+e;i++){const o=this.getParsed(i),e=o._custom,a=s.getPixelForValue(o.y);this.updateElement(t[i],i,{from:e.from,height:Math.abs(s.getPixelForValue(o.y+e.height)-a),options:this.resolveDataElementOptions(i,r),progress:"reset"===r?0:1,to:e.to,x:n.getPixelForValue(o.x)+c+h,x2:n.getPixelForValue(e.x)-h,y:a,y2:s.getPixelForValue(e.y)},r)}this.updateSharedOptions(a,r,i)}_drawLabels(){const t=this.chart.ctx,o=this.options,e=this._nodes||new Map,r=n(o.size),s=o.borderWidth??1,i=o.nodeWidth??10,a=o.labels,{xScale:l,yScale:c}=this._cachedMeta;if(!l||!c)return;t.save();const h=this.chart.chartArea;for(const n of e.values()){const e=l.getPixelForValue(n.x),f=c.getPixelForValue(n.y),d=Math[r](n.in||n.out,n.out||n.in),u=Math.abs(c.getPixelForValue(n.y+d)-f),y=a?.[n.key]??n.key;let p=e;t.fillStyle=o.color??"black",t.textBaseline="middle",e<h.width/2?(t.textAlign="left",p+=i+s+4):(t.textAlign="right",p-=s+4),this._drawLabel(y,f,u,t,p)}t.restore()}_drawLabel(t,o,r,n,s){const i=e.toFont(this.options.font,this.chart.options.font),a=function(t){if(!t)return[];const o=[],e=Array.isArray(t)?t:[t];for(;e.length;){const t=e.pop();"string"==typeof t?o.unshift(...t.split("\n")):Array.isArray(t)?e.push(...t):t&&o.unshift(`${t}`)}return o}(t),l=a.length,c=o+r/2,h=i.lineHeight,f=e.valueOrDefault(this.options.padding,h/2);if(n.font=i.string,l>1){const t=c-h*l/2+f;for(let o=0;o<l;o++)n.fillText(a[o],s,t+o*h)}else n.fillText(t,s,c)}_drawNodes(){const t=this.chart.ctx,o=this._nodes||new Map,{borderColor:e,borderWidth:r=0,nodeWidth:s=10,size:i}=this.options,a=n(i),{xScale:l,yScale:c}=this._cachedMeta;t.save(),e&&r&&(t.strokeStyle=e,t.lineWidth=r);for(const e of o.values()){t.fillStyle=e.color??"black";const o=l.getPixelForValue(e.x),n=c.getPixelForValue(e.y),i=Math[a](e.in||e.out,e.out||e.in),h=Math.abs(c.getPixelForValue(e.y+i)-n);r&&t.strokeRect(o,n,s,h),t.fillRect(o,n,s,h)}t.restore()}draw(){const t=this.chart.ctx,o=this.getMeta().data??[],e=[];for(let t=0,r=o.length;t<r;++t){const r=o[t];r.from.color=r.options.colorFrom,r.to.color=r.options.colorTo,r.active&&e.push(r)}for(const t of e)t.from.color=t.options.colorFrom,t.to.color=t.options.colorTo;this._drawNodes();for(let e=0,r=o.length;e<r;++e)o[e].draw(t);this._drawLabels()}}b.id="sankey",b.defaults={animations:{colors:{properties:["colorFrom","colorTo"],type:"color"},numbers:{properties:["x","y","x2","y2","height"],type:"number"},progress:{delay:t=>"data"===t.type?500*t.parsed.x+20*t.dataIndex:void 0,duration:t=>"data"===t.type?200*(t.parsed._custom.x-t.parsed.x):void 0,easing:"linear"}},borderColor:"black",borderWidth:1,color:"black",dataElementType:"flow",modeX:"edge",nodePadding:10,nodeWidth:10,transitions:{hide:{animations:{colors:{properties:["colorFrom","colorTo"],to:"transparent",type:"color"}}},show:{animations:{colors:{from:"transparent",properties:["colorFrom","colorTo"],type:"color"}}}}},b.overrides={datasets:{clip:!1,parsing:{flow:"flow",from:"from",to:"to"}},interaction:{intersect:!0,mode:"nearest"},layout:{padding:{bottom:3,left:3,right:13,top:3}},plugins:{legend:{display:!1},tooltip:{callbacks:{label(t){const o=t.parsed._custom;return o.from.key+" -> "+o.to.key+": "+o.flow},title:()=>""}}},scales:{x:{bounds:"data",display:!1,min:0,offset:!1,type:"linear"},y:{bounds:"data",display:!1,min:0,offset:!1,reverse:!0,type:"linear"}}};const k=(t,o,e,r)=>t<e?{cp1:{x:t+(e-t)/3*2,y:o},cp2:{x:t+(e-t)/3,y:r}}:{cp1:{x:t-(t-e)/3,y:0},cp2:{x:e+(t-e)/3,y:0}},v=(t,o,e)=>({x:t.x+e*(o.x-t.x),y:t.y+e*(o.y-t.y)}),P=(t,o)=>e.color(t).alpha(o).rgbString(),F=(t,o)=>"string"==typeof t?P(t,o):t;class S extends o.Element{draw(t){const{x:o,x2:e,y:r,y2:n,height:s,progress:i}=this,{cp1:a,cp2:l}=k(o,r,e,n);0!==i&&(t.save(),i<1&&(t.beginPath(),t.rect(o,Math.min(r,n),(e-o)*i+1,Math.abs(n-r)+s+1),t.clip()),function(t,{x:o,x2:e,options:r}){let n="black";"from"===r.colorMode?n=F(r.colorFrom,r.alpha):"to"===r.colorMode?n=F(r.colorTo,r.alpha):"string"==typeof r.colorFrom&&"string"==typeof r.colorTo&&(n=t.createLinearGradient(o,0,e,0),n.addColorStop(0,P(r.colorFrom,r.alpha)),n.addColorStop(1,P(r.colorTo,r.alpha))),t.fillStyle=n,t.strokeStyle=n,t.lineWidth=.5}(t,this),t.beginPath(),t.moveTo(o,r),t.bezierCurveTo(a.x,a.y,l.x,l.y,e,n),t.lineTo(e,n+s),t.bezierCurveTo(l.x,l.y+s,a.x,a.y+s,o,r+s),t.lineTo(o,r),t.stroke(),t.closePath(),t.fill(),t.restore())}inRange(t,o,e){const{x:r,y:n,x2:s,y2:i,height:a}=this.getProps(["x","y","x2","y2","height"],e);if(t<r||t>s)return!1;const{cp1:l,cp2:c}=k(r,n,s,i),h=(t-r)/(s-r),f={x:s,y:i},d=v({x:r,y:n},l,h),u=v(l,c,h),y=v(c,f,h),p=v(d,u,h),x=v(u,y,h),m=v(p,x,h).y;return o>=m&&o<=m+a}inXRange(t,o){const{x:e,x2:r}=this.getProps(["x","x2"],o);return t>=e&&t<=r}inYRange(t,o){const{y:e,y2:r,height:n}=this.getProps(["y","y2","height"],o),s=Math.min(e,r),i=Math.max(e,r)+n;return t>=s&&t<=i}getCenterPoint(t){const{x:o,y:e,x2:r,y2:n,height:s}=this.getProps(["x","y","x2","y2","height"],t);return{x:(o+r)/2,y:(e+n+s)/2}}tooltipPosition(t){return this.getCenterPoint(t)}getRange(t){return"x"===t?this.width/2:this.height/2}constructor(t){super(),t&&Object.assign(this,t)}}S.id="flow",S.defaults={alpha:.5,colorFrom:"red",colorMode:"gradient",colorTo:"green",hoverColorFrom:(t,o)=>e.getHoverColor(o.colorFrom),hoverColorTo:(t,o)=>e.getHoverColor(o.colorTo)},S.descriptors={_scriptable:!0},o.Chart.register(b,S),t.Flow=S,t.SankeyController=b});
@@ -0,0 +1,119 @@
1
+ import type { ChartMeta, SankeyControllerDatasetOptions, SankeyParsedData } from 'chart.js';
2
+ import type Flow from './flow.js';
3
+ import type { AnyObject } from './types.js';
4
+ import { DatasetController } from 'chart.js';
5
+ export default class SankeyController extends DatasetController {
6
+ static readonly id = "sankey";
7
+ static readonly defaults: {
8
+ animations: {
9
+ colors: {
10
+ properties: string[];
11
+ type: string;
12
+ };
13
+ numbers: {
14
+ properties: string[];
15
+ type: string;
16
+ };
17
+ progress: {
18
+ delay: (ctx: any) => number;
19
+ duration: (ctx: any) => number;
20
+ easing: string;
21
+ };
22
+ };
23
+ borderColor: string;
24
+ borderWidth: number;
25
+ color: string;
26
+ dataElementType: string;
27
+ modeX: string;
28
+ nodePadding: number;
29
+ nodeWidth: number;
30
+ transitions: {
31
+ hide: {
32
+ animations: {
33
+ colors: {
34
+ properties: string[];
35
+ to: string;
36
+ type: string;
37
+ };
38
+ };
39
+ };
40
+ show: {
41
+ animations: {
42
+ colors: {
43
+ from: string;
44
+ properties: string[];
45
+ type: string;
46
+ };
47
+ };
48
+ };
49
+ };
50
+ };
51
+ static readonly overrides: {
52
+ datasets: {
53
+ clip: boolean;
54
+ parsing: {
55
+ flow: string;
56
+ from: string;
57
+ to: string;
58
+ };
59
+ };
60
+ interaction: {
61
+ intersect: boolean;
62
+ mode: string;
63
+ };
64
+ layout: {
65
+ padding: {
66
+ bottom: number;
67
+ left: number;
68
+ right: number;
69
+ top: number;
70
+ };
71
+ };
72
+ plugins: {
73
+ legend: {
74
+ display: boolean;
75
+ };
76
+ tooltip: {
77
+ callbacks: {
78
+ label(context: any): string;
79
+ title(): string;
80
+ };
81
+ };
82
+ };
83
+ scales: {
84
+ x: {
85
+ bounds: string;
86
+ display: boolean;
87
+ min: number;
88
+ offset: boolean;
89
+ type: string;
90
+ };
91
+ y: {
92
+ bounds: string;
93
+ display: boolean;
94
+ min: number;
95
+ offset: boolean;
96
+ reverse: boolean;
97
+ type: string;
98
+ };
99
+ };
100
+ };
101
+ options: SankeyControllerDatasetOptions;
102
+ private _nodes;
103
+ private _maxX;
104
+ private _maxY;
105
+ parseObjectData(meta: ChartMeta<'sankey', Flow>, data: AnyObject[], start: number, count: number): SankeyParsedData[];
106
+ getMinMax(scale: any): {
107
+ max: number;
108
+ min: number;
109
+ };
110
+ update(mode: any): void;
111
+ updateElements(elems: Flow[], start: number, count: number, mode: 'default' | 'resize' | 'reset' | 'none' | 'hide' | 'show' | 'active'): void;
112
+ private _drawLabels;
113
+ private _drawLabel;
114
+ private _drawNodes;
115
+ /**
116
+ * That's where the drawing process happens
117
+ */
118
+ draw(): void;
119
+ }
package/dist/flow.d.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type { SankeyNode } from 'chart.js';
2
+ import type { FlowConfig, FlowOptions, FlowProps } from './types.js';
3
+ import { Element } from 'chart.js';
4
+ export default class Flow extends Element<FlowProps, FlowOptions> {
5
+ static readonly id = "flow";
6
+ static readonly defaults: {
7
+ alpha: number;
8
+ colorFrom: string;
9
+ colorMode: string;
10
+ colorTo: string;
11
+ hoverColorFrom: (_ctx: any, options: any) => CanvasGradient;
12
+ hoverColorTo: (_ctx: any, options: any) => CanvasGradient;
13
+ };
14
+ static readonly descriptors: {
15
+ _scriptable: boolean;
16
+ };
17
+ x2: number;
18
+ y2: number;
19
+ width: number;
20
+ height: number;
21
+ progress: number;
22
+ from: SankeyNode;
23
+ to: SankeyNode;
24
+ constructor(cfg: FlowConfig);
25
+ /**
26
+ * @param {CanvasRenderingContext2D} ctx
27
+ */
28
+ draw(ctx: CanvasRenderingContext2D): void;
29
+ /**
30
+ * @param {number} mouseX
31
+ * @param {number} mouseY
32
+ * @param {boolean} useFinalPosition
33
+ * @return {boolean}
34
+ */
35
+ inRange(mouseX: number, mouseY: number, useFinalPosition: boolean): boolean;
36
+ /**
37
+ * @param {number} mouseX
38
+ * @param {boolean} useFinalPosition
39
+ * @return {boolean}
40
+ */
41
+ inXRange(mouseX: number, useFinalPosition: boolean): boolean;
42
+ /**
43
+ * @param {number} mouseY
44
+ * @param {boolean} useFinalPosition
45
+ * @return {boolean}
46
+ */
47
+ inYRange(mouseY: number, useFinalPosition: boolean): boolean;
48
+ /**
49
+ * @param {boolean} useFinalPosition
50
+ * @return {{x: number, y:number}}
51
+ */
52
+ getCenterPoint(useFinalPosition: boolean): {
53
+ x: number;
54
+ y: number;
55
+ };
56
+ tooltipPosition(useFinalPosition: any): {
57
+ x: number;
58
+ y: number;
59
+ };
60
+ /**
61
+ * @param {"x" | "y"} axis
62
+ * @return {number}
63
+ */
64
+ getRange(axis: 'x' | 'y'): number;
65
+ }
@@ -0,0 +1,4 @@
1
+ import Sankey from './controller.js';
2
+ import Flow from './flow.js';
3
+ export type { FlowConfig, FlowOptions, FlowProps, } from './types.js';
4
+ export { Flow, Sankey as SankeyController };
@@ -0,0 +1,3 @@
1
+ export type { FlowConfig, FlowOptions, FlowProps, } from './types.js';
2
+ export { default as SankeyController } from './controller.js';
3
+ export { default as Flow } from './flow.js';
@@ -0,0 +1,4 @@
1
+ import type { SankeyControllerDatasetOptions, SankeyDataPoint, SankeyNode } from 'chart.js';
2
+ import type { AnyObject } from '../types.js';
3
+ export declare const getParsedData: (data: AnyObject[], parsing: SankeyControllerDatasetOptions["parsing"]) => SankeyDataPoint[];
4
+ export declare function buildNodesFromData(data: SankeyDataPoint[], { size, priority, column }: Pick<SankeyControllerDatasetOptions, 'size' | 'priority' | 'column'>): Map<string, SankeyNode>;
@@ -0,0 +1,3 @@
1
+ export declare const defined: <T>(x?: T) => x is T;
2
+ export declare function toTextLines(raw?: string | number | Array<string | number | Array<string | number>>): string[];
3
+ export declare function validateSizeValue(size: any): 'min' | 'max';
@@ -0,0 +1,34 @@
1
+ import type { SankeyControllerDatasetOptions, SankeyDataPoint, SankeyNode } from 'chart.js';
2
+ export type SankeyMode = 'edge' | 'even';
3
+ /**
4
+ * Get all keys the input nodes flow to, including keys of the input nodes
5
+ */
6
+ export declare const getAllKeysForward: (nodes: SankeyNode[], visited?: Set<string>) => string[];
7
+ /**
8
+ * Find the nodes that should be placed leftmost on the chart.
9
+ * NOTE: With circular flows, data order matters.
10
+ */
11
+ export declare const startColumn: (data: SankeyDataPoint[], nodes: SankeyNode[]) => string[];
12
+ export declare function calculateX(nodeMap: Map<string, SankeyNode>, data: SankeyDataPoint[], mode: SankeyMode): number;
13
+ export declare function calculateY(nodeArray: SankeyNode[], maxX: number): number;
14
+ export declare function calculateYUsingPriority(nodeArray: SankeyNode[], maxX: number): number;
15
+ /**
16
+ * @return {number} maxY
17
+ */
18
+ export declare function addPadding(nodeArray: Pick<SankeyNode, 'x' | 'y' | 'in' | 'out' | 'size'>[], padding: number): number;
19
+ export declare function sortFlows(nodeArray: SankeyNode[]): void;
20
+ interface LayoutOptions {
21
+ /** use node priority when sorting nodes vertically */
22
+ priority: boolean;
23
+ /** canvas height (in pixels) */
24
+ height: number;
25
+ /** vertical padding between nodes (in pixels) */
26
+ nodePadding: number;
27
+ /** layout mode in x-direction */
28
+ modeX: SankeyControllerDatasetOptions['modeX'];
29
+ }
30
+ export declare function layout(nodes: Map<string, SankeyNode>, data: SankeyDataPoint[], { priority, height, nodePadding, modeX }: LayoutOptions): {
31
+ maxY: number;
32
+ maxX: number;
33
+ };
34
+ export {};
@@ -0,0 +1,102 @@
1
+ import type { CartesianScaleTypeRegistry, Color, FontSpec, Scriptable, ScriptableContext } from 'chart.js';
2
+ export type AnyObject = Record<string, unknown>;
3
+ declare module 'chart.js' {
4
+ interface SankeyDataPoint {
5
+ from: string;
6
+ to: string;
7
+ flow: number;
8
+ }
9
+ interface SankeyControllerDatasetOptions {
10
+ label: string;
11
+ data: Array<SankeyDataPoint>;
12
+ colorFrom: (data: ScriptableContext<'sankey'>) => string;
13
+ colorTo: (data: ScriptableContext<'sankey'>) => string;
14
+ colorMode: 'gradient' | 'from' | 'to';
15
+ hoverColorFrom?: Scriptable<string, ScriptableContext<'sankey'>>;
16
+ hoverColorTo?: Scriptable<string, ScriptableContext<'sankey'>>;
17
+ priority?: Record<string, number>;
18
+ column?: Record<string, number>;
19
+ labels?: Record<string, string>;
20
+ modeX?: 'edge' | 'even';
21
+ size?: 'min' | 'max';
22
+ borderWidth?: number;
23
+ nodeWidth?: number;
24
+ nodePadding?: number;
25
+ color?: string;
26
+ borderColor?: string;
27
+ font?: FontSpec;
28
+ padding?: number;
29
+ parsing: {
30
+ from: string;
31
+ to: string;
32
+ flow: string;
33
+ };
34
+ }
35
+ type FromToElement = {
36
+ addY: number;
37
+ flow: number;
38
+ key: string;
39
+ node: SankeyNode;
40
+ index: number;
41
+ };
42
+ type SankeyNode = {
43
+ key: string;
44
+ in: number;
45
+ out: number;
46
+ size: number;
47
+ from: Array<FromToElement>;
48
+ to: Array<FromToElement>;
49
+ column?: boolean;
50
+ priority?: number;
51
+ y?: number;
52
+ x?: number;
53
+ color?: Color;
54
+ _visited?: number;
55
+ };
56
+ interface SankeyParsedData {
57
+ x: number;
58
+ y: number;
59
+ _custom: {
60
+ from: SankeyNode;
61
+ to: SankeyNode;
62
+ x: number;
63
+ y: number;
64
+ height: number;
65
+ flow: number;
66
+ };
67
+ }
68
+ interface ChartTypeRegistry {
69
+ sankey: {
70
+ datasetOptions: SankeyControllerDatasetOptions;
71
+ defaultDataPoint: SankeyDataPoint;
72
+ parsedDataType: SankeyParsedData;
73
+ metaExtensions: AnyObject;
74
+ chartOptions: FlowOptions;
75
+ scales: keyof CartesianScaleTypeRegistry;
76
+ };
77
+ }
78
+ }
79
+ export interface FlowProps {
80
+ x: number;
81
+ y: number;
82
+ x2: number;
83
+ y2: number;
84
+ height: number;
85
+ width: number;
86
+ }
87
+ export interface FlowOptions {
88
+ alpha: number;
89
+ colorMode: 'gradient' | 'from' | 'to';
90
+ colorFrom: 'string';
91
+ colorTo: Color;
92
+ hoverColorFrom: Color;
93
+ hoverColorTo: Color;
94
+ }
95
+ export interface FlowConfig {
96
+ x: number;
97
+ y: number;
98
+ x2: number;
99
+ y2: number;
100
+ height: number;
101
+ options: FlowOptions;
102
+ }
package/package.json CHANGED
@@ -1,71 +1,31 @@
1
1
  {
2
- "name": "chartjs-chart-sankey",
3
- "version": "0.14.0",
4
- "description": "Chart.js module for creating sankey diagrams",
5
- "main": "dist/chartjs-chart-sankey.js",
6
- "module": "dist/chartjs-chart-sankey.esm.js",
7
- "type": "module",
8
- "types": "types/index.esm.d.ts",
9
- "exports": {
10
- "types": "./types/index.esm.d.ts",
11
- "require": "./dist/chartjs-chart-sankey.js",
12
- "import": "./dist/chartjs-chart-sankey.esm.js",
13
- "script": "./dist/chartjs-chart-sankey.min.js"
14
- },
15
- "scripts": {
16
- "build": "rollup -c",
17
- "autobuild": "rollup -c -w",
18
- "dev": "karma start ./karma.conf.cjs --no-single-run --auto-watch --browsers chrome",
19
- "dev:ff": "karma start ./karma.conf.cjs --no-single-run --auto-watch --browsers firefox",
20
- "lint": "eslint",
21
- "typecheck": "tsc --noEmit && tsc --noEmit -p types/tests/",
22
- "test": "npm run test:unit && npm run test:fixture",
23
- "test:unit": "jest",
24
- "test:fixture": "cross-env NODE_ENV=test karma start ./karma.conf.cjs --no-auto-watch --single-run"
25
- },
26
- "repository": {
27
- "type": "git",
28
- "url": "git+https://github.com/kurkle/chartjs-chart-sankey.git"
29
- },
30
- "keywords": [
31
- "chart.js",
32
- "chart",
33
- "sankey"
34
- ],
35
- "files": [
36
- "dist/*.js",
37
- "types/index.esm.d.ts"
38
- ],
39
2
  "author": "Jukka Kurkela",
40
- "license": "MIT",
41
3
  "bugs": {
42
4
  "url": "https://github.com/kurkle/chartjs-chart-sankey/issues"
43
5
  },
44
- "homepage": "https://github.com/kurkle/chartjs-chart-sankey#readme",
6
+ "description": "Chart.js module for creating sankey diagrams",
45
7
  "devDependencies": {
46
- "@eslint/eslintrc": "^3.1.0",
47
- "@eslint/js": "^9.13.0",
48
- "@eslint/markdown": "^6.2.1",
8
+ "@astrojs/check": "^0.9.9",
9
+ "@astrojs/mdx": "^5.0.6",
10
+ "@astrojs/starlight": "^0.38.5",
11
+ "@biomejs/biome": "^2.4.14",
12
+ "@emnapi/core": "^1.10.0",
13
+ "@emnapi/runtime": "^1.10.0",
49
14
  "@jest/globals": "^29.7.0",
50
- "@rollup/plugin-node-resolve": "^15.3.0",
15
+ "@kurkle/configs": "^1.0.1",
16
+ "@napi-rs/canvas": "^1.0.0",
17
+ "@rollup/plugin-node-resolve": "^16.0.0",
51
18
  "@rollup/plugin-swc": "^0.4.0",
52
19
  "@rollup/plugin-terser": "^0.4.0",
53
20
  "@swc/core": "^1.7.40",
54
- "@types/jest": "^29.5.14",
55
- "@types/node": "^22.8.1",
56
- "@typescript-eslint/eslint-plugin": "^8.11.0",
57
- "@typescript-eslint/parser": "^8.11.0",
21
+ "@types/jest": "^30.0.0",
22
+ "@types/node": "^25.0.3",
23
+ "astro": "^6.4.2",
58
24
  "chart.js": "^4.4.5",
59
25
  "chartjs-test-utils": "^0.5.0",
60
- "cross-env": "^7.0.3",
61
- "eslint": "^9.13.0",
62
- "eslint-config-chartjs": "^0.3.0",
63
- "eslint-config-prettier": "^9.1.0",
64
- "eslint-plugin-prettier": "^5.2.1",
65
- "eslint-plugin-simple-import-sort": "^12.1.1",
66
- "eslint-plugin-unused-imports": "^4.1.4",
67
- "globals": "^15.11.0",
68
- "jest": "^29.7.0",
26
+ "cross-env": "^10.1.0",
27
+ "jest": "^30.2.0",
28
+ "jest-util": "^30.2.0",
69
29
  "karma": "^6.3.2",
70
30
  "karma-chrome-launcher": "^3.1.0",
71
31
  "karma-coverage": "^2.0.3",
@@ -77,11 +37,62 @@
77
37
  "rollup": "^4.24.0",
78
38
  "rollup-plugin-cleanup": "^3.2.1",
79
39
  "rollup-plugin-istanbul": "^5.0.0",
40
+ "semantic-release": "^25.0.3",
80
41
  "ts-jest": "^29.2.5",
81
42
  "ts-node": "^10.9.2",
82
43
  "typescript": "^5.0.4"
83
44
  },
45
+ "exports": {
46
+ "import": "./dist/chartjs-chart-sankey.esm.js",
47
+ "require": "./dist/chartjs-chart-sankey.cjs",
48
+ "script": "./dist/chartjs-chart-sankey.min.js",
49
+ "types": "./dist/index.esm.d.ts"
50
+ },
51
+ "files": [
52
+ "dist/*",
53
+ "!dist/docs/**"
54
+ ],
55
+ "homepage": "https://chartjs-chart-sankey.pages.dev/",
56
+ "jsdelivr": "dist/chartjs-chart-sankey.min.js",
57
+ "keywords": [
58
+ "chart.js",
59
+ "chart",
60
+ "sankey"
61
+ ],
62
+ "license": "MIT",
63
+ "main": "dist/chartjs-chart-sankey.cjs",
64
+ "module": "dist/chartjs-chart-sankey.esm.js",
65
+ "name": "chartjs-chart-sankey",
84
66
  "peerDependencies": {
85
67
  "chart.js": ">=3.3.0"
86
- }
68
+ },
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "git+https://github.com/kurkle/chartjs-chart-sankey.git"
72
+ },
73
+ "scripts": {
74
+ "autobuild": "rollup -c -w",
75
+ "build": "rollup -c && tsc -p tsconfig.json --emitDeclarationOnly",
76
+ "dev": "karma start ./karma.conf.cjs --no-single-run --auto-watch --browsers chrome",
77
+ "dev:ff": "karma start ./karma.conf.cjs --no-single-run --auto-watch --browsers firefox",
78
+ "docs": "npm run build && astro build",
79
+ "docs:dev": "npm run build && astro dev",
80
+ "docs:version": "node ./docs/scripts/write-docs-version.cjs",
81
+ "format": "biome check --write",
82
+ "lint": "biome check",
83
+ "predocs": "npm run docs:version",
84
+ "predocs:dev": "npm run docs:version",
85
+ "test": "npm run test:unit && npm run test:fixture && npm run test:integration:browser-module && npm run test:integration:node-commonjs && npm run test:integration:node-module",
86
+ "test:fixture": "cross-env NODE_ENV=test karma start ./karma.conf.cjs --no-auto-watch --single-run",
87
+ "test:integration:browser-module": "karma start ./karma.integration.cjs --single-run",
88
+ "test:integration:node-commonjs": "node test/integration/node-commonjs/test.cjs",
89
+ "test:integration:node-module": "node test/integration/node-module/test.mjs",
90
+ "test:unit": "jest",
91
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.json --emitDeclarationOnly && tsc --noEmit -p test/types/",
92
+ "typecheck:docs": "astro check"
93
+ },
94
+ "type": "module",
95
+ "types": "dist/index.esm.d.ts",
96
+ "unpkg": "dist/chartjs-chart-sankey.min.js",
97
+ "version": "0.14.2"
87
98
  }