@graphysdk/geom-sankey 0.1.0 → 0.1.1-beta.1792404455940

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.
@@ -9,6 +9,7 @@ declare const NODE_VOCABULARY: {
9
9
  readonly alpha: "unitInterval";
10
10
  readonly stroke: "color";
11
11
  readonly strokeWidth: "pixels";
12
+ readonly overpaint: "overpaint";
12
13
  };
13
14
  declare const LABEL_VOCABULARY: {
14
15
  readonly fontFamily: "fontFamily";
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let y=require("@graphysdk/react"),S=require("d3-sankey"),O=require("react"),v=require("react/jsx-runtime");var i={kind:"sankeyKind",nodeName:"sankeyNodeName",observationKey:"sankeyObservationKey",nodeKey:"sankeyNodeKey",targetKey:"sankeyTargetKey",x0:"sankeyX0",x1:"sankeyX1",y0:"sankeyY0",y1:"sankeyY1",targetY0:"sankeyTargetY0",targetY1:"sankeyTargetY1"},k=(e,t)=>{const a=e[t];return typeof a=="number"&&Number.isFinite(a)?a:null},K=e=>{const t=e[i.observationKey],a=e[i.nodeKey],n=k(e,i.x0),o=k(e,i.x1),r=k(e,i.y0),s=k(e,i.y1);if(typeof t!="string"||typeof a!="string"||n===null||o===null||r===null||s===null)return null;switch(e[i.kind]){case"node":return{kind:"node",observation:e,key:t,nodeKey:a,x0:n,x1:o,y0:r,y1:s};case"flow":{const l=k(e,i.targetY0),u=k(e,i.targetY1),c=e[i.targetKey];return l===null||u===null||typeof c!="string"?null:{kind:"flow",observation:e,key:t,nodeKey:a,targetKey:c,x0:n,x1:o,y0:r,y1:s,targetY0:l,targetY1:u}}default:return null}},C=new WeakMap,N=e=>{const t=C.get(e);if(t!==void 0)return t;const a=[],n=[];for(const r of e){const s=K(r);s?.kind==="node"&&a.push(s),s?.kind==="flow"&&n.push(s)}const o={nodes:a,flows:n};return C.set(e,o),o},V=(e,t)=>e.nodeKey===t.nodeKey||e.targetKey===t.nodeKey,I=e=>e*e*(3-2*e),F=(e,t)=>{const a=I(t);return{top:e.y0+(e.targetY0-e.y0)*a,bottom:e.y1+(e.targetY1-e.y1)*a}},W=(e,t)=>{const a=e.x1-e.x0;if(a<=0||t.x<e.x0||t.x>e.x1)return!1;const{top:n,bottom:o}=F(e,(t.x-e.x0)/a);return t.y>=n&&t.y<=o},_=(e,t)=>{const a=u=>u*t.width,n=u=>u*t.height,o=a(e.x0),r=a(e.x1),s=a(e.x0+(e.x1-e.x0)/3),l=a(e.x0+(e.x1-e.x0)*2/3);return[`M${o},${n(e.y0)}`,`C${s},${n(e.y0)} ${l},${n(e.targetY0)} ${r},${n(e.targetY0)}`,`L${r},${n(e.targetY1)}`,`C${l},${n(e.targetY1)} ${s},${n(e.y1)} ${o},${n(e.y1)}`,"Z"].join("")},D=.018,G=.03,w={justify:S.sankeyJustify,left:S.sankeyLeft,right:S.sankeyRight,center:S.sankeyCenter},H=(e,t)=>{const a=B(e);if(a.length===0)return{nodes:[],flows:[]};const n=[...new Set(a.flatMap(r=>[r.source,r.target]))],o=(0,S.sankey)().nodeId(r=>r.key).nodeAlign(w[t]).nodeWidth(D).nodePadding(G).extent([[0,0],[1,1]])({nodes:n.map(r=>({key:r})),links:a.map(r=>({source:r.source,target:r.target,value:r.value,link:r}))});return{nodes:o.nodes.map(r=>({key:r.key,value:r.value??0,x0:p(r.x0),x1:p(r.x1),y0:p(r.y0),y1:p(r.y1)})),flows:o.links.map(r=>{const s=r.source,l=r.target,u=(r.width??0)/2;return{link:r.link,x0:p(s.x1),x1:p(l.x0),y0:p((r.y0??0)-u),y1:p((r.y0??0)+u),targetY0:p((r.y1??0)-u),targetY1:p((r.y1??0)+u)}})}},p=e=>Math.min(1,Math.max(0,e??0)),B=e=>{const t=new Map,a=(n,o)=>{const r=new Set,s=[n];for(;s.length>0;){const l=s.pop();if(l===o)return!0;r.has(l)||(r.add(l),s.push(...t.get(l)??[]))}return!1};return e.filter(n=>t.get(n.source)?.has(n.target)===!0?!0:a(n.target,n.source)?!1:(t.set(n.source,(t.get(n.source)??new Set).add(n.target)),!0))},E=new Set(["node"]),j=["color","alpha"],U=["justify","left","right","center"],X=class extends y.Stat{constructor(...e){super(...e),this.type="sankey",this.computedVariables=E}computeStat({data:e,mapping:t,params:a}){const n=Q(e,t);return n===null?{data:e,mapping:{}}:(Z(e,n),{data:ae(e,n,J(a)),mapping:{node:i.nodeName,...R(t,n)}})}},R=(e,t)=>{const a={};for(const n of j){const o=q(n,e[n],t);o!==null&&(a[n]=o)}return a},q=(e,t,{sourceVariable:a,targetVariable:n})=>{if(t===void 0)return e==="color"?i.nodeKey:null;const o=(0,y.readVariableName)(t);return o===a?i.nodeKey:o===n?i.targetKey:null},z=e=>U.includes(e),J=e=>{const t=e?.align;return z(t)?t:"justify"},L=(e,t)=>e===null?null:e instanceof Date?t.type==="year"?String(e.getUTCFullYear()):e.toISOString():String(e),Z=(e,{valueVariable:t})=>{const a=e.getType(t);if(!(e.size()===0||a==="numeric"))throw new y.UserInputError({code:"INCOMPATIBLE_TYPE",message:`'sankey' stat requires a numeric 'value' (got '${a}' for variable '${t}')`,context:{aesthetic:"value",variableName:t,variableType:a},suggestion:"Map each flow's amount to 'value', declaring the column numeric if it holds whole years."})},Q=(e,t)=>{const a=(0,y.readVariableName)(t.source),n=(0,y.readVariableName)(t.target),o=(0,y.readVariableName)(t.value);return a===null||n===null||o===null||![a,n,o].every(r=>e.hasVariable(r))?null:{sourceVariable:a,targetVariable:n,valueVariable:o}},ee=(e,{sourceVariable:t,targetVariable:a,valueVariable:n})=>{const o=e.getValues(t),r=e.getValues(a),s=e.getValues(n,{type:"numeric"}),l=e.getValueFormat(t),u=e.getValueFormat(a),c=new Map,g=new Map,d=[];return o.forEach((h,m)=>{const b=r[m]??null,f=L(h,l),x=L(b,u);if(f===null||x===null)return;g.set(f,h),g.set(x,b);const P=JSON.stringify([f,x]),Y=c.get(P)??0;c.set(P,Y+1);const A=s[m];typeof A!="number"||!Number.isFinite(A)||A<=0||d.push({source:f,target:x,value:A,row:m,occurrence:Y})}),{links:d,names:g}},$=(e,{sourceVariable:t,targetVariable:a})=>e.getType(t)===e.getType(a),te=(e,t,a,n)=>{const o=e.getType(t.sourceVariable);return $(e,t)?{type:o,values:a.map(r=>n.get(r)??null),valueFormat:e.getValueFormat(t.sourceVariable)}:{type:"categorical",values:[...a]}},re=(e,t,a,n,o)=>e===a.valueVariable?n.nodes.map(r=>r.value):e===a.sourceVariable&&$(t,a)?n.nodes.map(r=>o.get(r.key)??null):null,ae=(e,t,a)=>{const{links:n,names:o}=ee(e,t),r=H(n,a),s=r.nodes.length,l=d=>[...d,...Array.from({length:s},()=>null)],u=e.getVariableNames(),c=Object.fromEntries(u.map(d=>{const h=e.getValues(d),m=r.flows.map(({link:x})=>h[x.row]??null),b=re(d,e,t,r,o),f=b===null?l(m):[...m,...b];return[d,{type:e.getType(d),values:f,valueFormat:e.getValueFormat(d)}]})),g=[...r.flows.map(({link:d})=>d.source),...r.nodes.map(({key:d})=>d)];return new y.Dataset({...c,...ne(r),[i.nodeName]:te(e,t,g,o)})},ne=e=>{const t=e.flows.map(({link:l,...u})=>({[i.kind]:"flow",[i.observationKey]:JSON.stringify(["flow",l.source,l.target,l.occurrence]),[i.nodeKey]:l.source,[i.targetKey]:l.target,[i.x0]:u.x0,[i.x1]:u.x1,[i.y0]:u.y0,[i.y1]:u.y1,[i.targetY0]:u.targetY0,[i.targetY1]:u.targetY1})),a=e.nodes.map(l=>({[i.kind]:"node",[i.observationKey]:JSON.stringify(["node",l.key]),[i.nodeKey]:l.key,[i.targetKey]:l.key,[i.x0]:l.x0,[i.x1]:l.x1,[i.y0]:l.y0,[i.y1]:l.y1,[i.targetY0]:null,[i.targetY1]:null})),n=[...t,...a],o=l=>n.map(u=>u[l]),r=l=>({type:"categorical",values:o(l)}),s=l=>({type:"numeric",values:o(l)});return{[i.kind]:r(i.kind),[i.observationKey]:r(i.observationKey),[i.nodeKey]:r(i.nodeKey),[i.targetKey]:r(i.targetKey),[i.x0]:s(i.x0),[i.x1]:s(i.x1),[i.y0]:s(i.y0),[i.y1]:s(i.y1),[i.targetY0]:s(i.targetY0),[i.targetY1]:s(i.targetY1)}},oe=.4,se=.65,ie=12,le=3,ue={},ce={fill:"paint",fillAlpha:"unitInterval",alpha:"unitInterval",stroke:"color",strokeWidth:"pixels"},ye={fontFamily:"fontFamily",fontSize:"pixels",fontWeight:"fontWeight",textColor:"color",textOutlineColor:"color",textOutlineWidth:"pixels"},M=class extends y.Geom{constructor(...e){super(...e),this.type="sankey",this.defaultParams={align:"justify"},this.defaultStat=new X,this.aesthetics=[{kind:"data",name:"source",required:!0},{kind:"data",name:"target",required:!0},{kind:"data",name:"value",required:!0},{kind:"data",name:"node"},{kind:"visual",name:"color"},{kind:"visual",name:"alpha"}],this.identityKey={variable:i.observationKey},this.supportedPositions=["identity"],this.supportedCoordTypes=["cartesian"],this.legend={defaultPosition:"none"},this.spatialKind="render-hit-test",this.highlightStrategy="observation-rerender",this.tooltip=[{aes:"node",heading:!0},{aes:"target"},{aes:"value"}],this.styleTarget=(0,y.defineGeomStyleTarget)({observation:{vocabulary:ue,aesthetics:{fill:"color",alpha:"alpha"},rest:{fill:(0,y.token)("geom"),fillAlpha:oe},hovered:{fillAlpha:se}},parts:{node:{vocabulary:ce,aesthetics:{fill:"color",alpha:"alpha"},rest:{fill:(0,y.token)("geom"),fillAlpha:1,alpha:1,stroke:(0,y.token)("graphBackground"),strokeWidth:0}},label:{vocabulary:ye,rest:{fontSize:ie,fontWeight:500,textColor:(0,y.token)("textPrimary"),textOutlineColor:(0,y.token)("graphBackground"),textOutlineWidth:le}}}}),this.resolveValueSource=t=>t.value??null,this.validateMapping=({mapping:t,computedVariables:a})=>{if(!a.has("node"))return[{code:"MISSING_STAT_OUTPUT",message:"sankey geom lays its flows out in the 'sankey' stat; remove the layer's stat"}];const n=[...E].filter(s=>t[s]!==void 0).map(s=>({code:"CONFLICTING_STAT_MAPPING",message:`sankey stat computes '${s}' from 'source' and 'target'; remove its mapping`})),o=[(0,y.readVariableName)(t.source),(0,y.readVariableName)(t.target)],r=j.flatMap(s=>{const l=(0,y.readVariableName)(t[s]);return l===null||o.includes(l)?[]:[{code:"UNSUPPORTED_MAPPING",message:`sankey geom scales '${s}' by node; map it to the source or target column rather than '${l}'`}]});return[...n,...r]},this.resolveAnchorPosition=t=>{const a=K(t);if(a===null)return null;if(a.kind==="node")return{x:(a.x0+a.x1)/2,y:1-(a.y0+a.y1)/2};const{top:n,bottom:o}=F(a,.5);return{x:(a.x0+a.x1)/2,y:1-(n+o)/2}}}compile({data:e}){return{data:e,mapping:{}}}},de=({layer:e,panelRect:t})=>{const{nodes:a,flows:n}=N(e.data),o=s=>s*t.width,r=s=>s*t.height;return[...n.map(s=>({kind:"region",pathData:_(s,t)})),...a.map(s=>({kind:"region",pathData:`M${o(s.x0)},${r(s.y0)}H${o(s.x1)}V${r(s.y1)}H${o(s.x0)}Z`}))]},ge=({flows:e,size:t,source:a,styleReaders:n,isHovered:o=!1,shouldAnimateTransitions:r=!1})=>{const s=o?"hovered":void 0,l=(0,O.useMemo)(()=>e.map(g=>n.get("fill",g.observation,s)??"transparent"),[e,n,s]),{fillFor:u,defs:c}=(0,y.usePaintDefs)({paints:l});return(0,v.jsxs)(v.Fragment,{children:[c,e.map((g,d)=>{const h=l[d],m=n.get("stroke",g.observation,s);return(0,v.jsx)(y.GeomPath,{"data-testid":"sankey-flow",d:_(g,t),source:a,fill:h===void 0?void 0:u(h),opacity:n.get("alpha",g.observation,s),fillOpacity:n.get("fillAlpha",g.observation,s),stroke:m===void 0?void 0:(0,y.toPaintColor)(m),strokeOpacity:n.get("strokeAlpha",g.observation,s),shouldAnimateTransitions:r},g.key)})]})},ve=6,he=e=>{const t=(e.y0+e.y1)/2;return(e.x0+e.x1)/2<.5?{x:e.x1,y:t,offsetX:ve,textAnchor:"start"}:{x:e.x0,y:t,offsetX:-6,textAnchor:"end"}},me=({nodes:e,valueFormat:t,styleReaders:a,isHovered:n=!1})=>{const o=n?"hovered":void 0,r=a.part("label"),s=(0,y.useGraphLocale)(),l=(0,y.useSceneSelector)(c=>c.config.numberFormat),u=(0,O.useMemo)(()=>(0,y.createValueFormatter)({valueFormat:t,locale:s,numberFormat:l}),[t,s,l]);return(0,v.jsx)("g",{pointerEvents:"none",children:e.map(c=>{const g=c.observation[i.nodeName];if(g==null)return null;const d=he(c),h=r?.get("textColor",c.observation,o),m=r?.get("textOutlineColor",c.observation,o);return(0,v.jsx)("text",{"data-testid":"sankey-label",x:(0,y.toPercent)(d.x),y:(0,y.toPercent)(d.y),dx:d.offsetX,textAnchor:d.textAnchor,dominantBaseline:"central",fontFamily:r?.get("fontFamily",c.observation,o),fontSize:r?.get("fontSize",c.observation,o),fontWeight:r?.get("fontWeight",c.observation,o),fill:h===void 0?void 0:(0,y.toPaintColor)(h),stroke:m===void 0?void 0:(0,y.toPaintColor)(m),strokeWidth:r?.get("textOutlineWidth",c.observation,o),strokeLinejoin:"round",paintOrder:"stroke",children:u(g,c.observation)},c.key)})})},pe=({nodes:e,styleReaders:t,isHovered:a=!1,shouldAnimateTransitions:n=!1})=>{const o=a?"hovered":void 0,r=t.part("node"),s=(0,O.useMemo)(()=>e.map(c=>r?.get("fill",c.observation,o)??"transparent"),[e,r,o]),{fillFor:l,defs:u}=(0,y.usePaintDefs)({paints:s});return(0,v.jsxs)(v.Fragment,{children:[u,e.map((c,g)=>{const d=s[g],h=r?.get("stroke",c.observation,o);return(0,v.jsx)(y.GeomRect,{"data-testid":"sankey-node",x:(0,y.toPercent)(c.x0),y:(0,y.toPercent)(c.y0),width:(0,y.toPercent)(c.x1-c.x0),height:(0,y.toPercent)(c.y1-c.y0),fill:d===void 0?void 0:l(d),opacity:r?.get("alpha",c.observation,o),fillOpacity:r?.get("fillAlpha",c.observation,o),stroke:h===void 0?void 0:(0,y.toPaintColor)(h),strokeWidth:r?.get("strokeWidth",c.observation,o),shouldAnimateTransitions:n},c.key)})]})},fe={type:"text"},T=({observations:e,layer:t,size:a,styleReaders:n,isHovered:o=!1,shouldAnimateTransitions:r=!1})=>(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(ge,{flows:e.flows,size:a,source:t,styleReaders:n,isHovered:o,shouldAnimateTransitions:r}),(0,v.jsx)(pe,{nodes:e.nodes,styleReaders:n,isHovered:o,shouldAnimateTransitions:r}),(0,v.jsx)(me,{nodes:e.nodes,valueFormat:t.data.hasVariable(i.nodeName)?t.data.getValueFormat(i.nodeName):fe,styleReaders:n,isHovered:o})]}),xe=({layer:e,size:t,styleReaders:a})=>(0,v.jsx)(T,{observations:N(e.data),layer:e,size:t,styleReaders:a}),ke=({layer:e})=>{const{nodes:t,flows:a}=N(e.data),n=[...t].reverse(),o=[...a].reverse();return r=>{const s=n.find(u=>r.x>=u.x0&&r.x<=u.x1&&r.y>=u.y0&&r.y<=u.y1);if(s!==void 0)return{key:s.key};const l=o.find(u=>W(u,r));return l===void 0?null:{key:l.key}}},be=({layer:e,primary:t,size:a,styleReaders:n})=>{const o=N(e.data),r=t.observation;return(0,v.jsx)("g",{"data-testid":"hovered-observations",children:(0,v.jsx)(T,{observations:(0,O.useMemo)(()=>Se(o,r),[o,r]),layer:e,size:a,styleReaders:n,isHovered:!0})})},Se=(e,t)=>{const a=K(t);if(a===null)return{nodes:[],flows:[]};if(a.kind==="node"){const n=e.flows.filter(r=>V(r,a)),o=new Set(n.flatMap(r=>[r.nodeKey,r.targetKey]));return{nodes:e.nodes.filter(r=>o.has(r.nodeKey)),flows:n}}return{nodes:e.nodes.filter(n=>V(a,n)),flows:[a]}},Ne=({layer:e,size:t,styleReaders:a,shouldAnimateTransitions:n})=>(0,v.jsx)(T,{observations:N(e.data),layer:e,size:t,styleReaders:a,shouldAnimateTransitions:n}),Ae=(0,y.defineGeomRenderer)(new M,{coord:"cartesian",swatchShape:"square",render:({layer:e,panelRect:t,styleReaders:a,shouldAnimateTransitions:n})=>(0,v.jsx)(Ne,{layer:e,size:t,styleReaders:a,shouldAnimateTransitions:n}),renderHighlight:({layer:e,panelRect:t,styleReaders:a})=>(0,v.jsx)(xe,{layer:e,size:t,styleReaders:a}),renderHover:({layer:e,primary:t,panelRect:a,styleReaders:n})=>(0,v.jsx)(be,{layer:e,primary:t,size:a,styleReaders:n}),renderHoverCompanions:()=>null,hitTest:ke,getEditOutlineShapes:de});exports.SankeyGeom=M;exports.sankey=Ae;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let u=require("@graphysdk/react"),S=require("d3-sankey"),O=require("react"),g=require("react/jsx-runtime");var i={kind:"sankeyKind",nodeName:"sankeyNodeName",observationKey:"sankeyObservationKey",nodeKey:"sankeyNodeKey",targetKey:"sankeyTargetKey",x0:"sankeyX0",x1:"sankeyX1",y0:"sankeyY0",y1:"sankeyY1",targetY0:"sankeyTargetY0",targetY1:"sankeyTargetY1"},k=(e,t)=>{const n=e[t];return typeof n=="number"&&Number.isFinite(n)?n:null},K=e=>{const t=e[i.observationKey],n=e[i.nodeKey],a=k(e,i.x0),o=k(e,i.x1),r=k(e,i.y0),s=k(e,i.y1);if(typeof t!="string"||typeof n!="string"||a===null||o===null||r===null||s===null)return null;switch(e[i.kind]){case"node":return{kind:"node",observation:e,key:t,nodeKey:n,x0:a,x1:o,y0:r,y1:s};case"flow":{const l=k(e,i.targetY0),c=k(e,i.targetY1),d=e[i.targetKey];return l===null||c===null||typeof d!="string"?null:{kind:"flow",observation:e,key:t,nodeKey:n,targetKey:d,x0:a,x1:o,y0:r,y1:s,targetY0:l,targetY1:c}}default:return null}},C=new WeakMap,N=e=>{const t=C.get(e);if(t!==void 0)return t;const n=[],a=[];for(const r of e){const s=K(r);s?.kind==="node"&&n.push(s),s?.kind==="flow"&&a.push(s)}const o={nodes:n,flows:a};return C.set(e,o),o},V=(e,t)=>e.nodeKey===t.nodeKey||e.targetKey===t.nodeKey,I=e=>e*e*(3-2*e),E=(e,t)=>{const n=I(t);return{top:e.y0+(e.targetY0-e.y0)*n,bottom:e.y1+(e.targetY1-e.y1)*n}},W=(e,t)=>{const n=e.x1-e.x0;if(n<=0||t.x<e.x0||t.x>e.x1)return!1;const{top:a,bottom:o}=E(e,(t.x-e.x0)/n);return t.y>=a&&t.y<=o},F=(e,t)=>{const n=c=>c*t.width,a=c=>c*t.height,o=n(e.x0),r=n(e.x1),s=n(e.x0+(e.x1-e.x0)/3),l=n(e.x0+(e.x1-e.x0)*2/3);return[`M${o},${a(e.y0)}`,`C${s},${a(e.y0)} ${l},${a(e.targetY0)} ${r},${a(e.targetY0)}`,`L${r},${a(e.targetY1)}`,`C${l},${a(e.targetY1)} ${s},${a(e.y1)} ${o},${a(e.y1)}`,"Z"].join("")},G=.018,D=.03,H={justify:S.sankeyJustify,left:S.sankeyLeft,right:S.sankeyRight,center:S.sankeyCenter},w=(e,t)=>{const n=B(e);if(n.length===0)return{nodes:[],flows:[]};const a=[...new Set(n.flatMap(r=>[r.source,r.target]))],o=(0,S.sankey)().nodeId(r=>r.key).nodeAlign(H[t]).nodeWidth(G).nodePadding(D).extent([[0,0],[1,1]])({nodes:a.map(r=>({key:r})),links:n.map(r=>({source:r.source,target:r.target,value:r.value,link:r}))});return{nodes:o.nodes.map(r=>({key:r.key,value:r.value??0,x0:p(r.x0),x1:p(r.x1),y0:p(r.y0),y1:p(r.y1)})),flows:o.links.map(r=>{const s=r.source,l=r.target,c=(r.width??0)/2;return{link:r.link,x0:p(s.x1),x1:p(l.x0),y0:p((r.y0??0)-c),y1:p((r.y0??0)+c),targetY0:p((r.y1??0)-c),targetY1:p((r.y1??0)+c)}})}},p=e=>Math.min(1,Math.max(0,e??0)),B=e=>{const t=new Map,n=(a,o)=>{const r=new Set,s=[a];for(;s.length>0;){const l=s.pop();if(l===o)return!0;r.has(l)||(r.add(l),s.push(...t.get(l)??[]))}return!1};return e.filter(a=>t.get(a.source)?.has(a.target)===!0?!0:n(a.target,a.source)?!1:(t.set(a.source,(t.get(a.source)??new Set).add(a.target)),!0))},_=new Set(["node"]),j=["color","alpha"],U=["justify","left","right","center"],X=class extends u.Stat{constructor(...e){super(...e),this.type="sankey",this.computedVariables=_}computeStat({data:e,mapping:t,params:n}){const a=Q(e,t);return a===null?{data:e,mapping:{}}:(Z(e,a),{data:ne(e,a,J(n)),mapping:{node:i.nodeName,...q(t,a)}})}},q=(e,t)=>{const n={};for(const a of j){const o=R(a,e[a],t);o!==null&&(n[a]=o)}return n},R=(e,t,{sourceVariable:n,targetVariable:a})=>{if(t===void 0)return e==="color"?i.nodeKey:null;const o=(0,u.readVariableName)(t);return o===n?i.nodeKey:o===a?i.targetKey:null},z=e=>U.includes(e),J=e=>{const t=e?.align;return z(t)?t:"justify"},L=(e,t)=>e===null?null:e instanceof Date?t.type==="year"?String(e.getUTCFullYear()):e.toISOString():String(e),Z=(e,{valueVariable:t})=>{const n=e.getType(t);if(!(e.size()===0||n==="numeric"))throw new u.UserInputError({code:"INCOMPATIBLE_TYPE",message:`'sankey' stat requires a numeric 'value' (got '${n}' for variable '${t}')`,context:{aesthetic:"value",variableName:t,variableType:n},suggestion:"Map each flow's amount to 'value', declaring the column numeric if it holds whole years."})},Q=(e,t)=>{const n=(0,u.readVariableName)(t.source),a=(0,u.readVariableName)(t.target),o=(0,u.readVariableName)(t.value);return n===null||a===null||o===null||![n,a,o].every(r=>e.hasVariable(r))?null:{sourceVariable:n,targetVariable:a,valueVariable:o}},ee=(e,{sourceVariable:t,targetVariable:n,valueVariable:a})=>{const o=e.getValues(t),r=e.getValues(n),s=e.getValues(a,{type:"numeric"}),l=e.getValueFormat(t),c=e.getValueFormat(n),d=new Map,v=new Map,y=[];return o.forEach((h,m)=>{const b=r[m]??null,f=L(h,l),x=L(b,c);if(f===null||x===null)return;v.set(f,h),v.set(x,b);const P=JSON.stringify([f,x]),Y=d.get(P)??0;d.set(P,Y+1);const A=s[m];typeof A!="number"||!Number.isFinite(A)||A<=0||y.push({source:f,target:x,value:A,row:m,occurrence:Y})}),{links:y,names:v}},$=(e,{sourceVariable:t,targetVariable:n})=>e.getType(t)===e.getType(n),te=(e,t,n,a)=>{const o=e.getType(t.sourceVariable);return $(e,t)?{type:o,values:n.map(r=>a.get(r)??null),valueFormat:e.getValueFormat(t.sourceVariable)}:{type:"categorical",values:[...n]}},re=(e,t,n,a,o)=>e===n.valueVariable?a.nodes.map(r=>r.value):e===n.sourceVariable&&$(t,n)?a.nodes.map(r=>o.get(r.key)??null):null,ne=(e,t,n)=>{const{links:a,names:o}=ee(e,t),r=w(a,n),s=r.nodes.length,l=y=>[...y,...Array.from({length:s},()=>null)],c=e.getVariableNames(),d=Object.fromEntries(c.map(y=>{const h=e.getValues(y),m=r.flows.map(({link:x})=>h[x.row]??null),b=re(y,e,t,r,o),f=b===null?l(m):[...m,...b];return[y,{type:e.getType(y),values:f,valueFormat:e.getValueFormat(y)}]})),v=[...r.flows.map(({link:y})=>y.source),...r.nodes.map(({key:y})=>y)];return new u.Dataset({...d,...ae(r),[i.nodeName]:te(e,t,v,o)})},ae=e=>{const t=e.flows.map(({link:l,...c})=>({[i.kind]:"flow",[i.observationKey]:JSON.stringify(["flow",l.source,l.target,l.occurrence]),[i.nodeKey]:l.source,[i.targetKey]:l.target,[i.x0]:c.x0,[i.x1]:c.x1,[i.y0]:c.y0,[i.y1]:c.y1,[i.targetY0]:c.targetY0,[i.targetY1]:c.targetY1})),n=e.nodes.map(l=>({[i.kind]:"node",[i.observationKey]:JSON.stringify(["node",l.key]),[i.nodeKey]:l.key,[i.targetKey]:l.key,[i.x0]:l.x0,[i.x1]:l.x1,[i.y0]:l.y0,[i.y1]:l.y1,[i.targetY0]:null,[i.targetY1]:null})),a=[...t,...n],o=l=>a.map(c=>c[l]),r=l=>({type:"categorical",values:o(l)}),s=l=>({type:"numeric",values:o(l)});return{[i.kind]:r(i.kind),[i.observationKey]:r(i.observationKey),[i.nodeKey]:r(i.nodeKey),[i.targetKey]:r(i.targetKey),[i.x0]:s(i.x0),[i.x1]:s(i.x1),[i.y0]:s(i.y0),[i.y1]:s(i.y1),[i.targetY0]:s(i.targetY0),[i.targetY1]:s(i.targetY1)}},oe=.4,se=.65,ie=12,le=3,ue={},ce={fill:"paint",fillAlpha:"unitInterval",alpha:"unitInterval",stroke:"color",strokeWidth:"pixels",overpaint:"overpaint"},de={fontFamily:"fontFamily",fontSize:"pixels",fontWeight:"fontWeight",textColor:"color",textOutlineColor:"color",textOutlineWidth:"pixels"},M=class extends u.Geom{constructor(...e){super(...e),this.type="sankey",this.defaultParams={align:"justify"},this.defaultStat=new X,this.aesthetics=[{kind:"data",name:"source",required:!0},{kind:"data",name:"target",required:!0},{kind:"data",name:"value",required:!0},{kind:"data",name:"node"},{kind:"visual",name:"color"},{kind:"visual",name:"alpha"}],this.identityKey={variable:i.observationKey},this.supportedPositions=["identity"],this.supportedCoordTypes=["cartesian"],this.legend={defaultPosition:"none"},this.spatialKind="render-hit-test",this.highlightStrategy="observation-rerender",this.tooltip=[{aes:"node",heading:!0},{aes:"target"},{aes:"value"}],this.styleTarget=(0,u.defineGeomStyleTarget)({observation:{vocabulary:ue,aesthetics:{fill:"color",alpha:"alpha"},rest:{fill:(0,u.token)("geom"),fillAlpha:oe},hovered:{fillAlpha:se}},parts:{node:{vocabulary:ce,aesthetics:{fill:"color",alpha:"alpha"},rest:{fill:(0,u.token)("geom"),fillAlpha:1,alpha:1,stroke:(0,u.token)("graphBackground"),strokeWidth:0}},label:{vocabulary:de,rest:{fontSize:ie,fontWeight:500,textColor:(0,u.token)("textPrimary"),textOutlineColor:(0,u.token)("graphBackground"),textOutlineWidth:le}}}}),this.resolveValueSource=t=>t.value??null,this.validateMapping=({mapping:t,computedVariables:n})=>{if(!n.has("node"))return[{code:"MISSING_STAT_OUTPUT",message:"sankey geom lays its flows out in the 'sankey' stat; remove the layer's stat"}];const a=[..._].filter(s=>t[s]!==void 0).map(s=>({code:"CONFLICTING_STAT_MAPPING",message:`sankey stat computes '${s}' from 'source' and 'target'; remove its mapping`})),o=[(0,u.readVariableName)(t.source),(0,u.readVariableName)(t.target)],r=j.flatMap(s=>{const l=(0,u.readVariableName)(t[s]);return l===null||o.includes(l)?[]:[{code:"UNSUPPORTED_MAPPING",message:`sankey geom scales '${s}' by node; map it to the source or target column rather than '${l}'`}]});return[...a,...r]},this.resolveAnchorPosition=t=>{const n=K(t);if(n===null)return null;if(n.kind==="node")return{x:(n.x0+n.x1)/2,y:1-(n.y0+n.y1)/2};const{top:a,bottom:o}=E(n,.5);return{x:(n.x0+n.x1)/2,y:1-(a+o)/2}}}compile({data:e}){return{data:e,mapping:{}}}},ye=({layer:e,panelRect:t})=>{const{nodes:n,flows:a}=N(e.data),o=s=>s*t.width,r=s=>s*t.height;return[...a.map(s=>({kind:"region",pathData:F(s,t)})),...n.map(s=>({kind:"region",pathData:`M${o(s.x0)},${r(s.y0)}H${o(s.x1)}V${r(s.y1)}H${o(s.x0)}Z`}))]},ge=({flows:e,size:t,source:n,styleReaders:a,hovered:o,shouldAnimateTransitions:r=!1})=>{const s=o===void 0?void 0:"hovered",l=(0,O.useMemo)(()=>e.map(v=>a.get("fill",v.observation,s)??"transparent"),[e,a,s]),{fillFor:c,defs:d}=(0,u.usePaintDefs)({paints:l});return(0,g.jsxs)(g.Fragment,{children:[d,(0,g.jsx)(u.GeomOverpaint,{styleReaders:a,state:s,children:e.map((v,y)=>{const h=l[y],m=a.get("stroke",v.observation,s);return(0,g.jsx)(u.GeomPath,{"data-testid":"sankey-flow",d:F(v,t),source:n,fill:h===void 0?void 0:c(h),opacity:a.get("alpha",v.observation,s),fillOpacity:a.get("fillAlpha",v.observation,s),stroke:m===void 0?void 0:(0,u.toPaintColor)(m),strokeOpacity:a.get("strokeAlpha",v.observation,s),shouldAnimateTransitions:r},v.key)})})]})},ve=6,he=e=>{const t=(e.y0+e.y1)/2;return(e.x0+e.x1)/2<.5?{x:e.x1,y:t,offsetX:ve,textAnchor:"start"}:{x:e.x0,y:t,offsetX:-6,textAnchor:"end"}},me=({nodes:e,valueFormat:t,styleReaders:n,hovered:a})=>{const o=a===void 0?void 0:"hovered",r=n.part("label"),s=(0,u.useGraphLocale)(),l=(0,u.useSceneSelector)(d=>d.config.numberFormat),c=(0,O.useMemo)(()=>(0,u.createValueFormatter)({valueFormat:t,locale:s,numberFormat:l}),[t,s,l]);return(0,g.jsx)("g",{pointerEvents:"none",children:e.map(d=>{const v=d.observation[i.nodeName];if(v==null)return null;const y=he(d),h=r?.get("textColor",d.observation,o),m=r?.get("textOutlineColor",d.observation,o);return(0,g.jsx)("text",{"data-testid":"sankey-label",x:(0,u.toPercent)(y.x),y:(0,u.toPercent)(y.y),dx:y.offsetX,textAnchor:y.textAnchor,dominantBaseline:"central",fontFamily:r?.get("fontFamily",d.observation,o),fontSize:r?.get("fontSize",d.observation,o),fontWeight:r?.get("fontWeight",d.observation,o),fill:h===void 0?void 0:(0,u.toPaintColor)(h),stroke:m===void 0?void 0:(0,u.toPaintColor)(m),strokeWidth:r?.get("textOutlineWidth",d.observation,o),strokeLinejoin:"round",paintOrder:"stroke",children:c(v,d.observation)},d.key)})})},pe=({nodes:e,styleReaders:t,hovered:n,shouldAnimateTransitions:a=!1})=>{const o=n===void 0?void 0:"hovered",r=t.part("node"),s=(0,O.useMemo)(()=>e.map(d=>r?.get("fill",d.observation,o)??"transparent"),[e,r,o]),{fillFor:l,defs:c}=(0,u.usePaintDefs)({paints:s});return(0,g.jsxs)(g.Fragment,{children:[c,(0,g.jsx)(u.GeomOverpaint,{styleReaders:r?.get("overpaint",void 0,o)===void 0?t:r,state:o,children:e.map((d,v)=>{const y=s[v],h=r?.get("stroke",d.observation,o);return(0,g.jsx)(u.GeomRect,{"data-testid":"sankey-node",x:(0,u.toPercent)(d.x0),y:(0,u.toPercent)(d.y0),width:(0,u.toPercent)(d.x1-d.x0),height:(0,u.toPercent)(d.y1-d.y0),fill:y===void 0?void 0:l(y),opacity:r?.get("alpha",d.observation,o),fillOpacity:r?.get("fillAlpha",d.observation,o),stroke:h===void 0?void 0:(0,u.toPaintColor)(h),strokeWidth:r?.get("strokeWidth",d.observation,o),effects:(0,u.readGeomEffects)(t,d.observation,o),shouldAnimateTransitions:a},d.key)})})]})},fe={type:"text"},T=({observations:e,layer:t,size:n,styleReaders:a,hovered:o,shouldAnimateTransitions:r=!1})=>(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(ge,{flows:e.flows,size:n,source:t,styleReaders:a,hovered:o,shouldAnimateTransitions:r}),(0,g.jsx)(pe,{nodes:e.nodes,styleReaders:a,hovered:o,shouldAnimateTransitions:r}),(0,g.jsx)(me,{nodes:e.nodes,valueFormat:t.data.hasVariable(i.nodeName)?t.data.getValueFormat(i.nodeName):fe,styleReaders:a,hovered:o})]}),xe=({layer:e,size:t,styleReaders:n})=>(0,g.jsx)(T,{observations:N(e.data),layer:e,size:t,styleReaders:n}),ke=({layer:e})=>{const{nodes:t,flows:n}=N(e.data),a=[...t].reverse(),o=[...n].reverse();return r=>{const s=a.find(c=>r.x>=c.x0&&r.x<=c.x1&&r.y>=c.y0&&r.y<=c.y1);if(s!==void 0)return{key:s.key};const l=o.find(c=>W(c,r));return l===void 0?null:{key:l.key}}},be=({layer:e,primary:t,size:n,styleReaders:a})=>{const o=N(e.data),r=t.observation;return(0,g.jsx)("g",{"data-testid":"hovered-observations",children:(0,g.jsx)(T,{observations:(0,O.useMemo)(()=>Se(o,r),[o,r]),layer:e,size:n,styleReaders:a,hovered:r})})},Se=(e,t)=>{const n=K(t);if(n===null)return{nodes:[],flows:[]};if(n.kind==="node"){const a=e.flows.filter(r=>V(r,n)),o=new Set(a.flatMap(r=>[r.nodeKey,r.targetKey]));return{nodes:e.nodes.filter(r=>o.has(r.nodeKey)),flows:a}}return{nodes:e.nodes.filter(a=>V(n,a)),flows:[n]}},Ne=({layer:e,size:t,styleReaders:n,shouldAnimateTransitions:a})=>(0,g.jsx)(T,{observations:N(e.data),layer:e,size:t,styleReaders:n,shouldAnimateTransitions:a}),Ae=(0,u.defineGeomRenderer)(new M,{coord:"cartesian",swatchShape:"square",overpaintPlacement:"manual",render:({layer:e,panelRect:t,styleReaders:n,shouldAnimateTransitions:a})=>(0,g.jsx)(Ne,{layer:e,size:t,styleReaders:n,shouldAnimateTransitions:a}),renderHighlight:({layer:e,panelRect:t,styleReaders:n})=>(0,g.jsx)(xe,{layer:e,size:t,styleReaders:n}),renderHover:({layer:e,primary:t,panelRect:n,styleReaders:a})=>(0,g.jsx)(be,{layer:e,primary:t,size:n,styleReaders:a}),renderHoverCompanions:()=>null,hitTest:ke,getEditOutlineShapes:ye});exports.SankeyGeom=M;exports.sankey=Ae;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { Dataset as H, Geom as B, GeomPath as U, GeomRect as X, Stat as R, UserInputError as j, createValueFormatter as z, defineGeomRenderer as q, defineGeomStyleTarget as J, readVariableName as m, toPaintColor as O, toPercent as b, token as N, useGraphLocale as Z, usePaintDefs as I, useSceneSelector as Q } from "@graphysdk/react";
2
- import { sankey as ee, sankeyCenter as te, sankeyJustify as re, sankeyLeft as ne, sankeyRight as ae } from "d3-sankey";
1
+ import { Dataset as B, Geom as U, GeomOverpaint as I, GeomPath as X, GeomRect as j, Stat as R, UserInputError as z, createValueFormatter as q, defineGeomRenderer as J, defineGeomStyleTarget as Z, readGeomEffects as Q, readVariableName as m, toPaintColor as K, toPercent as b, token as N, useGraphLocale as ee, usePaintDefs as M, useSceneSelector as te } from "@graphysdk/react";
2
+ import { sankey as re, sankeyCenter as ne, sankeyJustify as ae, sankeyLeft as oe, sankeyRight as se } from "d3-sankey";
3
3
  import { useMemo as T } from "react";
4
4
  import { Fragment as Y, jsx as g, jsxs as C } from "react/jsx-runtime";
5
5
  var i = {
@@ -64,18 +64,18 @@ var i = {
64
64
  flows: a
65
65
  };
66
66
  return P.set(e, o), o;
67
- }, _ = (e, t) => e.nodeKey === t.nodeKey || e.targetKey === t.nodeKey, oe = (e) => e * e * (3 - 2 * e), M = (e, t) => {
68
- const n = oe(t);
67
+ }, _ = (e, t) => e.nodeKey === t.nodeKey || e.targetKey === t.nodeKey, ie = (e) => e * e * (3 - 2 * e), W = (e, t) => {
68
+ const n = ie(t);
69
69
  return {
70
70
  top: e.y0 + (e.targetY0 - e.y0) * n,
71
71
  bottom: e.y1 + (e.targetY1 - e.y1) * n
72
72
  };
73
- }, se = (e, t) => {
73
+ }, le = (e, t) => {
74
74
  const n = e.x1 - e.x0;
75
75
  if (n <= 0 || t.x < e.x0 || t.x > e.x1) return !1;
76
- const { top: a, bottom: o } = M(e, (t.x - e.x0) / n);
76
+ const { top: a, bottom: o } = W(e, (t.x - e.x0) / n);
77
77
  return t.y >= a && t.y <= o;
78
- }, W = (e, t) => {
78
+ }, G = (e, t) => {
79
79
  const n = (u) => u * t.width, a = (u) => u * t.height, o = n(e.x0), r = n(e.x1), s = n(e.x0 + (e.x1 - e.x0) / 3), l = n(e.x0 + (e.x1 - e.x0) * 2 / 3);
80
80
  return [
81
81
  `M${o},${a(e.y0)}`,
@@ -84,18 +84,18 @@ var i = {
84
84
  `C${l},${a(e.targetY1)} ${s},${a(e.y1)} ${o},${a(e.y1)}`,
85
85
  "Z"
86
86
  ].join("");
87
- }, ie = 0.018, le = 0.03, ue = {
88
- justify: re,
89
- left: ne,
90
- right: ae,
91
- center: te
92
- }, ce = (e, t) => {
93
- const n = ye(e);
87
+ }, ue = 0.018, ce = 0.03, de = {
88
+ justify: ae,
89
+ left: oe,
90
+ right: se,
91
+ center: ne
92
+ }, ye = (e, t) => {
93
+ const n = ge(e);
94
94
  if (n.length === 0) return {
95
95
  nodes: [],
96
96
  flows: []
97
97
  };
98
- const a = [...new Set(n.flatMap((r) => [r.source, r.target]))], o = ee().nodeId((r) => r.key).nodeAlign(ue[t]).nodeWidth(ie).nodePadding(le).extent([[0, 0], [1, 1]])({
98
+ const a = [...new Set(n.flatMap((r) => [r.source, r.target]))], o = re().nodeId((r) => r.key).nodeAlign(de[t]).nodeWidth(ue).nodePadding(ce).extent([[0, 0], [1, 1]])({
99
99
  nodes: a.map((r) => ({ key: r })),
100
100
  links: n.map((r) => ({
101
101
  source: r.source,
@@ -126,7 +126,7 @@ var i = {
126
126
  };
127
127
  })
128
128
  };
129
- }, p = (e) => Math.min(1, Math.max(0, e ?? 0)), ye = (e) => {
129
+ }, p = (e) => Math.min(1, Math.max(0, e ?? 0)), ge = (e) => {
130
130
  const t = /* @__PURE__ */ new Map(), n = (a, o) => {
131
131
  const r = /* @__PURE__ */ new Set(), s = [a];
132
132
  for (; s.length > 0; ) {
@@ -137,46 +137,46 @@ var i = {
137
137
  return !1;
138
138
  };
139
139
  return e.filter((a) => t.get(a.source)?.has(a.target) === !0 ? !0 : n(a.target, a.source) ? !1 : (t.set(a.source, (t.get(a.source) ?? /* @__PURE__ */ new Set()).add(a.target)), !0));
140
- }, D = /* @__PURE__ */ new Set(["node"]), G = ["color", "alpha"], de = [
140
+ }, D = /* @__PURE__ */ new Set(["node"]), H = ["color", "alpha"], ve = [
141
141
  "justify",
142
142
  "left",
143
143
  "right",
144
144
  "center"
145
- ], ge = class extends R {
145
+ ], he = class extends R {
146
146
  constructor(...e) {
147
147
  super(...e), this.type = "sankey", this.computedVariables = D;
148
148
  }
149
149
  computeStat({ data: e, mapping: t, params: n }) {
150
- const a = xe(e, t);
150
+ const a = be(e, t);
151
151
  return a === null ? {
152
152
  data: e,
153
153
  mapping: {}
154
- } : (fe(e, a), {
155
- data: Ne(e, a, me(n)),
154
+ } : (ke(e, a), {
155
+ data: Oe(e, a, xe(n)),
156
156
  mapping: {
157
157
  node: i.nodeName,
158
- ...ve(t, a)
158
+ ...pe(t, a)
159
159
  }
160
160
  });
161
161
  }
162
- }, ve = (e, t) => {
162
+ }, pe = (e, t) => {
163
163
  const n = {};
164
- for (const a of G) {
165
- const o = he(a, e[a], t);
164
+ for (const a of H) {
165
+ const o = me(a, e[a], t);
166
166
  o !== null && (n[a] = o);
167
167
  }
168
168
  return n;
169
- }, he = (e, t, { sourceVariable: n, targetVariable: a }) => {
169
+ }, me = (e, t, { sourceVariable: n, targetVariable: a }) => {
170
170
  if (t === void 0) return e === "color" ? i.nodeKey : null;
171
171
  const o = m(t);
172
172
  return o === n ? i.nodeKey : o === a ? i.targetKey : null;
173
- }, pe = (e) => de.includes(e), me = (e) => {
173
+ }, fe = (e) => ve.includes(e), xe = (e) => {
174
174
  const t = e?.align;
175
- return pe(t) ? t : "justify";
176
- }, $ = (e, t) => e === null ? null : e instanceof Date ? t.type === "year" ? String(e.getUTCFullYear()) : e.toISOString() : String(e), fe = (e, { valueVariable: t }) => {
175
+ return fe(t) ? t : "justify";
176
+ }, $ = (e, t) => e === null ? null : e instanceof Date ? t.type === "year" ? String(e.getUTCFullYear()) : e.toISOString() : String(e), ke = (e, { valueVariable: t }) => {
177
177
  const n = e.getType(t);
178
178
  if (!(e.size() === 0 || n === "numeric"))
179
- throw new j({
179
+ throw new z({
180
180
  code: "INCOMPATIBLE_TYPE",
181
181
  message: `'sankey' stat requires a numeric 'value' (got '${n}' for variable '${t}')`,
182
182
  context: {
@@ -186,7 +186,7 @@ var i = {
186
186
  },
187
187
  suggestion: "Map each flow's amount to 'value', declaring the column numeric if it holds whole years."
188
188
  });
189
- }, xe = (e, t) => {
189
+ }, be = (e, t) => {
190
190
  const n = m(t.source), a = m(t.target), o = m(t.value);
191
191
  return n === null || a === null || o === null || ![
192
192
  n,
@@ -197,27 +197,27 @@ var i = {
197
197
  targetVariable: a,
198
198
  valueVariable: o
199
199
  };
200
- }, ke = (e, { sourceVariable: t, targetVariable: n, valueVariable: a }) => {
201
- const o = e.getValues(t), r = e.getValues(n), s = e.getValues(a, { type: "numeric" }), l = e.getValueFormat(t), u = e.getValueFormat(n), c = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), y = [];
200
+ }, Se = (e, { sourceVariable: t, targetVariable: n, valueVariable: a }) => {
201
+ const o = e.getValues(t), r = e.getValues(n), s = e.getValues(a, { type: "numeric" }), l = e.getValueFormat(t), u = e.getValueFormat(n), c = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), d = [];
202
202
  return o.forEach((v, h) => {
203
203
  const S = r[h] ?? null, f = $(v, l), x = $(S, u);
204
204
  if (f === null || x === null) return;
205
- d.set(f, v), d.set(x, S);
205
+ y.set(f, v), y.set(x, S);
206
206
  const F = JSON.stringify([f, x]), V = c.get(F) ?? 0;
207
207
  c.set(F, V + 1);
208
- const K = s[h];
209
- typeof K != "number" || !Number.isFinite(K) || K <= 0 || y.push({
208
+ const O = s[h];
209
+ typeof O != "number" || !Number.isFinite(O) || O <= 0 || d.push({
210
210
  source: f,
211
211
  target: x,
212
- value: K,
212
+ value: O,
213
213
  row: h,
214
214
  occurrence: V
215
215
  });
216
216
  }), {
217
- links: y,
218
- names: d
217
+ links: d,
218
+ names: y
219
219
  };
220
- }, w = (e, { sourceVariable: t, targetVariable: n }) => e.getType(t) === e.getType(n), be = (e, t, n, a) => {
220
+ }, w = (e, { sourceVariable: t, targetVariable: n }) => e.getType(t) === e.getType(n), Ne = (e, t, n, a) => {
221
221
  const o = e.getType(t.sourceVariable);
222
222
  return w(e, t) ? {
223
223
  type: o,
@@ -227,21 +227,21 @@ var i = {
227
227
  type: "categorical",
228
228
  values: [...n]
229
229
  };
230
- }, Se = (e, t, n, a, o) => e === n.valueVariable ? a.nodes.map((r) => r.value) : e === n.sourceVariable && w(t, n) ? a.nodes.map((r) => o.get(r.key) ?? null) : null, Ne = (e, t, n) => {
231
- const { links: a, names: o } = ke(e, t), r = ce(a, n), s = r.nodes.length, l = (y) => [...y, ...Array.from({ length: s }, () => null)], u = e.getVariableNames(), c = Object.fromEntries(u.map((y) => {
232
- const v = e.getValues(y), h = r.flows.map(({ link: x }) => v[x.row] ?? null), S = Se(y, e, t, r, o), f = S === null ? l(h) : [...h, ...S];
233
- return [y, {
234
- type: e.getType(y),
230
+ }, Ae = (e, t, n, a, o) => e === n.valueVariable ? a.nodes.map((r) => r.value) : e === n.sourceVariable && w(t, n) ? a.nodes.map((r) => o.get(r.key) ?? null) : null, Oe = (e, t, n) => {
231
+ const { links: a, names: o } = Se(e, t), r = ye(a, n), s = r.nodes.length, l = (d) => [...d, ...Array.from({ length: s }, () => null)], u = e.getVariableNames(), c = Object.fromEntries(u.map((d) => {
232
+ const v = e.getValues(d), h = r.flows.map(({ link: x }) => v[x.row] ?? null), S = Ae(d, e, t, r, o), f = S === null ? l(h) : [...h, ...S];
233
+ return [d, {
234
+ type: e.getType(d),
235
235
  values: f,
236
- valueFormat: e.getValueFormat(y)
236
+ valueFormat: e.getValueFormat(d)
237
237
  }];
238
- })), d = [...r.flows.map(({ link: y }) => y.source), ...r.nodes.map(({ key: y }) => y)];
239
- return new H({
238
+ })), y = [...r.flows.map(({ link: d }) => d.source), ...r.nodes.map(({ key: d }) => d)];
239
+ return new B({
240
240
  ...c,
241
- ...Ae(r),
242
- [i.nodeName]: be(e, t, d, o)
241
+ ...Ke(r),
242
+ [i.nodeName]: Ne(e, t, y, o)
243
243
  });
244
- }, Ae = (e) => {
244
+ }, Ke = (e) => {
245
245
  const t = e.flows.map(({ link: l, ...u }) => ({
246
246
  [i.kind]: "flow",
247
247
  [i.observationKey]: JSON.stringify([
@@ -288,22 +288,23 @@ var i = {
288
288
  [i.targetY0]: s(i.targetY0),
289
289
  [i.targetY1]: s(i.targetY1)
290
290
  };
291
- }, Ke = 0.4, Oe = 0.65, Te = 12, Ye = 3, Ce = {}, Le = {
291
+ }, Te = 0.4, Ye = 0.65, Ce = 12, Le = 3, Ee = {}, Fe = {
292
292
  fill: "paint",
293
293
  fillAlpha: "unitInterval",
294
294
  alpha: "unitInterval",
295
295
  stroke: "color",
296
- strokeWidth: "pixels"
297
- }, Ee = {
296
+ strokeWidth: "pixels",
297
+ overpaint: "overpaint"
298
+ }, Ve = {
298
299
  fontFamily: "fontFamily",
299
300
  fontSize: "pixels",
300
301
  fontWeight: "fontWeight",
301
302
  textColor: "color",
302
303
  textOutlineColor: "color",
303
304
  textOutlineWidth: "pixels"
304
- }, Fe = class extends B {
305
+ }, Pe = class extends U {
305
306
  constructor(...e) {
306
- super(...e), this.type = "sankey", this.defaultParams = { align: "justify" }, this.defaultStat = new ge(), this.aesthetics = [
307
+ super(...e), this.type = "sankey", this.defaultParams = { align: "justify" }, this.defaultStat = new he(), this.aesthetics = [
307
308
  {
308
309
  kind: "data",
309
310
  name: "source",
@@ -338,22 +339,22 @@ var i = {
338
339
  },
339
340
  { aes: "target" },
340
341
  { aes: "value" }
341
- ], this.styleTarget = J({
342
+ ], this.styleTarget = Z({
342
343
  observation: {
343
- vocabulary: Ce,
344
+ vocabulary: Ee,
344
345
  aesthetics: {
345
346
  fill: "color",
346
347
  alpha: "alpha"
347
348
  },
348
349
  rest: {
349
350
  fill: N("geom"),
350
- fillAlpha: Ke
351
+ fillAlpha: Te
351
352
  },
352
- hovered: { fillAlpha: Oe }
353
+ hovered: { fillAlpha: Ye }
353
354
  },
354
355
  parts: {
355
356
  node: {
356
- vocabulary: Le,
357
+ vocabulary: Fe,
357
358
  aesthetics: {
358
359
  fill: "color",
359
360
  alpha: "alpha"
@@ -367,13 +368,13 @@ var i = {
367
368
  }
368
369
  },
369
370
  label: {
370
- vocabulary: Ee,
371
+ vocabulary: Ve,
371
372
  rest: {
372
- fontSize: Te,
373
+ fontSize: Ce,
373
374
  fontWeight: 500,
374
375
  textColor: N("textPrimary"),
375
376
  textOutlineColor: N("graphBackground"),
376
- textOutlineWidth: Ye
377
+ textOutlineWidth: Le
377
378
  }
378
379
  }
379
380
  }
@@ -385,7 +386,7 @@ var i = {
385
386
  const a = [...D].filter((s) => t[s] !== void 0).map((s) => ({
386
387
  code: "CONFLICTING_STAT_MAPPING",
387
388
  message: `sankey stat computes '${s}' from 'source' and 'target'; remove its mapping`
388
- })), o = [m(t.source), m(t.target)], r = G.flatMap((s) => {
389
+ })), o = [m(t.source), m(t.target)], r = H.flatMap((s) => {
389
390
  const l = m(t[s]);
390
391
  return l === null || o.includes(l) ? [] : [{
391
392
  code: "UNSUPPORTED_MAPPING",
@@ -400,7 +401,7 @@ var i = {
400
401
  x: (n.x0 + n.x1) / 2,
401
402
  y: 1 - (n.y0 + n.y1) / 2
402
403
  };
403
- const { top: a, bottom: o } = M(n, 0.5);
404
+ const { top: a, bottom: o } = W(n, 0.5);
404
405
  return {
405
406
  x: (n.x0 + n.x1) / 2,
406
407
  y: 1 - (a + o) / 2
@@ -413,41 +414,45 @@ var i = {
413
414
  mapping: {}
414
415
  };
415
416
  }
416
- }, Ve = ({ layer: e, panelRect: t }) => {
417
+ }, _e = ({ layer: e, panelRect: t }) => {
417
418
  const { nodes: n, flows: a } = A(e.data), o = (s) => s * t.width, r = (s) => s * t.height;
418
419
  return [...a.map((s) => ({
419
420
  kind: "region",
420
- pathData: W(s, t)
421
+ pathData: G(s, t)
421
422
  })), ...n.map((s) => ({
422
423
  kind: "region",
423
424
  pathData: `M${o(s.x0)},${r(s.y0)}H${o(s.x1)}V${r(s.y1)}H${o(s.x0)}Z`
424
425
  }))];
425
- }, Pe = ({ flows: e, size: t, source: n, styleReaders: a, isHovered: o = !1, shouldAnimateTransitions: r = !1 }) => {
426
- const s = o ? "hovered" : void 0, l = T(() => e.map((d) => a.get("fill", d.observation, s) ?? "transparent"), [
426
+ }, $e = ({ flows: e, size: t, source: n, styleReaders: a, hovered: o, shouldAnimateTransitions: r = !1 }) => {
427
+ const s = o === void 0 ? void 0 : "hovered", l = T(() => e.map((y) => a.get("fill", y.observation, s) ?? "transparent"), [
427
428
  e,
428
429
  a,
429
430
  s
430
- ]), { fillFor: u, defs: c } = I({ paints: l });
431
- return /* @__PURE__ */ C(Y, { children: [c, e.map((d, y) => {
432
- const v = l[y], h = a.get("stroke", d.observation, s);
433
- return /* @__PURE__ */ g(U, {
434
- "data-testid": "sankey-flow",
435
- d: W(d, t),
436
- source: n,
437
- fill: v === void 0 ? void 0 : u(v),
438
- opacity: a.get("alpha", d.observation, s),
439
- fillOpacity: a.get("fillAlpha", d.observation, s),
440
- stroke: h === void 0 ? void 0 : O(h),
441
- strokeOpacity: a.get("strokeAlpha", d.observation, s),
442
- shouldAnimateTransitions: r
443
- }, d.key);
431
+ ]), { fillFor: u, defs: c } = M({ paints: l });
432
+ return /* @__PURE__ */ C(Y, { children: [c, /* @__PURE__ */ g(I, {
433
+ styleReaders: a,
434
+ state: s,
435
+ children: e.map((y, d) => {
436
+ const v = l[d], h = a.get("stroke", y.observation, s);
437
+ return /* @__PURE__ */ g(X, {
438
+ "data-testid": "sankey-flow",
439
+ d: G(y, t),
440
+ source: n,
441
+ fill: v === void 0 ? void 0 : u(v),
442
+ opacity: a.get("alpha", y.observation, s),
443
+ fillOpacity: a.get("fillAlpha", y.observation, s),
444
+ stroke: h === void 0 ? void 0 : K(h),
445
+ strokeOpacity: a.get("strokeAlpha", y.observation, s),
446
+ shouldAnimateTransitions: r
447
+ }, y.key);
448
+ })
444
449
  })] });
445
- }, _e = 6, $e = (e) => {
450
+ }, Ie = 6, Me = (e) => {
446
451
  const t = (e.y0 + e.y1) / 2;
447
452
  return (e.x0 + e.x1) / 2 < 0.5 ? {
448
453
  x: e.x1,
449
454
  y: t,
450
- offsetX: _e,
455
+ offsetX: Ie,
451
456
  textAnchor: "start"
452
457
  } : {
453
458
  x: e.x0,
@@ -455,8 +460,8 @@ var i = {
455
460
  offsetX: -6,
456
461
  textAnchor: "end"
457
462
  };
458
- }, Ie = ({ nodes: e, valueFormat: t, styleReaders: n, isHovered: a = !1 }) => {
459
- const o = a ? "hovered" : void 0, r = n.part("label"), s = Z(), l = Q((c) => c.config.numberFormat), u = T(() => z({
463
+ }, We = ({ nodes: e, valueFormat: t, styleReaders: n, hovered: a }) => {
464
+ const o = a === void 0 ? void 0 : "hovered", r = n.part("label"), s = ee(), l = te((c) => c.config.numberFormat), u = T(() => q({
460
465
  valueFormat: t,
461
466
  locale: s,
462
467
  numberFormat: l
@@ -468,97 +473,102 @@ var i = {
468
473
  return /* @__PURE__ */ g("g", {
469
474
  pointerEvents: "none",
470
475
  children: e.map((c) => {
471
- const d = c.observation[i.nodeName];
472
- if (d == null) return null;
473
- const y = $e(c), v = r?.get("textColor", c.observation, o), h = r?.get("textOutlineColor", c.observation, o);
476
+ const y = c.observation[i.nodeName];
477
+ if (y == null) return null;
478
+ const d = Me(c), v = r?.get("textColor", c.observation, o), h = r?.get("textOutlineColor", c.observation, o);
474
479
  return /* @__PURE__ */ g("text", {
475
480
  "data-testid": "sankey-label",
476
- x: b(y.x),
477
- y: b(y.y),
478
- dx: y.offsetX,
479
- textAnchor: y.textAnchor,
481
+ x: b(d.x),
482
+ y: b(d.y),
483
+ dx: d.offsetX,
484
+ textAnchor: d.textAnchor,
480
485
  dominantBaseline: "central",
481
486
  fontFamily: r?.get("fontFamily", c.observation, o),
482
487
  fontSize: r?.get("fontSize", c.observation, o),
483
488
  fontWeight: r?.get("fontWeight", c.observation, o),
484
- fill: v === void 0 ? void 0 : O(v),
485
- stroke: h === void 0 ? void 0 : O(h),
489
+ fill: v === void 0 ? void 0 : K(v),
490
+ stroke: h === void 0 ? void 0 : K(h),
486
491
  strokeWidth: r?.get("textOutlineWidth", c.observation, o),
487
492
  strokeLinejoin: "round",
488
493
  paintOrder: "stroke",
489
- children: u(d, c.observation)
494
+ children: u(y, c.observation)
490
495
  }, c.key);
491
496
  })
492
497
  });
493
- }, Me = ({ nodes: e, styleReaders: t, isHovered: n = !1, shouldAnimateTransitions: a = !1 }) => {
494
- const o = n ? "hovered" : void 0, r = t.part("node"), s = T(() => e.map((c) => r?.get("fill", c.observation, o) ?? "transparent"), [
498
+ }, Ge = ({ nodes: e, styleReaders: t, hovered: n, shouldAnimateTransitions: a = !1 }) => {
499
+ const o = n === void 0 ? void 0 : "hovered", r = t.part("node"), s = T(() => e.map((c) => r?.get("fill", c.observation, o) ?? "transparent"), [
495
500
  e,
496
501
  r,
497
502
  o
498
- ]), { fillFor: l, defs: u } = I({ paints: s });
499
- return /* @__PURE__ */ C(Y, { children: [u, e.map((c, d) => {
500
- const y = s[d], v = r?.get("stroke", c.observation, o);
501
- return /* @__PURE__ */ g(X, {
502
- "data-testid": "sankey-node",
503
- x: b(c.x0),
504
- y: b(c.y0),
505
- width: b(c.x1 - c.x0),
506
- height: b(c.y1 - c.y0),
507
- fill: y === void 0 ? void 0 : l(y),
508
- opacity: r?.get("alpha", c.observation, o),
509
- fillOpacity: r?.get("fillAlpha", c.observation, o),
510
- stroke: v === void 0 ? void 0 : O(v),
511
- strokeWidth: r?.get("strokeWidth", c.observation, o),
512
- shouldAnimateTransitions: a
513
- }, c.key);
503
+ ]), { fillFor: l, defs: u } = M({ paints: s });
504
+ return /* @__PURE__ */ C(Y, { children: [u, /* @__PURE__ */ g(I, {
505
+ styleReaders: r?.get("overpaint", void 0, o) === void 0 ? t : r,
506
+ state: o,
507
+ children: e.map((c, y) => {
508
+ const d = s[y], v = r?.get("stroke", c.observation, o);
509
+ return /* @__PURE__ */ g(j, {
510
+ "data-testid": "sankey-node",
511
+ x: b(c.x0),
512
+ y: b(c.y0),
513
+ width: b(c.x1 - c.x0),
514
+ height: b(c.y1 - c.y0),
515
+ fill: d === void 0 ? void 0 : l(d),
516
+ opacity: r?.get("alpha", c.observation, o),
517
+ fillOpacity: r?.get("fillAlpha", c.observation, o),
518
+ stroke: v === void 0 ? void 0 : K(v),
519
+ strokeWidth: r?.get("strokeWidth", c.observation, o),
520
+ effects: Q(t, c.observation, o),
521
+ shouldAnimateTransitions: a
522
+ }, c.key);
523
+ })
514
524
  })] });
515
- }, We = { type: "text" }, E = ({ observations: e, layer: t, size: n, styleReaders: a, isHovered: o = !1, shouldAnimateTransitions: r = !1 }) => /* @__PURE__ */ C(Y, { children: [
516
- /* @__PURE__ */ g(Pe, {
525
+ }, De = { type: "text" }, E = ({ observations: e, layer: t, size: n, styleReaders: a, hovered: o, shouldAnimateTransitions: r = !1 }) => /* @__PURE__ */ C(Y, { children: [
526
+ /* @__PURE__ */ g($e, {
517
527
  flows: e.flows,
518
528
  size: n,
519
529
  source: t,
520
530
  styleReaders: a,
521
- isHovered: o,
531
+ hovered: o,
522
532
  shouldAnimateTransitions: r
523
533
  }),
524
- /* @__PURE__ */ g(Me, {
534
+ /* @__PURE__ */ g(Ge, {
525
535
  nodes: e.nodes,
526
536
  styleReaders: a,
527
- isHovered: o,
537
+ hovered: o,
528
538
  shouldAnimateTransitions: r
529
539
  }),
530
- /* @__PURE__ */ g(Ie, {
540
+ /* @__PURE__ */ g(We, {
531
541
  nodes: e.nodes,
532
- valueFormat: t.data.hasVariable(i.nodeName) ? t.data.getValueFormat(i.nodeName) : We,
542
+ valueFormat: t.data.hasVariable(i.nodeName) ? t.data.getValueFormat(i.nodeName) : De,
533
543
  styleReaders: a,
534
- isHovered: o
544
+ hovered: o
535
545
  })
536
- ] }), De = ({ layer: e, size: t, styleReaders: n }) => /* @__PURE__ */ g(E, {
546
+ ] }), He = ({ layer: e, size: t, styleReaders: n }) => /* @__PURE__ */ g(E, {
537
547
  observations: A(e.data),
538
548
  layer: e,
539
549
  size: t,
540
550
  styleReaders: n
541
- }), Ge = ({ layer: e }) => {
551
+ }), we = ({ layer: e }) => {
542
552
  const { nodes: t, flows: n } = A(e.data), a = [...t].reverse(), o = [...n].reverse();
543
553
  return (r) => {
544
554
  const s = a.find((u) => r.x >= u.x0 && r.x <= u.x1 && r.y >= u.y0 && r.y <= u.y1);
545
555
  if (s !== void 0) return { key: s.key };
546
- const l = o.find((u) => se(u, r));
556
+ const l = o.find((u) => le(u, r));
547
557
  return l === void 0 ? null : { key: l.key };
548
558
  };
549
- }, we = ({ layer: e, primary: t, size: n, styleReaders: a }) => {
559
+ }, Be = ({ layer: e, primary: t, size: n, styleReaders: a }) => {
550
560
  const o = A(e.data), r = t.observation;
551
561
  return /* @__PURE__ */ g("g", {
552
562
  "data-testid": "hovered-observations",
553
563
  children: /* @__PURE__ */ g(E, {
554
- observations: T(() => He(o, r), [o, r]),
564
+ observations: T(() => Ue(o, r), [o, r]),
555
565
  layer: e,
556
566
  size: n,
557
567
  styleReaders: a,
558
- isHovered: !0
568
+ hovered: r
559
569
  })
560
570
  });
561
- }, He = (e, t) => {
571
+ }, Ue = (e, t) => {
562
572
  const n = L(t);
563
573
  if (n === null) return {
564
574
  nodes: [],
@@ -575,37 +585,38 @@ var i = {
575
585
  nodes: e.nodes.filter((a) => _(n, a)),
576
586
  flows: [n]
577
587
  };
578
- }, Be = ({ layer: e, size: t, styleReaders: n, shouldAnimateTransitions: a }) => /* @__PURE__ */ g(E, {
588
+ }, Xe = ({ layer: e, size: t, styleReaders: n, shouldAnimateTransitions: a }) => /* @__PURE__ */ g(E, {
579
589
  observations: A(e.data),
580
590
  layer: e,
581
591
  size: t,
582
592
  styleReaders: n,
583
593
  shouldAnimateTransitions: a
584
- }), ze = q(new Fe(), {
594
+ }), Je = J(new Pe(), {
585
595
  coord: "cartesian",
586
596
  swatchShape: "square",
587
- render: ({ layer: e, panelRect: t, styleReaders: n, shouldAnimateTransitions: a }) => /* @__PURE__ */ g(Be, {
597
+ overpaintPlacement: "manual",
598
+ render: ({ layer: e, panelRect: t, styleReaders: n, shouldAnimateTransitions: a }) => /* @__PURE__ */ g(Xe, {
588
599
  layer: e,
589
600
  size: t,
590
601
  styleReaders: n,
591
602
  shouldAnimateTransitions: a
592
603
  }),
593
- renderHighlight: ({ layer: e, panelRect: t, styleReaders: n }) => /* @__PURE__ */ g(De, {
604
+ renderHighlight: ({ layer: e, panelRect: t, styleReaders: n }) => /* @__PURE__ */ g(He, {
594
605
  layer: e,
595
606
  size: t,
596
607
  styleReaders: n
597
608
  }),
598
- renderHover: ({ layer: e, primary: t, panelRect: n, styleReaders: a }) => /* @__PURE__ */ g(we, {
609
+ renderHover: ({ layer: e, primary: t, panelRect: n, styleReaders: a }) => /* @__PURE__ */ g(Be, {
599
610
  layer: e,
600
611
  primary: t,
601
612
  size: n,
602
613
  styleReaders: a
603
614
  }),
604
615
  renderHoverCompanions: () => null,
605
- hitTest: Ge,
606
- getEditOutlineShapes: Ve
616
+ hitTest: we,
617
+ getEditOutlineShapes: _e
607
618
  });
608
619
  export {
609
- Fe as SankeyGeom,
610
- ze as sankey
620
+ Pe as SankeyGeom,
621
+ Je as sankey
611
622
  };
@@ -1,4 +1,4 @@
1
- import { GeomStyleReaders, SceneLayer } from '@graphysdk/react';
1
+ import { GeomStyleReaders, Observation, SceneLayer } from '@graphysdk/react';
2
2
  import { SankeyFlowObservation } from '../../utils/read-sankey';
3
3
  export interface SankeyFlowsProps {
4
4
  flows: readonly SankeyFlowObservation[];
@@ -10,8 +10,9 @@ export interface SankeyFlowsProps {
10
10
  /** The layer the ribbons are drawn from, so a resize redraws them in place and only new data morphs them. */
11
11
  source: SceneLayer;
12
12
  styleReaders: GeomStyleReaders;
13
- isHovered?: boolean;
13
+ /** The observation under the pointer: paints in the `hovered` state. */
14
+ hovered?: Observation;
14
15
  shouldAnimateTransitions?: boolean;
15
16
  }
16
- /** Each flow as a filled ribbon, painted through the observations' readers. */
17
- export declare const SankeyFlows: ({ flows, size, source, styleReaders, isHovered, shouldAnimateTransitions, }: SankeyFlowsProps) => import("react/jsx-runtime").JSX.Element;
17
+ /** Each flow as a filled ribbon, painted through the observations' readers, under the geom's overpaint. */
18
+ export declare const SankeyFlows: ({ flows, size, source, styleReaders, hovered, shouldAnimateTransitions, }: SankeyFlowsProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,14 +1,15 @@
1
- import { GeomStyleReaders, ValueFormat } from '@graphysdk/react';
1
+ import { GeomStyleReaders, Observation, ValueFormat } from '@graphysdk/react';
2
2
  import { SankeyNodeObservation } from '../../utils/read-sankey';
3
3
  export interface SankeyLabelsProps {
4
4
  nodes: readonly SankeyNodeObservation[];
5
5
  /** The node names' format. */
6
6
  valueFormat: ValueFormat;
7
7
  styleReaders: GeomStyleReaders;
8
- isHovered?: boolean;
8
+ /** The observation under the pointer: paints in the `hovered` state. */
9
+ hovered?: Observation;
9
10
  }
10
11
  /**
11
12
  * Each node's name beside it, painted through the `label` part's readers. The outline, in the background's color
12
13
  * by default, keeps a name legible where it crosses a flow.
13
14
  */
14
- export declare const SankeyLabels: ({ nodes, valueFormat, styleReaders, isHovered }: SankeyLabelsProps) => import("react/jsx-runtime").JSX.Element;
15
+ export declare const SankeyLabels: ({ nodes, valueFormat, styleReaders, hovered }: SankeyLabelsProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,10 +1,11 @@
1
- import { GeomStyleReaders } from '@graphysdk/react';
1
+ import { GeomStyleReaders, Observation } from '@graphysdk/react';
2
2
  import { SankeyNodeObservation } from '../../utils/read-sankey';
3
3
  export interface SankeyNodesProps {
4
4
  nodes: readonly SankeyNodeObservation[];
5
5
  styleReaders: GeomStyleReaders;
6
- isHovered?: boolean;
6
+ /** The observation under the pointer: paints in the `hovered` state. */
7
+ hovered?: Observation;
7
8
  shouldAnimateTransitions?: boolean;
8
9
  }
9
- /** Each node as its box, painted through the `node` part's readers. */
10
- export declare const SankeyNodes: ({ nodes, styleReaders, isHovered, shouldAnimateTransitions, }: SankeyNodesProps) => import("react/jsx-runtime").JSX.Element;
10
+ /** Each node as its box, painted through the `node` part's readers, under the part's overpaint or else the geom's. */
11
+ export declare const SankeyNodes: ({ nodes, styleReaders, hovered, shouldAnimateTransitions }: SankeyNodesProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,4 @@
1
- import { GeomStyleReaders, SceneLayer } from '@graphysdk/react';
1
+ import { GeomStyleReaders, Observation, SceneLayer } from '@graphysdk/react';
2
2
  import { SankeyObservations } from '../../utils/read-sankey';
3
3
  export interface SankeyPaintProps {
4
4
  observations: SankeyObservations;
@@ -9,8 +9,9 @@ export interface SankeyPaintProps {
9
9
  height: number;
10
10
  };
11
11
  styleReaders: GeomStyleReaders;
12
- isHovered?: boolean;
12
+ /** The observation under the pointer: paints in the `hovered` state. */
13
+ hovered?: Observation;
13
14
  shouldAnimateTransitions?: boolean;
14
15
  }
15
- /** The flows, the nodes over their ends, and the names over both. */
16
- export declare const SankeyPaint: ({ observations, layer, size, styleReaders, isHovered, shouldAnimateTransitions, }: SankeyPaintProps) => import("react/jsx-runtime").JSX.Element;
16
+ /** The flows, the nodes over their ends, and the names over both; the overpaint covers the flows and the nodes. */
17
+ export declare const SankeyPaint: ({ observations, layer, size, styleReaders, hovered, shouldAnimateTransitions, }: SankeyPaintProps) => import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "flow",
15
15
  "alluvial"
16
16
  ],
17
- "version": "0.1.0",
17
+ "version": "0.1.1-beta.1792404455940",
18
18
  "type": "module",
19
19
  "sideEffects": false,
20
20
  "types": "./dist/index.d.ts",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": "^19.0.0",
39
- "@graphysdk/react": "^1.9.0-beta.1791969243405"
39
+ "@graphysdk/react": "^1.9.0-beta.1792404455940"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@testing-library/react": "^16.3.1",
@@ -49,11 +49,11 @@
49
49
  "vite": "^8.1.5",
50
50
  "vite-plugin-dts": "^4.5.4",
51
51
  "vitest": "^4.1.11",
52
- "@graphysdk/viz-engine": "1.8.0",
53
- "@graphysdk/react": "1.9.0-beta.1791969243405",
54
- "@graphytools/eslint-config": "0.0.1",
52
+ "@graphysdk/react": "1.9.0-beta.1792404455940",
53
+ "@graphysdk/viz-engine": "1.9.0-beta.1792404455940",
55
54
  "@graphytools/typescript-config": "0.0.1",
56
- "@graphytools/vitest-config": "1.0.0"
55
+ "@graphytools/vitest-config": "1.0.0",
56
+ "@graphytools/eslint-config": "0.0.1"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public"