mirror of
https://github.com/apotdevin/thunderhub.git
synced 2025-02-22 14:22:33 +01:00
chore: 🔧 add chord graph
This commit is contained in:
parent
a183cc5ab9
commit
97ba42beb9
6 changed files with 466 additions and 16 deletions
170
package-lock.json
generated
170
package-lock.json
generated
|
@ -8044,6 +8044,11 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/classnames": {
|
||||
"version": "2.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz",
|
||||
"integrity": "sha512-2koNhpWm3DgWRp5tpkiJ8JGc1xTn2q0l+jUNUE7oMKXUf5NpI9AIdC4kbjGNFBdHtcxBD18LAksoudAVhFKCjw=="
|
||||
},
|
||||
"@types/color-name": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
|
@ -8094,6 +8099,50 @@
|
|||
"integrity": "sha512-6+OPzqhKX/cx5xh+yO8Cqg3u3alrkhoxhE5ZOdSEv0DOzJ13lwJ6laqGU0Kv6+XDMFmlnGId04LtY22PsFLQUw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-chord": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.10.tgz",
|
||||
"integrity": "sha512-U6YojfET6ITL1/bUJo+/Lh3pMV9XPAfOWwbshl3y3RlgAX9VO/Bxa13IMAylZIDY4VsA3Gkh29kZP1AcAeyoYA=="
|
||||
},
|
||||
"@types/d3-color": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.1.tgz",
|
||||
"integrity": "sha512-xkPLi+gbgUU9ED6QX4g6jqYL2KCB0/3AlM+ncMGqn49OgH0gFMY/ITGqPF8HwEiLzJaC+2L0I+gNwBgABv1Pvg=="
|
||||
},
|
||||
"@types/d3-interpolate": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz",
|
||||
"integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==",
|
||||
"requires": {
|
||||
"@types/d3-color": "^1"
|
||||
}
|
||||
},
|
||||
"@types/d3-path": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ=="
|
||||
},
|
||||
"@types/d3-scale": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.2.1.tgz",
|
||||
"integrity": "sha512-j+FryQSVk3GHLqjOX/RsHwGHg4XByJ0xIO1ASBTgzhE9o1tgeV4kEWLOzMzJRembKalflk5F03lEkM+4V6LDrQ==",
|
||||
"requires": {
|
||||
"@types/d3-time": "*"
|
||||
}
|
||||
},
|
||||
"@types/d3-shape": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.5.tgz",
|
||||
"integrity": "sha512-aPEax03owTAKynoK8ZkmkZEDZvvT4Y5pWgii4Jp4oQt0gH45j6siDl9gNDVC5kl64XHN2goN9jbYoHK88tFAcA==",
|
||||
"requires": {
|
||||
"@types/d3-path": "^1"
|
||||
}
|
||||
},
|
||||
"@types/d3-time": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.1.1.tgz",
|
||||
"integrity": "sha512-ULX7LoqXTCYtM+tLYOaeAJK7IwCT+4Gxlm2MaH0ErKLi07R5lh8NHCAyWcDkCCmx1AfRcBEV6H9QE9R25uP7jw=="
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.6.tgz",
|
||||
|
@ -8288,8 +8337,7 @@
|
|||
"@types/lodash": {
|
||||
"version": "4.14.157",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.157.tgz",
|
||||
"integrity": "sha512-Ft5BNFmv2pHDgxV5JDsndOWTRJ+56zte0ZpYLowp03tW+K+t8u8YMOzAnpuqPgzX6WO1XpDIUm7u04M8vdDiVQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Ft5BNFmv2pHDgxV5JDsndOWTRJ+56zte0ZpYLowp03tW+K+t8u8YMOzAnpuqPgzX6WO1XpDIUm7u04M8vdDiVQ=="
|
||||
},
|
||||
"@types/lodash.groupby": {
|
||||
"version": "4.6.6",
|
||||
|
@ -8383,8 +8431,7 @@
|
|||
"@types/prop-types": {
|
||||
"version": "15.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
|
||||
},
|
||||
"@types/qrcode.react": {
|
||||
"version": "1.0.1",
|
||||
|
@ -8409,7 +8456,6 @@
|
|||
"version": "16.9.56",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.56.tgz",
|
||||
"integrity": "sha512-gIkl4J44G/qxbuC6r2Xh+D3CGZpJ+NdWTItAPmZbR5mUS+JQ8Zvzpl0ea5qT/ZT3ZNTUcDKUVqV3xBE8wv/DyQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
|
@ -8418,8 +8464,7 @@
|
|||
"csstype": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.4.tgz",
|
||||
"integrity": "sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8893,6 +8938,103 @@
|
|||
"eslint-visitor-keys": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@visx/chord": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/chord/-/chord-1.0.0.tgz",
|
||||
"integrity": "sha512-S2+LDiGUHqgDqmuNHERThFRvzA3uGp2Ne0Jxi/V7sncKxuW4bFNeyK21fh9xGMLVaI7Vv52ZSLi+BVcd71HUDA==",
|
||||
"requires": {
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/d3-chord": "^1.0.9",
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.2.6",
|
||||
"d3-chord": "^1.0.4",
|
||||
"prop-types": "^15.6.1"
|
||||
}
|
||||
},
|
||||
"@visx/curve": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/curve/-/curve-1.0.0.tgz",
|
||||
"integrity": "sha512-rN9TUf4uRmPuQ5Rd4kbvinSDsTbR61YB26+ucK6RNMHIr9aLmujpcPJhVwk22EWphRRGIxzK2OSp0d5dgpNppQ==",
|
||||
"requires": {
|
||||
"@types/d3-shape": "^1.3.1",
|
||||
"d3-shape": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"@visx/group": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/group/-/group-1.0.0.tgz",
|
||||
"integrity": "sha512-2YlhGHTINUl7do046p/bkIYiD4xDv/sJ4JAaGrqFXwX68EJZ5Er/0gpZZ4nrADQlxB8/uyJvZzp1Q54ySfTMiA==",
|
||||
"requires": {
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.2.5",
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"@visx/responsive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-1.1.0.tgz",
|
||||
"integrity": "sha512-rKdhm9FDwN2PYWNXQ3X9JA+BOUb39bk8y2wYCW7/IzQtLUajzQeIHfYNGBfBZyeEj0J7b4l18ljTy3P//CFBmA==",
|
||||
"requires": {
|
||||
"@types/lodash": "^4.14.146",
|
||||
"@types/react": "*",
|
||||
"lodash": "^4.17.10",
|
||||
"prop-types": "^15.6.1",
|
||||
"resize-observer-polyfill": "1.5.1"
|
||||
}
|
||||
},
|
||||
"@visx/scale": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/scale/-/scale-1.1.0.tgz",
|
||||
"integrity": "sha512-6m11vrqDD5zPhJdS2KW8fEtdpne3zgJ2YVqnM9naibaUsdA7oLXh54zUlKEd+mzYWLRYuwA+urFPWBSA7kiEaw==",
|
||||
"requires": {
|
||||
"@types/d3-interpolate": "^1.3.1",
|
||||
"@types/d3-scale": "^3.1.0",
|
||||
"@types/d3-time": "^1.0.10",
|
||||
"d3-interpolate": "^1.4.0",
|
||||
"d3-scale": "^3.0.1",
|
||||
"d3-time": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3-array": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.8.0.tgz",
|
||||
"integrity": "sha512-6V272gsOeg7+9pTW1jSYOR1QE37g95I3my1hBmY+vOUNHRrk9yt4OTz/gK7PMkVAVDrYYq4mq3grTiZ8iJdNIw=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz",
|
||||
"integrity": "sha512-8E37oWEmEzj57bHcnjPVOBS3n4jqakOeuv1EDdQSiSrYnMCBdMd3nc4HtKk7uia8DUHcY/CGuJ42xxgtEYrX0g==",
|
||||
"requires": {
|
||||
"d3-array": "^2.3.0",
|
||||
"d3-format": "1 - 2",
|
||||
"d3-interpolate": "1.2.0 - 2",
|
||||
"d3-time": "1 - 2",
|
||||
"d3-time-format": "2 - 3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@visx/shape": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/shape/-/shape-1.1.0.tgz",
|
||||
"integrity": "sha512-3tf+m0R2fAecz+eGgG4NMIl+LVEKm51CrM+AxSJEOrRiTe4syERgRXxOGa04BHDo75S66coBN+416L38GHri4g==",
|
||||
"requires": {
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/d3-path": "^1.0.8",
|
||||
"@types/d3-shape": "^1.3.1",
|
||||
"@types/lodash": "^4.14.146",
|
||||
"@types/react": "*",
|
||||
"@visx/curve": "1.0.0",
|
||||
"@visx/group": "1.0.0",
|
||||
"@visx/scale": "1.1.0",
|
||||
"classnames": "^2.2.5",
|
||||
"d3-path": "^1.0.5",
|
||||
"d3-shape": "^1.2.0",
|
||||
"lodash": "^4.17.15",
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
|
||||
|
@ -13868,6 +14010,15 @@
|
|||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
|
||||
"integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
|
||||
},
|
||||
"d3-chord": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz",
|
||||
"integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"d3-collection": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
|
||||
|
@ -25613,6 +25764,11 @@
|
|||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||
},
|
||||
"resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
||||
|
|
|
@ -35,6 +35,11 @@
|
|||
"dependencies": {
|
||||
"@apollo/client": "^3.2.5",
|
||||
"@next/bundle-analyzer": "^10.0.1",
|
||||
"@visx/chord": "^1.0.0",
|
||||
"@visx/group": "^1.0.0",
|
||||
"@visx/responsive": "^1.1.0",
|
||||
"@visx/scale": "^1.1.0",
|
||||
"@visx/shape": "^1.1.0",
|
||||
"apollo-server-micro": "^2.19.0",
|
||||
"balanceofsatoshis": "^7.3.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
|
|
|
@ -19,6 +19,7 @@ import { ForwardChannelsReport } from 'src/views/home/reports/forwardReport/Forw
|
|||
import { useState } from 'react';
|
||||
import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
|
||||
import { BarChart2, List } from 'react-feather';
|
||||
import { ForwardChord } from 'src/views/forwards/forwardChord';
|
||||
import {
|
||||
SubTitle,
|
||||
Card,
|
||||
|
@ -26,6 +27,7 @@ import {
|
|||
CardTitle,
|
||||
Separation,
|
||||
SingleLine,
|
||||
ResponsiveLine,
|
||||
} from '../src/components/generic/Styled';
|
||||
|
||||
const ForwardsView = () => {
|
||||
|
@ -69,7 +71,7 @@ const ForwardsView = () => {
|
|||
</ColorButton>
|
||||
</SingleLine>
|
||||
</CardTitle>
|
||||
<SingleLine>
|
||||
<ResponsiveLine>
|
||||
<MultiButton margin={'8px 0'}>
|
||||
{renderButton(1, 'D')}
|
||||
{renderButton(7, '1W')}
|
||||
|
@ -85,19 +87,25 @@ const ForwardsView = () => {
|
|||
{renderTypeButton('fee', 'Fees')}
|
||||
</MultiButton>
|
||||
)}
|
||||
</SingleLine>
|
||||
</ResponsiveLine>
|
||||
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{isTable ? (
|
||||
{isTable ? (
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
<ForwardsList days={days} />
|
||||
) : (
|
||||
<>
|
||||
</Card>
|
||||
) : (
|
||||
<>
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
<ForwardReport days={days} order={infoType} />
|
||||
<Separation />
|
||||
<ForwardChannelsReport days={days} order={infoType} />
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</Card>
|
||||
<SubTitle>Chord Graph</SubTitle>
|
||||
<Card>
|
||||
<ForwardChord days={days} order={infoType} />
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
</CardWithTitle>
|
||||
</>
|
||||
);
|
||||
|
|
108
src/components/chord/index.tsx
Normal file
108
src/components/chord/index.tsx
Normal file
|
@ -0,0 +1,108 @@
|
|||
import React from 'react';
|
||||
import { Arc } from '@visx/shape';
|
||||
import { Group } from '@visx/group';
|
||||
import { Chord, Ribbon } from '@visx/chord';
|
||||
import { scaleOrdinal } from '@visx/scale';
|
||||
|
||||
const pink = '#ff2fab';
|
||||
const orange = '#ffc62e';
|
||||
const purple = '#dc04ff';
|
||||
const purple2 = '#7324ff';
|
||||
const red = '#d04376';
|
||||
const green = '#52f091';
|
||||
const blue = '#04a6ff';
|
||||
const lime = '#00ddc6';
|
||||
|
||||
function descending(a: number, b: number): number {
|
||||
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
|
||||
}
|
||||
|
||||
export type SingleGroupProps = {
|
||||
endAngle: number;
|
||||
index: number;
|
||||
startAngle: number;
|
||||
value: number;
|
||||
};
|
||||
|
||||
export type SingleChordProps = {
|
||||
source: SingleGroupProps;
|
||||
target: SingleGroupProps;
|
||||
};
|
||||
|
||||
const groupColor = scaleOrdinal<number, string>({
|
||||
domain: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||
range: [pink, orange, purple, purple2, red, green, blue, lime],
|
||||
});
|
||||
|
||||
export type ChordProps = {
|
||||
matrix: number[][];
|
||||
width: number;
|
||||
height: number;
|
||||
centerSize?: number;
|
||||
groupCallback?: (group: SingleGroupProps) => void;
|
||||
chordCallback?: (chord: SingleChordProps) => void;
|
||||
};
|
||||
|
||||
export const ChordGraph = ({
|
||||
matrix,
|
||||
width,
|
||||
height,
|
||||
centerSize = 20,
|
||||
groupCallback,
|
||||
chordCallback,
|
||||
}: ChordProps) => {
|
||||
const outerRadius = Math.min(width, height) * 0.5 - (centerSize + 10);
|
||||
const innerRadius = outerRadius - centerSize;
|
||||
|
||||
return width < 10 ? null : (
|
||||
<div className="chords">
|
||||
<svg width={width} height={height}>
|
||||
<Group top={height / 2} left={width / 2}>
|
||||
<Chord matrix={matrix} padAngle={0.05} sortSubgroups={descending}>
|
||||
{({ chords }) => (
|
||||
<g>
|
||||
{chords.groups.map((group, i) => (
|
||||
<Arc
|
||||
key={`key-${i}`}
|
||||
data={group}
|
||||
innerRadius={innerRadius}
|
||||
outerRadius={outerRadius}
|
||||
fill={groupColor(i)}
|
||||
onClick={() => {
|
||||
groupCallback && groupCallback(group);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{chords.map((chord, i) => {
|
||||
return (
|
||||
<Ribbon
|
||||
key={`ribbon-${i}`}
|
||||
chord={chord}
|
||||
radius={innerRadius}
|
||||
fill={groupColor(chord.source.index)}
|
||||
fillOpacity={0.75}
|
||||
onClick={() => {
|
||||
chordCallback && chordCallback(chord);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
)}
|
||||
</Chord>
|
||||
</Group>
|
||||
</svg>
|
||||
<style jsx>{`
|
||||
.chords {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
user-select: none;
|
||||
}
|
||||
svg {
|
||||
margin: 1rem 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
128
src/views/forwards/forwardChord.tsx
Normal file
128
src/views/forwards/forwardChord.tsx
Normal file
|
@ -0,0 +1,128 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { useGetForwardsPastDaysQuery } from 'src/graphql/queries/__generated__/getForwardsPastDays.generated';
|
||||
import { toast } from 'react-toastify';
|
||||
import { getErrorContent } from 'src/utils/error';
|
||||
import { Forward } from 'src/graphql/types';
|
||||
import { ParentSize } from '@visx/responsive';
|
||||
import {
|
||||
ChordGraph,
|
||||
SingleGroupProps,
|
||||
SingleChordProps,
|
||||
} from 'src/components/chord';
|
||||
import styled from 'styled-components';
|
||||
import { renderLine } from 'src/components/generic/helpers';
|
||||
import { DarkSubTitle } from 'src/components/generic/Styled';
|
||||
import { ReportType } from '../home/reports/forwardReport/ForwardReport';
|
||||
import { getChordMatrix } from './helpers';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 800px;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const Center = styled.div`
|
||||
width: '100%';
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
type SelectedProps =
|
||||
| { type: 'group'; group: SingleGroupProps }
|
||||
| { type: 'chord'; chord: SingleChordProps }
|
||||
| null;
|
||||
|
||||
const getTitle = (order: ReportType) => {
|
||||
switch (order) {
|
||||
case 'fee':
|
||||
return 'Total Fees (sats)';
|
||||
case 'tokens':
|
||||
return 'Total Tokens (sats)';
|
||||
default:
|
||||
return 'Total Amount (Forwards)';
|
||||
}
|
||||
};
|
||||
|
||||
export const ForwardChord = ({
|
||||
days,
|
||||
order,
|
||||
}: {
|
||||
days: number;
|
||||
order: ReportType;
|
||||
}) => {
|
||||
const [selected, setSelected] = useState<SelectedProps>();
|
||||
|
||||
useEffect(() => {
|
||||
setSelected(null);
|
||||
}, [order]);
|
||||
|
||||
const { data, loading } = useGetForwardsPastDaysQuery({
|
||||
ssr: false,
|
||||
variables: { days },
|
||||
onError: error => toast.error(getErrorContent(error)),
|
||||
});
|
||||
|
||||
if (loading || !data?.getForwardsPastDays?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { matrix, uniqueNodes } = getChordMatrix(
|
||||
order,
|
||||
data.getForwardsPastDays as Forward[]
|
||||
);
|
||||
|
||||
const handleGroupClick = (group: SingleGroupProps) => {
|
||||
setSelected({ type: 'group', group });
|
||||
};
|
||||
const handleChordClick = (chord: SingleChordProps) => {
|
||||
setSelected({ type: 'chord', chord });
|
||||
};
|
||||
|
||||
const renderInfo = () => {
|
||||
if (!selected) {
|
||||
return (
|
||||
<Center>
|
||||
<DarkSubTitle>Click the graph for specific info!</DarkSubTitle>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
if (selected.type === 'group') {
|
||||
return (
|
||||
<>
|
||||
{renderLine('Node', uniqueNodes[selected.group.index])}
|
||||
{renderLine(getTitle(order), selected.group.value)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (selected.type === 'chord') {
|
||||
return (
|
||||
<>
|
||||
{renderLine(
|
||||
'Flow between',
|
||||
`${uniqueNodes[selected.chord.source.index]} - ${
|
||||
uniqueNodes[selected.chord.target.index]
|
||||
}`
|
||||
)}
|
||||
{renderLine(getTitle(order), selected.chord.source.value)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderInfo()}
|
||||
<Wrapper>
|
||||
<ParentSize>
|
||||
{parent => (
|
||||
<ChordGraph
|
||||
matrix={matrix}
|
||||
width={parent.width}
|
||||
height={parent.height}
|
||||
groupCallback={handleGroupClick}
|
||||
chordCallback={handleChordClick}
|
||||
/>
|
||||
)}
|
||||
</ParentSize>
|
||||
</Wrapper>
|
||||
</>
|
||||
);
|
||||
};
|
45
src/views/forwards/helpers.tsx
Normal file
45
src/views/forwards/helpers.tsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { Forward } from 'src/graphql/types';
|
||||
import { ReportType } from '../home/reports/forwardReport/ForwardReport';
|
||||
|
||||
export const getChordMatrix = (order: ReportType, forwardArray: Forward[]) => {
|
||||
const cleaned = forwardArray.map(f => {
|
||||
let value = 1;
|
||||
|
||||
if (order === 'fee') {
|
||||
value = f.fee;
|
||||
} else if (order === 'tokens') {
|
||||
value = f.tokens;
|
||||
}
|
||||
|
||||
return {
|
||||
aliasIn: f.incoming_node?.alias || 'Unknown',
|
||||
aliasOut: f.outgoing_node?.alias || 'Unknown',
|
||||
value,
|
||||
};
|
||||
});
|
||||
|
||||
const incomingNodes = cleaned.map(f => f.aliasIn);
|
||||
const outgoingNodes = cleaned.map(f => f.aliasOut);
|
||||
|
||||
const uniqueNodes = [...new Set(incomingNodes), ...new Set(outgoingNodes)];
|
||||
const nodeLength = uniqueNodes.length;
|
||||
|
||||
const matrix = new Array(nodeLength);
|
||||
|
||||
for (let i = 0; i < matrix.length; i++) {
|
||||
matrix[i] = new Array(nodeLength).fill(0);
|
||||
}
|
||||
|
||||
cleaned.forEach(f => {
|
||||
const inIndex = uniqueNodes.indexOf(f.aliasIn);
|
||||
const outIndex = uniqueNodes.indexOf(f.aliasOut);
|
||||
|
||||
const previousValue = matrix[inIndex][outIndex];
|
||||
const previousOutValue = matrix[outIndex][inIndex];
|
||||
|
||||
matrix[inIndex][outIndex] = previousValue + f.value;
|
||||
matrix[outIndex][inIndex] = previousOutValue + f.value;
|
||||
});
|
||||
|
||||
return { uniqueNodes, matrix };
|
||||
};
|
Loading…
Add table
Reference in a new issue