mirror of
https://github.com/apotdevin/thunderhub.git
synced 2024-11-19 01:40:03 +01:00
Echarts implementation (#536)
* feat: implement the payments graph with echarts * fix: improve echarts import in next.config.js * fix: formatting * fix: no-implicity-any * fix: tidy up inconsistencies in echarts implementation * feat: improve a number of aspects about echarts implementation as per suggestions * feat: move forwards chart to echarts * chore: move invoice, payment, forward graphs to new BarChart. move liquidityGraph to new HorizontalBarChart * chore: remove V2 from new graphs * feat: implement Sankey chart for forwards * chore: change justification on Sankey Graph * feat: add Sankey graph * chore: remove chord graph * chore: remove chord graph and update package.json * chore: remove stray console log * chore: format numbers on y axis to be integer values * feat: tidy echarts implementation * feat: revamp tooltip * feat: bound the size of the sankey chart * feat: provide function that creates a mock sankey dataset of arbitrary size * fix: missing memo dependencies and css * chore: small changes --------- Co-authored-by: Anthony Potdevin <potdevin.anthony@gmail.com> Co-authored-by: Anthony Potdevin <31413433+apotdevin@users.noreply.github.com> Co-authored-by: secondl1ght <secondl1ght@protonmail.com>
This commit is contained in:
parent
e62f5bf6ea
commit
0f893bddad
768
package-lock.json
generated
768
package-lock.json
generated
@ -24,14 +24,6 @@
|
||||
"@nestjs/throttler": "^4.0.0",
|
||||
"@nestjs/websockets": "^9.4.2",
|
||||
"@tanstack/react-table": "^8.9.1",
|
||||
"@visx/axis": "^2.12.2",
|
||||
"@visx/chord": "^2.10.0",
|
||||
"@visx/event": "^2.6.0",
|
||||
"@visx/group": "^2.10.0",
|
||||
"@visx/responsive": "^2.10.0",
|
||||
"@visx/scale": "^2.2.2",
|
||||
"@visx/shape": "^2.12.2",
|
||||
"@visx/tooltip": "^2.16.0",
|
||||
"apollo-server-express": "^3.12.0",
|
||||
"balanceofsatoshis": "^15.8.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
@ -48,6 +40,8 @@
|
||||
"d3-time-format": "^4.1.0",
|
||||
"date-fns": "^2.30.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"echarts": "^5.4.2",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"ecpair": "^2.0.1",
|
||||
"graphql": "^16.6.0",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
@ -5224,11 +5218,6 @@
|
||||
"lodash.get": "^4.4.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@juggle/resize-observer": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
|
||||
"integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw=="
|
||||
},
|
||||
"node_modules/@lukeed/csprng": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz",
|
||||
@ -6552,50 +6541,6 @@
|
||||
"integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/d3-chord": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.11.tgz",
|
||||
"integrity": "sha512-0DdfJ//bxyW3G9Nefwq/LDgazSKNN8NU0lBT3Cza6uVuInC2awMNsAcv1oKyRFLn9z7kXClH5XjwpveZjuz2eg=="
|
||||
},
|
||||
"node_modules/@types/d3-color": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz",
|
||||
"integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA=="
|
||||
},
|
||||
"node_modules/@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==",
|
||||
"dependencies": {
|
||||
"@types/d3-color": "^1"
|
||||
}
|
||||
},
|
||||
"node_modules/@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=="
|
||||
},
|
||||
"node_modules/@types/d3-scale": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz",
|
||||
"integrity": "sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==",
|
||||
"dependencies": {
|
||||
"@types/d3-time": "^2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-shape": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz",
|
||||
"integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==",
|
||||
"dependencies": {
|
||||
"@types/d3-path": "^1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-time": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz",
|
||||
"integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg=="
|
||||
},
|
||||
"node_modules/@types/d3-time-format": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz",
|
||||
@ -6755,7 +6700,8 @@
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.195",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
|
||||
"integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg=="
|
||||
"integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/long": {
|
||||
"version": "4.0.2",
|
||||
@ -6874,14 +6820,6 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "18.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz",
|
||||
"integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-grid-layout": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.3.2.tgz",
|
||||
@ -7244,171 +7182,6 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/axis": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/axis/-/axis-2.14.0.tgz",
|
||||
"integrity": "sha512-/mJuPiAUN/YdatSlXkkXD/8Pb4gVclbucNZkpUk6JVhnrmow0a1x73QiMXKuH2qDO5GDaqQS0C3Ly9lI3qTQ5Q==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/point": "2.6.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"@visx/shape": "2.12.2",
|
||||
"@visx/text": "2.12.2",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/bounds": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/bounds/-/bounds-2.16.0.tgz",
|
||||
"integrity": "sha512-KJoSSJt5SOLzprEbmsmdxR46PLudau0kWOgxavrah9D/49RsHwGdUdxHLKdXz4OdCruEfgGo4yxiuYLYmUWl4A==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"prop-types": "^15.5.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0",
|
||||
"react-dom": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/chord": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/chord/-/chord-2.10.0.tgz",
|
||||
"integrity": "sha512-p2ZQ9uiyiXV4Yu9DL+cqKbZbh1umMgCUWTP2CpgwSN5p822QHQjzpe1nafWOmNSLpANIBDDYIbtIgOZXUHkelA==",
|
||||
"dependencies": {
|
||||
"@types/d3-chord": "^1.0.9",
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.3.1",
|
||||
"d3-chord": "^1.0.4",
|
||||
"prop-types": "^15.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/curve": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/curve/-/curve-2.1.0.tgz",
|
||||
"integrity": "sha512-9b6JOnx91gmOQiSPhUOxdsvcnW88fgqfTPKoVgQxidMsD/I3wksixtwo8TR/vtEz2aHzzsEEhlv1qK7Y3yaSDw==",
|
||||
"dependencies": {
|
||||
"@types/d3-shape": "^1.3.1",
|
||||
"d3-shape": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/event": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/event/-/event-2.6.0.tgz",
|
||||
"integrity": "sha512-WGp91g82s727g3NAnENF1ppC3ZAlvWg+Y+GG0WFg34NmmOZbvPI/PTOqTqZE3x6B8EUn8NJiMxRjxIMbi+IvRw==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"@visx/point": "2.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/group": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/group/-/group-2.10.0.tgz",
|
||||
"integrity": "sha512-DNJDX71f65Et1+UgQvYlZbE66owYUAfcxTkC96Db6TnxV221VKI3T5l23UWbnMzwFBP9dR3PWUjjqhhF12N5pA==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/point": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/point/-/point-2.6.0.tgz",
|
||||
"integrity": "sha512-amBi7yMz4S2VSchlPdliznN41TuES64506ySI22DeKQ+mc1s1+BudlpnY90sM1EIw4xnqbKmrghTTGfy6SVqvQ=="
|
||||
},
|
||||
"node_modules/@visx/responsive": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-2.10.0.tgz",
|
||||
"integrity": "sha512-NssDPpuUYp7hqVISuYkKZ5zk6ob0++RdTIaUjRcUdyFEbvzb9+zIb8QToOkvI90L2EC/MY4Jx0NpDbEe79GpAw==",
|
||||
"dependencies": {
|
||||
"@juggle/resize-observer": "^3.3.1",
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@types/react": "*",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/scale": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/scale/-/scale-2.2.2.tgz",
|
||||
"integrity": "sha512-3aDySGUTpe6VykDQmF+g2nz5paFu9iSPTcCOEgkcru0/v5tmGzUdvivy8CkYbr87HN73V/Jc53lGm+kJUQcLBw==",
|
||||
"dependencies": {
|
||||
"@types/d3-interpolate": "^1.3.1",
|
||||
"@types/d3-scale": "^3.3.0",
|
||||
"@types/d3-time": "^2.0.0",
|
||||
"d3-interpolate": "^1.4.0",
|
||||
"d3-scale": "^3.3.0",
|
||||
"d3-time": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/shape": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/shape/-/shape-2.12.2.tgz",
|
||||
"integrity": "sha512-4gN0fyHWYXiJ+Ck8VAazXX0i8TOnLJvOc5jZBnaJDVxgnSIfCjJn0+Nsy96l9Dy/bCMTh4DBYUBv9k+YICBUOA==",
|
||||
"dependencies": {
|
||||
"@types/d3-path": "^1.0.8",
|
||||
"@types/d3-shape": "^1.3.1",
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@types/react": "*",
|
||||
"@visx/curve": "2.1.0",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"d3-path": "^1.0.5",
|
||||
"d3-shape": "^1.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.5.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/text": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/text/-/text-2.12.2.tgz",
|
||||
"integrity": "sha512-Sv9YEolggfv2Nf6+l28ESG3VXVR1+s4u/Cz17QpgOxygcbOM8LfLtriWtBsBMKdMbYKeUpoUro0clx55TUwzew==",
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.3.1",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.7.2",
|
||||
"reduce-css-calc": "^1.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@visx/tooltip": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/tooltip/-/tooltip-2.16.0.tgz",
|
||||
"integrity": "sha512-kCjVtNGYpYm6AuMc1fT9cIwqpBivfQ8A5Qd7fQMC2xm4YVmehFdbyRr0nVft8zNXyUW3lDxbcq5bPIMRYhuhlA==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"@visx/bounds": "2.16.0",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-use-measure": "^2.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0",
|
||||
"react-dom": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
@ -10255,84 +10028,6 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/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==",
|
||||
"dependencies": {
|
||||
"d3-array": "1",
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-chord/node_modules/d3-array": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
|
||||
"integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
|
||||
},
|
||||
"node_modules/d3-color": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
|
||||
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
|
||||
},
|
||||
"node_modules/d3-format": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
|
||||
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
|
||||
},
|
||||
"node_modules/d3-interpolate": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
|
||||
"integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
|
||||
"dependencies": {
|
||||
"d3-color": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-path": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
|
||||
},
|
||||
"node_modules/d3-scale": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||
"integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
|
||||
"dependencies": {
|
||||
"d3-array": "^2.3.0",
|
||||
"d3-format": "1 - 2",
|
||||
"d3-interpolate": "1.2.0 - 2",
|
||||
"d3-time": "^2.1.1",
|
||||
"d3-time-format": "2 - 3"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-scale/node_modules/d3-array": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
|
||||
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
|
||||
"dependencies": {
|
||||
"internmap": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-scale/node_modules/d3-time-format": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
|
||||
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
|
||||
"dependencies": {
|
||||
"d3-time": "1 - 2"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-scale/node_modules/internmap": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||
},
|
||||
"node_modules/d3-shape": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
|
||||
"integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
|
||||
"dependencies": {
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-time": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
|
||||
@ -10421,7 +10116,8 @@
|
||||
"node_modules/debounce": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
|
||||
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="
|
||||
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
@ -10790,6 +10486,33 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/echarts": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.2.tgz",
|
||||
"integrity": "sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==",
|
||||
"dependencies": {
|
||||
"tslib": "2.3.0",
|
||||
"zrender": "5.4.3"
|
||||
}
|
||||
},
|
||||
"node_modules/echarts-for-react": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.2.tgz",
|
||||
"integrity": "sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"size-sensor": "^1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"echarts": "^3.0.0 || ^4.0.0 || ^5.0.0",
|
||||
"react": "^15.0.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/echarts/node_modules/tslib": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||
},
|
||||
"node_modules/ecpair": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz",
|
||||
@ -16852,11 +16575,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/math-expression-evaluator": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz",
|
||||
"integrity": "sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw=="
|
||||
},
|
||||
"node_modules/md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
@ -19215,18 +18933,6 @@
|
||||
"react-dom": ">=16.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-use-measure": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz",
|
||||
"integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==",
|
||||
"dependencies": {
|
||||
"debounce": "^1.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.13",
|
||||
"react-dom": ">=16.13"
|
||||
}
|
||||
},
|
||||
"node_modules/read-pkg": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
@ -19360,29 +19066,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/reduce-css-calc": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
|
||||
"integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^0.4.2",
|
||||
"math-expression-evaluator": "^1.2.14",
|
||||
"reduce-function-call": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/reduce-css-calc/node_modules/balanced-match": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
|
||||
"integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg=="
|
||||
},
|
||||
"node_modules/reduce-function-call": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz",
|
||||
"integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect-metadata": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||
@ -20001,6 +19684,11 @@
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/size-sensor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.1.tgz",
|
||||
"integrity": "sha512-QTy7MnuugCFXIedXRpUSk9gUnyNiaxIdxGfUjr8xxXOqIB3QvBUYP9+b51oCg2C4dnhaeNk/h57TxjbvoJrJUA=="
|
||||
},
|
||||
"node_modules/sjcl": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz",
|
||||
@ -22612,6 +22300,19 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/zrender": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.3.tgz",
|
||||
"integrity": "sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==",
|
||||
"dependencies": {
|
||||
"tslib": "2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zrender/node_modules/tslib": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -26464,11 +26165,6 @@
|
||||
"lodash.get": "^4.4.2"
|
||||
}
|
||||
},
|
||||
"@juggle/resize-observer": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
|
||||
"integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw=="
|
||||
},
|
||||
"@lukeed/csprng": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz",
|
||||
@ -27417,50 +27113,6 @@
|
||||
"integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/d3-chord": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.11.tgz",
|
||||
"integrity": "sha512-0DdfJ//bxyW3G9Nefwq/LDgazSKNN8NU0lBT3Cza6uVuInC2awMNsAcv1oKyRFLn9z7kXClH5XjwpveZjuz2eg=="
|
||||
},
|
||||
"@types/d3-color": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz",
|
||||
"integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA=="
|
||||
},
|
||||
"@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.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz",
|
||||
"integrity": "sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==",
|
||||
"requires": {
|
||||
"@types/d3-time": "^2"
|
||||
}
|
||||
},
|
||||
"@types/d3-shape": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz",
|
||||
"integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==",
|
||||
"requires": {
|
||||
"@types/d3-path": "^1"
|
||||
}
|
||||
},
|
||||
"@types/d3-time": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz",
|
||||
"integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg=="
|
||||
},
|
||||
"@types/d3-time-format": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz",
|
||||
@ -27622,7 +27274,8 @@
|
||||
"@types/lodash": {
|
||||
"version": "4.14.195",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
|
||||
"integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg=="
|
||||
"integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/long": {
|
||||
"version": "4.0.2",
|
||||
@ -27740,14 +27393,6 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "18.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz",
|
||||
"integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==",
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-grid-layout": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.3.2.tgz",
|
||||
@ -28021,145 +27666,6 @@
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@visx/axis": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/axis/-/axis-2.14.0.tgz",
|
||||
"integrity": "sha512-/mJuPiAUN/YdatSlXkkXD/8Pb4gVclbucNZkpUk6JVhnrmow0a1x73QiMXKuH2qDO5GDaqQS0C3Ly9lI3qTQ5Q==",
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/point": "2.6.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"@visx/shape": "2.12.2",
|
||||
"@visx/text": "2.12.2",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"@visx/bounds": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/bounds/-/bounds-2.16.0.tgz",
|
||||
"integrity": "sha512-KJoSSJt5SOLzprEbmsmdxR46PLudau0kWOgxavrah9D/49RsHwGdUdxHLKdXz4OdCruEfgGo4yxiuYLYmUWl4A==",
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"@visx/chord": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/chord/-/chord-2.10.0.tgz",
|
||||
"integrity": "sha512-p2ZQ9uiyiXV4Yu9DL+cqKbZbh1umMgCUWTP2CpgwSN5p822QHQjzpe1nafWOmNSLpANIBDDYIbtIgOZXUHkelA==",
|
||||
"requires": {
|
||||
"@types/d3-chord": "^1.0.9",
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.3.1",
|
||||
"d3-chord": "^1.0.4",
|
||||
"prop-types": "^15.6.1"
|
||||
}
|
||||
},
|
||||
"@visx/curve": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/curve/-/curve-2.1.0.tgz",
|
||||
"integrity": "sha512-9b6JOnx91gmOQiSPhUOxdsvcnW88fgqfTPKoVgQxidMsD/I3wksixtwo8TR/vtEz2aHzzsEEhlv1qK7Y3yaSDw==",
|
||||
"requires": {
|
||||
"@types/d3-shape": "^1.3.1",
|
||||
"d3-shape": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"@visx/event": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/event/-/event-2.6.0.tgz",
|
||||
"integrity": "sha512-WGp91g82s727g3NAnENF1ppC3ZAlvWg+Y+GG0WFg34NmmOZbvPI/PTOqTqZE3x6B8EUn8NJiMxRjxIMbi+IvRw==",
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"@visx/point": "2.6.0"
|
||||
}
|
||||
},
|
||||
"@visx/group": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/group/-/group-2.10.0.tgz",
|
||||
"integrity": "sha512-DNJDX71f65Et1+UgQvYlZbE66owYUAfcxTkC96Db6TnxV221VKI3T5l23UWbnMzwFBP9dR3PWUjjqhhF12N5pA==",
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"@visx/point": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/point/-/point-2.6.0.tgz",
|
||||
"integrity": "sha512-amBi7yMz4S2VSchlPdliznN41TuES64506ySI22DeKQ+mc1s1+BudlpnY90sM1EIw4xnqbKmrghTTGfy6SVqvQ=="
|
||||
},
|
||||
"@visx/responsive": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-2.10.0.tgz",
|
||||
"integrity": "sha512-NssDPpuUYp7hqVISuYkKZ5zk6ob0++RdTIaUjRcUdyFEbvzb9+zIb8QToOkvI90L2EC/MY4Jx0NpDbEe79GpAw==",
|
||||
"requires": {
|
||||
"@juggle/resize-observer": "^3.3.1",
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@types/react": "*",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.6.1"
|
||||
}
|
||||
},
|
||||
"@visx/scale": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/scale/-/scale-2.2.2.tgz",
|
||||
"integrity": "sha512-3aDySGUTpe6VykDQmF+g2nz5paFu9iSPTcCOEgkcru0/v5tmGzUdvivy8CkYbr87HN73V/Jc53lGm+kJUQcLBw==",
|
||||
"requires": {
|
||||
"@types/d3-interpolate": "^1.3.1",
|
||||
"@types/d3-scale": "^3.3.0",
|
||||
"@types/d3-time": "^2.0.0",
|
||||
"d3-interpolate": "^1.4.0",
|
||||
"d3-scale": "^3.3.0",
|
||||
"d3-time": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"@visx/shape": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/shape/-/shape-2.12.2.tgz",
|
||||
"integrity": "sha512-4gN0fyHWYXiJ+Ck8VAazXX0i8TOnLJvOc5jZBnaJDVxgnSIfCjJn0+Nsy96l9Dy/bCMTh4DBYUBv9k+YICBUOA==",
|
||||
"requires": {
|
||||
"@types/d3-path": "^1.0.8",
|
||||
"@types/d3-shape": "^1.3.1",
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@types/react": "*",
|
||||
"@visx/curve": "2.1.0",
|
||||
"@visx/group": "2.10.0",
|
||||
"@visx/scale": "2.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"d3-path": "^1.0.5",
|
||||
"d3-shape": "^1.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"@visx/text": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@visx/text/-/text-2.12.2.tgz",
|
||||
"integrity": "sha512-Sv9YEolggfv2Nf6+l28ESG3VXVR1+s4u/Cz17QpgOxygcbOM8LfLtriWtBsBMKdMbYKeUpoUro0clx55TUwzew==",
|
||||
"requires": {
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@types/react": "*",
|
||||
"classnames": "^2.3.1",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.7.2",
|
||||
"reduce-css-calc": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"@visx/tooltip": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@visx/tooltip/-/tooltip-2.16.0.tgz",
|
||||
"integrity": "sha512-kCjVtNGYpYm6AuMc1fT9cIwqpBivfQ8A5Qd7fQMC2xm4YVmehFdbyRr0nVft8zNXyUW3lDxbcq5bPIMRYhuhlA==",
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"@visx/bounds": "2.16.0",
|
||||
"classnames": "^2.3.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-use-measure": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
@ -30438,88 +29944,6 @@
|
||||
"internmap": "1 - 2"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3-array": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
|
||||
"integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"d3-color": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
|
||||
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
|
||||
},
|
||||
"d3-format": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
|
||||
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
|
||||
},
|
||||
"d3-interpolate": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
|
||||
"integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
|
||||
"requires": {
|
||||
"d3-color": "1"
|
||||
}
|
||||
},
|
||||
"d3-path": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||
"integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
|
||||
"requires": {
|
||||
"d3-array": "^2.3.0",
|
||||
"d3-format": "1 - 2",
|
||||
"d3-interpolate": "1.2.0 - 2",
|
||||
"d3-time": "^2.1.1",
|
||||
"d3-time-format": "2 - 3"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3-array": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
|
||||
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
|
||||
"requires": {
|
||||
"internmap": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
|
||||
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
|
||||
"requires": {
|
||||
"d3-time": "1 - 2"
|
||||
}
|
||||
},
|
||||
"internmap": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"d3-shape": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
|
||||
"integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
|
||||
"requires": {
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"d3-time": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
|
||||
@ -30591,7 +30015,8 @@
|
||||
"debounce": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
|
||||
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="
|
||||
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
@ -30868,6 +30293,31 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"echarts": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.2.tgz",
|
||||
"integrity": "sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==",
|
||||
"requires": {
|
||||
"tslib": "2.3.0",
|
||||
"zrender": "5.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"echarts-for-react": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.2.tgz",
|
||||
"integrity": "sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"size-sensor": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"ecpair": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz",
|
||||
@ -35509,11 +34959,6 @@
|
||||
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"math-expression-evaluator": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz",
|
||||
"integrity": "sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw=="
|
||||
},
|
||||
"md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
@ -37260,14 +36705,6 @@
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"react-use-measure": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz",
|
||||
"integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==",
|
||||
"requires": {
|
||||
"debounce": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
@ -37375,31 +36812,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"reduce-css-calc": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
|
||||
"integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==",
|
||||
"requires": {
|
||||
"balanced-match": "^0.4.2",
|
||||
"math-expression-evaluator": "^1.2.14",
|
||||
"reduce-function-call": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"balanced-match": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
|
||||
"integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"reduce-function-call": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz",
|
||||
"integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"reflect-metadata": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||
@ -37874,6 +37286,11 @@
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"dev": true
|
||||
},
|
||||
"size-sensor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.1.tgz",
|
||||
"integrity": "sha512-QTy7MnuugCFXIedXRpUSk9gUnyNiaxIdxGfUjr8xxXOqIB3QvBUYP9+b51oCg2C4dnhaeNk/h57TxjbvoJrJUA=="
|
||||
},
|
||||
"sjcl": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz",
|
||||
@ -39812,6 +39229,21 @@
|
||||
"version": "3.21.4",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
|
||||
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw=="
|
||||
},
|
||||
"zrender": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.3.tgz",
|
||||
"integrity": "sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==",
|
||||
"requires": {
|
||||
"tslib": "2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
package.json
10
package.json
@ -49,14 +49,6 @@
|
||||
"@nestjs/throttler": "^4.0.0",
|
||||
"@nestjs/websockets": "^9.4.2",
|
||||
"@tanstack/react-table": "^8.9.1",
|
||||
"@visx/axis": "^2.12.2",
|
||||
"@visx/chord": "^2.10.0",
|
||||
"@visx/event": "^2.6.0",
|
||||
"@visx/group": "^2.10.0",
|
||||
"@visx/responsive": "^2.10.0",
|
||||
"@visx/scale": "^2.2.2",
|
||||
"@visx/shape": "^2.12.2",
|
||||
"@visx/tooltip": "^2.16.0",
|
||||
"apollo-server-express": "^3.12.0",
|
||||
"balanceofsatoshis": "^15.8.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
@ -73,6 +65,8 @@
|
||||
"d3-time-format": "^4.1.0",
|
||||
"date-fns": "^2.30.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"echarts": "^5.4.2",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"ecpair": "^2.0.1",
|
||||
"graphql": "^16.6.0",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
|
@ -10,6 +10,7 @@ module.exports = {
|
||||
reactStrictMode: true,
|
||||
poweredByHeader: false,
|
||||
basePath: process.env.BASE_PATH || '',
|
||||
transpilePackages: ['echarts', 'zrender'],
|
||||
compiler: {
|
||||
styledComponents: true,
|
||||
},
|
||||
|
@ -4,7 +4,6 @@ import { getProps } from '../src/utils/ssr';
|
||||
import { ForwardsList } from '../src/views/forwards/index';
|
||||
import { ForwardChannelsReport } from '../src/views/home/reports/forwardReport/ForwardChannelReport';
|
||||
import { useState } from 'react';
|
||||
import { ForwardChord } from '../src/views/forwards/forwardChord';
|
||||
import { ForwardTable } from '../src/views/forwards/ForwardTable';
|
||||
import { options, typeOptions } from '../src/views/home/reports/forwardReport';
|
||||
import { ForwardsGraph } from '../src/views/home/reports/forwardReport/ForwardsGraph';
|
||||
@ -18,6 +17,7 @@ import {
|
||||
CardTitle,
|
||||
Separation,
|
||||
} from '../src/components/generic/Styled';
|
||||
import { ForwardSankey } from '../src/views/forwards/forwardSankey';
|
||||
|
||||
const S = {
|
||||
options: styled.div`
|
||||
@ -85,9 +85,12 @@ const ForwardsView = () => {
|
||||
<Card>
|
||||
<ForwardTable days={days.value} order={type.value} />
|
||||
</Card>
|
||||
<SubTitle>Chord Graph</SubTitle>
|
||||
<SubTitle>Sankey</SubTitle>
|
||||
<Card>
|
||||
<ForwardChord days={days.value} order={type.value} />
|
||||
<ForwardSankey
|
||||
days={days.value}
|
||||
type={type.value as 'amount' | 'fee' | 'tokens'}
|
||||
/>
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
|
@ -110,8 +110,6 @@ const TransactionsView = () => {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
console.log(lastInvoice, lastPayment);
|
||||
}, [invoiceQuery.data, paymentQuery.data, show]);
|
||||
|
||||
const renderInvoices = useCallback(() => {
|
||||
|
@ -1,235 +1,132 @@
|
||||
import { Group } from '@visx/group';
|
||||
import { BarGroup } from '@visx/shape';
|
||||
import { AxisBottom, AxisLeft } from '@visx/axis';
|
||||
import { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale';
|
||||
import { timeParse, timeFormat } from 'd3-time-format';
|
||||
import { ParentSize } from '@visx/responsive';
|
||||
import { chartColors } from '../../../src/styles/Themes';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { BarChart as EBarChart } from 'echarts/charts';
|
||||
import {
|
||||
GraphicComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TitleComponent,
|
||||
ToolboxComponent,
|
||||
TooltipComponent,
|
||||
} from 'echarts/components';
|
||||
import * as echarts from 'echarts/core';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import ReactEChartsCore from 'echarts-for-react/lib/core';
|
||||
import { ThemeContext } from 'styled-components';
|
||||
import { useContext } from 'react';
|
||||
import { TooltipWithBounds, defaultStyles, useTooltip } from '@visx/tooltip';
|
||||
import { localPoint } from '@visx/event';
|
||||
import { Price } from '../price/Price';
|
||||
import numeral from 'numeral';
|
||||
import { timeFormat, timeParse } from 'd3-time-format';
|
||||
import { formatSats } from '../../utils/helpers';
|
||||
import { COMMON_CHART_STYLES } from './common';
|
||||
|
||||
type BarGroupProps = {
|
||||
width: number;
|
||||
height: number;
|
||||
} & BarChartProps;
|
||||
echarts.use([
|
||||
EBarChart,
|
||||
CanvasRenderer,
|
||||
GridComponent,
|
||||
TooltipComponent,
|
||||
GraphicComponent,
|
||||
TitleComponent,
|
||||
LegendComponent,
|
||||
ToolboxComponent,
|
||||
]);
|
||||
|
||||
type BarChartProps = {
|
||||
data: any[];
|
||||
margin?: { top: number; right: number; bottom: number; left: number };
|
||||
events?: boolean;
|
||||
colorRange?: string[];
|
||||
priceLabel?: boolean;
|
||||
};
|
||||
|
||||
const defaultMargin = { top: 40, right: 0, bottom: 40, left: 0 };
|
||||
const defaultColorRange = [
|
||||
chartColors.green,
|
||||
chartColors.orange,
|
||||
chartColors.lightblue,
|
||||
];
|
||||
|
||||
const amountOfYTicks = (height: number) => {
|
||||
switch (true) {
|
||||
case height < 300:
|
||||
return 3;
|
||||
case height < 400:
|
||||
return 6;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
|
||||
const amountOfXTicks = (width: number) => {
|
||||
switch (true) {
|
||||
case width < 300:
|
||||
return 2;
|
||||
case width < 400:
|
||||
return 6;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
|
||||
const parseDate = timeParse('%Y-%m-%dT%H:%M:%S.%L%Z');
|
||||
const formatDate = timeFormat('%b %d');
|
||||
const formatTime = timeFormat('%H:%M');
|
||||
const tickFormatDate = (date: string) => formatDate(parseDate(date) as Date);
|
||||
const tickFormatTime = (date: string) => formatTime(parseDate(date) as Date);
|
||||
|
||||
const tooltipStyles = {
|
||||
...defaultStyles,
|
||||
minWidth: 60,
|
||||
backgroundColor: 'rgba(0,0,0,0.9)',
|
||||
color: 'white',
|
||||
};
|
||||
|
||||
const Chart = ({
|
||||
width,
|
||||
height,
|
||||
margin = defaultMargin,
|
||||
data = [],
|
||||
colorRange = defaultColorRange,
|
||||
priceLabel,
|
||||
}: BarGroupProps) => {
|
||||
const {
|
||||
tooltipData,
|
||||
tooltipLeft,
|
||||
tooltipTop,
|
||||
tooltipOpen,
|
||||
showTooltip,
|
||||
hideTooltip,
|
||||
} = useTooltip<any>();
|
||||
interface BarChartProps {
|
||||
colorRange: string[];
|
||||
data: any;
|
||||
title: string;
|
||||
dataKey: string;
|
||||
}
|
||||
|
||||
export const BarChart = ({
|
||||
data,
|
||||
colorRange,
|
||||
title,
|
||||
dataKey,
|
||||
}: BarChartProps) => {
|
||||
const themeContext = useContext(ThemeContext);
|
||||
|
||||
const axisColor = themeContext.mode === 'light' ? 'black' : 'white';
|
||||
const seriesData = useMemo(() => {
|
||||
if (data.length === 0) return { dates: [], series: [] };
|
||||
|
||||
const keys = Object.keys(data[0] || {}).filter(d => d !== 'date');
|
||||
const series = [
|
||||
{
|
||||
name: title,
|
||||
type: 'bar',
|
||||
emphasis: { focus: 'series' },
|
||||
data: data.map((d: any) => d[dataKey]),
|
||||
},
|
||||
];
|
||||
|
||||
if (!keys.length) return null;
|
||||
const dates = data.map((d: any) => d.date);
|
||||
|
||||
let tooltipTimeout: number;
|
||||
return { dates, series };
|
||||
}, [data, title]);
|
||||
|
||||
const getDate = (d: any) => d.date;
|
||||
const option = useMemo(() => {
|
||||
const fontColor = themeContext.mode === 'light' ? 'black' : 'white';
|
||||
|
||||
const xScale = scaleBand<string>({
|
||||
domain: data.map(getDate),
|
||||
padding: 0.2,
|
||||
});
|
||||
|
||||
const barScale = scaleBand<string>({
|
||||
domain: keys,
|
||||
padding: 0.1,
|
||||
});
|
||||
|
||||
const yScale = scaleLinear<number>({
|
||||
domain: [
|
||||
0,
|
||||
Math.max(...data.map(d => Math.max(...keys.map(key => Number(d[key]))))),
|
||||
],
|
||||
});
|
||||
|
||||
const colorScale = scaleOrdinal<string, string>({
|
||||
domain: keys,
|
||||
range: colorRange,
|
||||
});
|
||||
|
||||
// bounds
|
||||
const xMax = width - margin.left - margin.right;
|
||||
const yMax = height - margin.top - margin.bottom;
|
||||
|
||||
// update scale output dimensions
|
||||
xScale.rangeRound([0, xMax]);
|
||||
yScale.rangeRound([yMax, 0]);
|
||||
barScale.rangeRound([0, xScale.bandwidth()]);
|
||||
return {
|
||||
color: colorRange,
|
||||
grid: {
|
||||
containLabel: true,
|
||||
top: '50px',
|
||||
left: '25px',
|
||||
bottom: '25px',
|
||||
right: '25px',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
animation: false,
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
return `<span style='color: ${
|
||||
colorRange[0]
|
||||
}; font-weight: bold;'>${title}</span><br />
|
||||
${formatSats(params[0].value)}<br />`;
|
||||
},
|
||||
...COMMON_CHART_STYLES.tooltip,
|
||||
},
|
||||
xAxis: {
|
||||
name: 'Dates',
|
||||
nameLocation: 'center',
|
||||
nameGap: 32,
|
||||
type: 'category',
|
||||
axisLine: { show: true, lineStyle: { color: fontColor } },
|
||||
data: seriesData.dates,
|
||||
axisLabel: {
|
||||
formatter: function (value: string) {
|
||||
const parseDate = timeParse('%Y-%m-%dT%H:%M:%S.%L%Z');
|
||||
const formatDate = timeFormat('%b %d');
|
||||
return formatDate(parseDate(value) as Date);
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
nameLocation: 'center',
|
||||
nameGap: 48,
|
||||
type: 'value',
|
||||
minInterval: 1,
|
||||
splitLine: { show: false },
|
||||
axisLine: { show: true, lineStyle: { color: fontColor } },
|
||||
axisTick: { show: true },
|
||||
axisLabel: {
|
||||
formatter: function (value: number) {
|
||||
const format = value < 1000 ? '0a' : '0.0a';
|
||||
return numeral(value).format(format);
|
||||
},
|
||||
},
|
||||
},
|
||||
series: seriesData.series,
|
||||
};
|
||||
}, [colorRange, themeContext, seriesData, title]);
|
||||
|
||||
return (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<svg width={width} height={height - 10}>
|
||||
<Group top={margin.top} left={margin.left}>
|
||||
<BarGroup
|
||||
data={data}
|
||||
keys={keys}
|
||||
height={yMax}
|
||||
x0={getDate}
|
||||
x0Scale={xScale}
|
||||
x1Scale={barScale}
|
||||
yScale={yScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{barGroups =>
|
||||
barGroups.map(barGroup => (
|
||||
<Group
|
||||
key={`bar-group-${barGroup.index}-${barGroup.x0}`}
|
||||
left={barGroup.x0}
|
||||
>
|
||||
{barGroup.bars.map(bar => (
|
||||
<rect
|
||||
key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
width={bar.width}
|
||||
height={Math.abs(bar.height)}
|
||||
fill={bar.color}
|
||||
onMouseOver={(e: any) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
|
||||
const coords = localPoint(e.target.ownerSVGElement, e);
|
||||
if (!coords) return;
|
||||
|
||||
showTooltip({
|
||||
tooltipLeft: coords.x,
|
||||
tooltipTop: coords.y,
|
||||
tooltipData: bar,
|
||||
});
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Group>
|
||||
))
|
||||
}
|
||||
</BarGroup>
|
||||
</Group>
|
||||
<AxisLeft
|
||||
numTicks={amountOfYTicks(height)}
|
||||
left={width - margin.left}
|
||||
top={margin.bottom}
|
||||
hideZero={true}
|
||||
scale={yScale}
|
||||
stroke={axisColor}
|
||||
tickStroke={axisColor}
|
||||
tickLabelProps={() => ({
|
||||
fill: axisColor,
|
||||
fontSize: 11,
|
||||
textAnchor: 'end',
|
||||
dy: '0.33em',
|
||||
dx: '-0.33em',
|
||||
})}
|
||||
/>
|
||||
<AxisBottom
|
||||
numTicks={amountOfXTicks(width)}
|
||||
top={yMax + margin.top}
|
||||
tickFormat={data.length == 24 ? tickFormatTime : tickFormatDate}
|
||||
scale={xScale}
|
||||
stroke={axisColor}
|
||||
tickStroke={axisColor}
|
||||
tickLabelProps={() => ({
|
||||
fill: axisColor,
|
||||
fontSize: 11,
|
||||
textAnchor: 'middle',
|
||||
})}
|
||||
/>
|
||||
</svg>
|
||||
{tooltipOpen && tooltipData ? (
|
||||
<TooltipWithBounds
|
||||
top={tooltipTop}
|
||||
left={tooltipLeft}
|
||||
style={tooltipStyles}
|
||||
>
|
||||
<div style={{ color: colorScale(tooltipData.key) }}>
|
||||
<strong>{tooltipData.key}</strong>
|
||||
</div>
|
||||
{priceLabel ? (
|
||||
<Price amount={tooltipData.value} />
|
||||
) : (
|
||||
tooltipData.value
|
||||
)}
|
||||
</TooltipWithBounds>
|
||||
) : null}
|
||||
</div>
|
||||
<ReactEChartsCore
|
||||
echarts={echarts}
|
||||
option={option}
|
||||
notMerge={true}
|
||||
lazyUpdate={true}
|
||||
showLoading={false}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const BarChart = (props: BarChartProps) => (
|
||||
<ParentSize>
|
||||
{parent => <Chart width={parent.width} height={parent.height} {...props} />}
|
||||
</ParentSize>
|
||||
);
|
||||
|
@ -1,191 +1,155 @@
|
||||
import { Group } from '@visx/group';
|
||||
import { BarGroupHorizontal, Bar } from '@visx/shape';
|
||||
import { AxisLeft } from '@visx/axis';
|
||||
import { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale';
|
||||
import { ParentSize } from '@visx/responsive';
|
||||
import { chartColors } from '../../../src/styles/Themes';
|
||||
import { chartColors } from '../../styles/Themes';
|
||||
import { ThemeContext } from 'styled-components';
|
||||
import { useContext } from 'react';
|
||||
import { TooltipWithBounds, defaultStyles, useTooltip } from '@visx/tooltip';
|
||||
import { localPoint } from '@visx/event';
|
||||
import { Price } from '../price/Price';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { BarChart } from 'echarts/charts';
|
||||
import {
|
||||
GraphicComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TitleComponent,
|
||||
ToolboxComponent,
|
||||
TooltipComponent,
|
||||
} from 'echarts/components';
|
||||
import * as echarts from 'echarts/core';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import ReactEChartsCore from 'echarts-for-react/lib/core';
|
||||
import { formatSats } from '../../utils/helpers';
|
||||
import { COMMON_CHART_STYLES } from './common';
|
||||
|
||||
type BarGroupProps = {
|
||||
width: number;
|
||||
height: number;
|
||||
} & BarChartProps;
|
||||
echarts.use([
|
||||
BarChart,
|
||||
CanvasRenderer,
|
||||
GridComponent,
|
||||
TooltipComponent,
|
||||
GraphicComponent,
|
||||
TitleComponent,
|
||||
LegendComponent,
|
||||
ToolboxComponent,
|
||||
]);
|
||||
|
||||
type BarChartProps = {
|
||||
type HorizontalBarChartProps = {
|
||||
data: any[];
|
||||
margin?: { top: number; right: number; bottom: number; left: number };
|
||||
events?: boolean;
|
||||
dataKey: string;
|
||||
colorRange?: string[];
|
||||
priceLabel?: boolean;
|
||||
};
|
||||
|
||||
const defaultMargin = { top: 40, right: 0, bottom: 40, left: 0 };
|
||||
const defaultColorRange = [
|
||||
chartColors.green,
|
||||
chartColors.orange,
|
||||
chartColors.lightblue,
|
||||
];
|
||||
|
||||
const tooltipStyles = {
|
||||
...defaultStyles,
|
||||
minWidth: 60,
|
||||
backgroundColor: 'rgba(0,0,0,0.9)',
|
||||
color: 'white',
|
||||
};
|
||||
|
||||
const Chart = ({
|
||||
width,
|
||||
height,
|
||||
margin = defaultMargin,
|
||||
export const HorizontalBarChart = ({
|
||||
data = [],
|
||||
colorRange = defaultColorRange,
|
||||
priceLabel,
|
||||
}: BarGroupProps) => {
|
||||
const {
|
||||
tooltipData,
|
||||
tooltipLeft,
|
||||
tooltipTop,
|
||||
tooltipOpen,
|
||||
showTooltip,
|
||||
hideTooltip,
|
||||
} = useTooltip<any>();
|
||||
|
||||
dataKey,
|
||||
}: HorizontalBarChartProps) => {
|
||||
const themeContext = useContext(ThemeContext);
|
||||
const axisColor = themeContext.mode === 'light' ? 'black' : 'white';
|
||||
|
||||
const keys = Object.keys(data[0] || {}).filter(d => d !== 'label');
|
||||
|
||||
if (!keys.length) return null;
|
||||
|
||||
const maxValue = Math.max(
|
||||
...data.map(d => Math.max(...keys.map(key => Number(d[key]))))
|
||||
);
|
||||
|
||||
let tooltipTimeout: number;
|
||||
const seriesData = useMemo(() => {
|
||||
if (data.length === 0) return [{ type: 'bar', data: [], barWidth: 25 }];
|
||||
|
||||
const getLabel = (d: any) => d.label;
|
||||
return [
|
||||
{
|
||||
type: 'bar',
|
||||
data: data.map((d: any) => d[dataKey]),
|
||||
barWidth: '25',
|
||||
},
|
||||
];
|
||||
}, [data, dataKey]);
|
||||
|
||||
const yScale = scaleBand<string>({
|
||||
domain: data.map(getLabel),
|
||||
});
|
||||
const yLabels = useMemo(() => {
|
||||
if (!data.length) return [];
|
||||
return data.map(d => d.label);
|
||||
}, [data]);
|
||||
|
||||
const barScale = scaleBand<string>({
|
||||
domain: keys,
|
||||
padding: 0.1,
|
||||
});
|
||||
const option = useMemo(() => {
|
||||
const themeColor = themeContext.mode === 'light' ? 'black' : 'white';
|
||||
|
||||
const xScale = scaleLinear<number>({
|
||||
domain: [0, maxValue + 0.1 * maxValue],
|
||||
});
|
||||
return {
|
||||
color: colorRange,
|
||||
grid: {
|
||||
left: '25px',
|
||||
bottom: '25px',
|
||||
top: '25px',
|
||||
right: '25px',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
animation: false,
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
return `<span style='color: ${
|
||||
colorRange[0]
|
||||
}; font-weight: bold;'>Value</span><br />
|
||||
${formatSats(params[0].value)}`;
|
||||
},
|
||||
...COMMON_CHART_STYLES.tooltip,
|
||||
},
|
||||
xAxis: {
|
||||
max: maxValue * 1.4,
|
||||
show: false,
|
||||
alignTicks: 'value',
|
||||
zIndex: 10,
|
||||
z: 10,
|
||||
},
|
||||
yAxis: {
|
||||
axisPointer: {
|
||||
show: true,
|
||||
type: 'none',
|
||||
triggerTooltip: true,
|
||||
},
|
||||
lineStyle: {
|
||||
color: themeColor,
|
||||
type: 'solid',
|
||||
},
|
||||
axisLine: {
|
||||
onZero: false,
|
||||
lineStyle: {
|
||||
color: themeColor,
|
||||
type: 'solid',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
inside: true,
|
||||
interval: 'auto',
|
||||
},
|
||||
axisTick: {
|
||||
show: true,
|
||||
alignWithLabel: true,
|
||||
interval: 'auto',
|
||||
inside: true,
|
||||
},
|
||||
data: yLabels,
|
||||
type: 'category',
|
||||
inverse: true,
|
||||
max: 4,
|
||||
position: 'right',
|
||||
},
|
||||
legend: { show: true },
|
||||
series: seriesData,
|
||||
};
|
||||
}, [colorRange, themeContext, seriesData, yLabels]);
|
||||
|
||||
const colorScale = scaleOrdinal<string, string>({
|
||||
domain: keys,
|
||||
range: colorRange,
|
||||
});
|
||||
|
||||
// bounds
|
||||
const xMax = width - margin.left - margin.right;
|
||||
const yMax = height - margin.top - margin.bottom;
|
||||
|
||||
// update scale output dimensions
|
||||
xScale.rangeRound([0, xMax]);
|
||||
yScale.rangeRound([yMax, 0]);
|
||||
barScale.rangeRound([0, yScale.bandwidth()]);
|
||||
if (!keys.length) return null;
|
||||
|
||||
return (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<svg width={width} height={height - 10}>
|
||||
<Group top={margin.top} left={margin.left}>
|
||||
<BarGroupHorizontal
|
||||
data={data}
|
||||
keys={keys}
|
||||
width={xMax}
|
||||
y0={getLabel}
|
||||
y0Scale={yScale}
|
||||
y1Scale={barScale}
|
||||
xScale={xScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{barGroups =>
|
||||
barGroups.map(barGroup => (
|
||||
<Group
|
||||
key={`bar-group-${barGroup.index}-${barGroup.y0}`}
|
||||
top={barGroup.y0}
|
||||
>
|
||||
{barGroup.bars.map(bar => (
|
||||
<Bar
|
||||
key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
width={bar.width < 10 ? 10 : bar.width}
|
||||
height={Math.abs(bar.height)}
|
||||
fill={bar.color}
|
||||
onMouseOver={(e: any) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
|
||||
const coords = localPoint(e.target.ownerSVGElement, e);
|
||||
if (!coords) return;
|
||||
|
||||
showTooltip({
|
||||
tooltipLeft: coords.x,
|
||||
tooltipTop: coords.y,
|
||||
tooltipData: bar,
|
||||
});
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Group>
|
||||
))
|
||||
}
|
||||
</BarGroupHorizontal>
|
||||
</Group>
|
||||
<AxisLeft
|
||||
left={width - margin.left}
|
||||
top={margin.bottom}
|
||||
hideZero={true}
|
||||
scale={yScale}
|
||||
stroke={axisColor}
|
||||
tickStroke={axisColor}
|
||||
tickLabelProps={() => ({
|
||||
fill: axisColor,
|
||||
fontSize: 11,
|
||||
textAnchor: 'end',
|
||||
dy: '0.33em',
|
||||
dx: '-0.33em',
|
||||
})}
|
||||
/>
|
||||
</svg>
|
||||
{tooltipOpen && tooltipData ? (
|
||||
<TooltipWithBounds
|
||||
top={tooltipTop}
|
||||
left={tooltipLeft}
|
||||
style={tooltipStyles}
|
||||
>
|
||||
<div style={{ color: colorScale(tooltipData.key) }}>
|
||||
<strong>{tooltipData.key}</strong>
|
||||
</div>
|
||||
{priceLabel ? (
|
||||
<Price amount={tooltipData.value} />
|
||||
) : (
|
||||
tooltipData.value
|
||||
)}
|
||||
</TooltipWithBounds>
|
||||
) : null}
|
||||
<div style={{ position: 'relative', height: '100%' }}>
|
||||
<ReactEChartsCore
|
||||
echarts={echarts}
|
||||
option={option}
|
||||
notMerge={true}
|
||||
lazyUpdate={true}
|
||||
showLoading={false}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const HorizontalBarChart = (props: BarChartProps) => (
|
||||
<ParentSize>
|
||||
{parent => <Chart width={parent.width} height={parent.height} {...props} />}
|
||||
</ParentSize>
|
||||
);
|
||||
|
9
src/client/src/components/chart/common.ts
Normal file
9
src/client/src/components/chart/common.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export const COMMON_CHART_STYLES = {
|
||||
tooltip: {
|
||||
backgroundColor: 'black',
|
||||
borderColor: 'black',
|
||||
textStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
},
|
||||
};
|
@ -1,108 +0,0 @@
|
||||
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>
|
||||
);
|
||||
};
|
@ -160,10 +160,11 @@ export const getPastFutureStr = (
|
||||
};
|
||||
|
||||
export const getFormatDate = (
|
||||
date: string | null | undefined
|
||||
date: string | null | undefined,
|
||||
style?: string
|
||||
): string | null => {
|
||||
if (!date) return null;
|
||||
return format(new Date(date), 'dd/MM/yyyy - HH:mm:ss');
|
||||
return format(new Date(date), style || 'yyyy.MM.dd - H:mm:ss');
|
||||
};
|
||||
|
||||
export const getMessageDate = (
|
||||
|
101
src/client/src/components/sankey/index.tsx
Normal file
101
src/client/src/components/sankey/index.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
import { useContext, useMemo } from 'react';
|
||||
import {
|
||||
GraphicComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TitleComponent,
|
||||
ToolboxComponent,
|
||||
TooltipComponent,
|
||||
} from 'echarts/components';
|
||||
import * as echarts from 'echarts/core';
|
||||
import { SankeyChart } from 'echarts/charts';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import ReactEChartsCore from 'echarts-for-react/lib/core';
|
||||
import { ThemeContext } from 'styled-components';
|
||||
|
||||
echarts.use([
|
||||
SankeyChart,
|
||||
CanvasRenderer,
|
||||
GridComponent,
|
||||
TooltipComponent,
|
||||
GraphicComponent,
|
||||
TitleComponent,
|
||||
LegendComponent,
|
||||
ToolboxComponent,
|
||||
]);
|
||||
|
||||
export type SankeyProps = {
|
||||
width: string;
|
||||
height: string;
|
||||
data: SankeyData;
|
||||
};
|
||||
|
||||
interface SankeyNode {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface SankeyLink {
|
||||
source: string;
|
||||
target: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface SankeyData {
|
||||
links: SankeyLink[];
|
||||
nodes: SankeyNode[];
|
||||
}
|
||||
|
||||
export const Sankey = ({ data, width, height }: SankeyProps) => {
|
||||
const themeContext = useContext(ThemeContext);
|
||||
|
||||
const option = useMemo(() => {
|
||||
const fontColor = themeContext.mode === 'light' ? 'black' : 'white';
|
||||
return {
|
||||
resize: true,
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
triggerOn: 'mousemove',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
height,
|
||||
type: 'sankey',
|
||||
nodeAlign: 'justify',
|
||||
nodeGap: 3,
|
||||
layoutIterations: 32,
|
||||
data: data.nodes,
|
||||
links: data.links,
|
||||
dragable: false,
|
||||
left: 'left',
|
||||
bottom: '5',
|
||||
top: 'top',
|
||||
label: {
|
||||
show: true,
|
||||
color: fontColor,
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'adjacency',
|
||||
},
|
||||
lineStyle: {
|
||||
color: 'gradient',
|
||||
curveness: 0.25,
|
||||
},
|
||||
itemStyle: {
|
||||
borderWidth: 50,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}, [data, themeContext, height]);
|
||||
|
||||
return (
|
||||
<ReactEChartsCore
|
||||
echarts={echarts}
|
||||
option={option}
|
||||
notMerge={true}
|
||||
lazyUpdate={true}
|
||||
showLoading={false}
|
||||
style={{ height, width }}
|
||||
/>
|
||||
);
|
||||
};
|
@ -12,6 +12,8 @@ import { widgetList, WidgetProps } from './widgetList';
|
||||
import { GetInvoicesQuery } from '../../../graphql/queries/__generated__/getInvoices.generated';
|
||||
import { GetPaymentsQuery } from '../../../graphql/queries/__generated__/getPayments.generated';
|
||||
|
||||
const ONE_WEEK = 7;
|
||||
|
||||
const getColumns = (width: number): number => {
|
||||
const { lg, md, sm, xs } = defaultGrid.breakpoints;
|
||||
|
||||
@ -82,12 +84,14 @@ export const getByTime = (array: ArrayType, time: number): any[] => {
|
||||
fee?: number;
|
||||
}[] = [];
|
||||
|
||||
// check to see if we're working in days (isDay = false) or hours (isDay = true)
|
||||
const isDay = time <= 1;
|
||||
|
||||
const today = isDay
|
||||
? new Date().setMinutes(0, 0, 0)
|
||||
: new Date().setHours(0, 0, 0, 0);
|
||||
|
||||
// Look through each transaction in the array and build an array of transactions with the difference between today and the day (or hour) that the tx occurred
|
||||
array.forEach((transaction: ArrayType[0]) => {
|
||||
if (!transaction?.__typename) return;
|
||||
|
||||
@ -149,10 +153,16 @@ export const getByTime = (array: ArrayType, time: number): any[] => {
|
||||
|
||||
if (!transactions?.length) return [];
|
||||
|
||||
// Group the transactionw in the array according to the 'difference' property of the object
|
||||
const grouped = groupBy(transactions, 'difference');
|
||||
|
||||
const final: any[] = [];
|
||||
const differences = Array.from({ length: isDay ? 24 : time }, (_, i) => i);
|
||||
|
||||
// If were working with a single day, divide the array in 24 pieces, one for each hour, otherwise, go back 7 days
|
||||
const differences = Array.from(
|
||||
{ length: isDay ? 24 : time ? time : ONE_WEEK },
|
||||
(_, i) => i
|
||||
);
|
||||
|
||||
differences.forEach(key => {
|
||||
const group = grouped[key];
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { useState } from 'react';
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
import { LoadingCard } from '../../../../components/loading/LoadingCard';
|
||||
import { SmallSelectWithValue } from '../../../../components/select';
|
||||
import { useGetForwardsQuery } from '../../../../graphql/queries/__generated__/getForwards.generated';
|
||||
import { chartColors } from '../../../../styles/Themes';
|
||||
import styled from 'styled-components';
|
||||
import { getByTime } from '../helpers';
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
|
||||
const S = {
|
||||
row: styled.div`
|
||||
@ -110,11 +110,12 @@ export const ForwardsGraph = () => {
|
||||
<Header />
|
||||
<S.content>
|
||||
<BarChart
|
||||
priceLabel={type.value !== 'amount'}
|
||||
data={forwards.map(f => ({
|
||||
Forward: f[type.value] || 0,
|
||||
date: f.date,
|
||||
}))}
|
||||
dataKey="Forward"
|
||||
title="Forwards Report"
|
||||
colorRange={[chartColors.purple]}
|
||||
/>
|
||||
</S.content>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
import { LoadingCard } from '../../../../components/loading/LoadingCard';
|
||||
import { SmallSelectWithValue } from '../../../../components/select';
|
||||
import { chartColors } from '../../../../styles/Themes';
|
||||
@ -7,6 +6,7 @@ import styled from 'styled-components';
|
||||
import { getByTime } from '../helpers';
|
||||
import { useGetInvoicesQuery } from '../../../../graphql/queries/__generated__/getInvoices.generated';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
|
||||
const S = {
|
||||
row: styled.div`
|
||||
@ -108,13 +108,14 @@ export const InvoicesGraph = () => {
|
||||
<Header />
|
||||
<S.content>
|
||||
<BarChart
|
||||
priceLabel={type.value !== 'amount'}
|
||||
data={invoicesByDate.map(f => {
|
||||
return {
|
||||
Invoices: f?.[type.value] || 0,
|
||||
date: f.date,
|
||||
};
|
||||
})}
|
||||
dataKey="Invoices"
|
||||
title="Invoices"
|
||||
colorRange={[chartColors.orange2]}
|
||||
/>
|
||||
</S.content>
|
||||
|
@ -62,9 +62,9 @@ export const LiquidityGraph = () => {
|
||||
return (
|
||||
<S.wrapper>
|
||||
<HorizontalBarChart
|
||||
priceLabel={true}
|
||||
data={liquidity}
|
||||
colorRange={[chartColors.green]}
|
||||
dataKey="Value"
|
||||
/>
|
||||
</S.wrapper>
|
||||
);
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
import { LoadingCard } from '../../../../components/loading/LoadingCard';
|
||||
import { SmallSelectWithValue } from '../../../../components/select';
|
||||
import { chartColors } from '../../../../styles/Themes';
|
||||
@ -8,6 +6,7 @@ import styled from 'styled-components';
|
||||
import { getByTime } from '../helpers';
|
||||
import { useGetPaymentsQuery } from '../../../../graphql/queries/__generated__/getPayments.generated';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
|
||||
const S = {
|
||||
row: styled.div`
|
||||
@ -108,7 +107,6 @@ export const PaymentsGraph = () => {
|
||||
<Header />
|
||||
<S.content>
|
||||
<BarChart
|
||||
priceLabel={type.value !== 'amount'}
|
||||
data={paymentsByDate.map(f => {
|
||||
return {
|
||||
Payments: f?.[type.value] || 0,
|
||||
@ -116,6 +114,8 @@ export const PaymentsGraph = () => {
|
||||
};
|
||||
})}
|
||||
colorRange={[chartColors.darkyellow]}
|
||||
title="Payments"
|
||||
dataKey="Payments"
|
||||
/>
|
||||
</S.content>
|
||||
</S.wrapper>
|
||||
|
@ -1,161 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { getErrorContent } from '../../utils/error';
|
||||
import { Forward } from '../../graphql/types';
|
||||
import { ParentSize } from '@visx/responsive';
|
||||
import {
|
||||
ChordGraph,
|
||||
SingleGroupProps,
|
||||
SingleChordProps,
|
||||
} from '../../components/chord';
|
||||
import styled from 'styled-components';
|
||||
import { renderLine } from '../../components/generic/helpers';
|
||||
import { DarkSubTitle } from '../../components/generic/Styled';
|
||||
import { mediaWidths } from '../../styles/Themes';
|
||||
import { usePriceState } from '../../context/PriceContext';
|
||||
import { getPrice } from '../../components/price/Price';
|
||||
import { useConfigState } from '../../context/ConfigContext';
|
||||
import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated';
|
||||
import { ChannelAlias } from '../home/reports/forwardReport/ChannelAlias';
|
||||
import { getChordMatrix } from './helpers';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 800px;
|
||||
width: 100%;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
height: 300px;
|
||||
}
|
||||
`;
|
||||
|
||||
const Center = styled.div`
|
||||
width: '100%';
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
type SelectedProps =
|
||||
| { type: 'group'; group: SingleGroupProps }
|
||||
| { type: 'chord'; chord: SingleChordProps }
|
||||
| null;
|
||||
|
||||
const getTitle = (order: string) => {
|
||||
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: string;
|
||||
}) => {
|
||||
const [selected, setSelected] = useState<SelectedProps>();
|
||||
|
||||
useEffect(() => {
|
||||
setSelected(null);
|
||||
}, [order]);
|
||||
|
||||
const { data, loading } = useGetForwardsQuery({
|
||||
ssr: false,
|
||||
variables: { days },
|
||||
onError: error => toast.error(getErrorContent(error)),
|
||||
});
|
||||
|
||||
const { currency, displayValues } = useConfigState();
|
||||
const priceContext = usePriceState();
|
||||
const format = getPrice(currency, displayValues, priceContext);
|
||||
|
||||
if (loading || !data?.getForwards?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { matrix, uniqueNodes } = getChordMatrix(
|
||||
order,
|
||||
data.getForwards 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(
|
||||
'With',
|
||||
<ChannelAlias id={uniqueNodes[selected.group.index]} />
|
||||
)}
|
||||
{renderLine('Channel Id', uniqueNodes[selected.group.index])}
|
||||
{renderLine(
|
||||
getTitle(order),
|
||||
format({ amount: selected.group.value, noUnit: order === 'amount' })
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (selected.type === 'chord') {
|
||||
return (
|
||||
<>
|
||||
{renderLine(
|
||||
'Between',
|
||||
<>
|
||||
<ChannelAlias id={uniqueNodes[selected.chord.source.index]} />
|
||||
{` - `}
|
||||
<ChannelAlias id={uniqueNodes[selected.chord.target.index]} />
|
||||
</>
|
||||
)}
|
||||
{renderLine(
|
||||
'Channel Ids',
|
||||
`${uniqueNodes[selected.chord.source.index]} - ${
|
||||
uniqueNodes[selected.chord.target.index]
|
||||
}`
|
||||
)}
|
||||
{renderLine(
|
||||
getTitle(order),
|
||||
format({
|
||||
amount: selected.chord.source.value,
|
||||
noUnit: order === 'amount',
|
||||
})
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderInfo()}
|
||||
<Wrapper>
|
||||
<ParentSize>
|
||||
{parent => (
|
||||
<ChordGraph
|
||||
matrix={matrix}
|
||||
width={parent.width}
|
||||
height={parent.height}
|
||||
groupCallback={handleGroupClick}
|
||||
chordCallback={handleChordClick}
|
||||
/>
|
||||
)}
|
||||
</ParentSize>
|
||||
</Wrapper>
|
||||
</>
|
||||
);
|
||||
};
|
100
src/client/src/views/forwards/forwardSankey.tsx
Normal file
100
src/client/src/views/forwards/forwardSankey.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { getErrorContent } from '../../utils/error';
|
||||
import styled from 'styled-components';
|
||||
import { mediaWidths } from '../../styles/Themes';
|
||||
import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated';
|
||||
import { Sankey, SankeyData } from '../../components/sankey';
|
||||
import { groupBy, orderBy, reduce, uniq } from 'lodash';
|
||||
|
||||
const Wrapper = styled.div<{ $height: number }>`
|
||||
height: ${props => props.$height}px;
|
||||
max-height: ${props => props.$height}px;
|
||||
width: 100%;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
height: ${props => props.$height}px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ForwardSankey: FC<{
|
||||
days: number;
|
||||
type: 'amount' | 'fee' | 'tokens';
|
||||
}> = ({ days, type }) => {
|
||||
const { data, loading } = useGetForwardsQuery({
|
||||
ssr: false,
|
||||
variables: { days },
|
||||
onError: error => toast.error(getErrorContent(error)),
|
||||
});
|
||||
|
||||
const sankeyData: SankeyData = useMemo(() => {
|
||||
if (loading || !data || !data.getForwards.length) {
|
||||
return { links: [], nodes: [] };
|
||||
}
|
||||
|
||||
const mapped = data.getForwards.map(d => ({
|
||||
...d,
|
||||
group: `${d.incoming_channel}-${d.outgoing_channel}`,
|
||||
}));
|
||||
|
||||
const grouped = groupBy(mapped, 'group');
|
||||
|
||||
const aggregated: {
|
||||
incoming_channel: string;
|
||||
outgoing_channel: string;
|
||||
fee: number;
|
||||
tokens: number;
|
||||
amount: number;
|
||||
}[] = [];
|
||||
|
||||
Object.entries(grouped).forEach(([, value]) => {
|
||||
const totalFees = value.map(v => v.fee).reduce((p, c) => p + c, 0);
|
||||
const totalTokens = value.map(v => v.tokens).reduce((p, c) => p + c, 0);
|
||||
const totalAmount = value.length;
|
||||
|
||||
const firstValue = value[0];
|
||||
|
||||
aggregated.push({
|
||||
incoming_channel: firstValue.incoming_channel,
|
||||
outgoing_channel: firstValue.outgoing_channel,
|
||||
fee: totalFees,
|
||||
tokens: totalTokens,
|
||||
amount: totalAmount,
|
||||
});
|
||||
});
|
||||
|
||||
const finalData = reduce(
|
||||
aggregated,
|
||||
(p, c) => {
|
||||
const source = `source: ${c.incoming_channel}`;
|
||||
const target = `target: ${c.outgoing_channel}`;
|
||||
|
||||
return {
|
||||
links: [...p.links, { source, target, value: c[type] || 0 }],
|
||||
nodes: [...p.nodes, source, target],
|
||||
};
|
||||
},
|
||||
{
|
||||
links: [] as { source: string; target: string; value: number }[],
|
||||
nodes: [] as string[],
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
links: orderBy(finalData.links, 'value', 'desc'),
|
||||
nodes: uniq(finalData.nodes).map(n => ({ name: n })),
|
||||
};
|
||||
}, [data, loading, type]);
|
||||
|
||||
if (loading || !data?.getForwards?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const graphHeight = 800 + 10 * sankeyData.links.length;
|
||||
|
||||
return (
|
||||
<Wrapper $height={graphHeight}>
|
||||
<Sankey data={sankeyData} width="100%" height={`${graphHeight}px`} />
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
@ -1,52 +1,6 @@
|
||||
import { sortBy } from 'lodash';
|
||||
import { Forward } from '../../graphql/types';
|
||||
|
||||
export const getChordMatrix = (order: string, forwardArray: Forward[]) => {
|
||||
const cleaned = forwardArray.map(f => {
|
||||
let value = 1;
|
||||
|
||||
if (order === 'fee') {
|
||||
value = f.fee;
|
||||
} else if (order === 'tokens') {
|
||||
value = f.tokens;
|
||||
}
|
||||
|
||||
return {
|
||||
incoming_channel: f.incoming_channel,
|
||||
outgoing_channel: f.outgoing_channel,
|
||||
value,
|
||||
};
|
||||
});
|
||||
|
||||
const incomingNodes = cleaned.map(f => f.incoming_channel);
|
||||
const outgoingNodes = cleaned.map(f => f.outgoing_channel);
|
||||
|
||||
const uniqueNodes = [
|
||||
...Array.from(new Set(incomingNodes)),
|
||||
...Array.from(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.incoming_channel);
|
||||
const outIndex = uniqueNodes.indexOf(f.outgoing_channel);
|
||||
|
||||
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 };
|
||||
};
|
||||
|
||||
export const sortByNode = (order: string, forwardArray: Forward[]) => {
|
||||
const cleaned = forwardArray.map(f => {
|
||||
let value = 1;
|
||||
|
@ -0,0 +1,93 @@
|
||||
export function generateUniqueSourcesAndTargets(
|
||||
numSources: number,
|
||||
numTargets: number,
|
||||
numRecords: number
|
||||
) {
|
||||
const sources: string[] = [];
|
||||
const targets: string[] = [];
|
||||
|
||||
// Generate unique sources
|
||||
for (let i = 0; i < numSources; i++) {
|
||||
const randomSource = `${Math.floor(Math.random() * 10000) + 1}x1x1`;
|
||||
sources.push(randomSource);
|
||||
}
|
||||
|
||||
// Generate unique targets
|
||||
for (let i = 0; i < numTargets; i++) {
|
||||
const randomTarget = `${Math.floor(Math.random() * 10000) + 1}x1x1`;
|
||||
targets.push(randomTarget);
|
||||
}
|
||||
|
||||
// Build a graph to represent the relationships between sources and targets
|
||||
const graph: { [key: string]: string[] } = {};
|
||||
for (const target of targets) {
|
||||
graph[target] = [];
|
||||
}
|
||||
|
||||
const links = [];
|
||||
|
||||
// Generate items while ensuring no circular references
|
||||
const orderedTargets = topologicalSort(graph);
|
||||
|
||||
for (const source of sources) {
|
||||
for (const target of orderedTargets) {
|
||||
const randomValue = Math.floor(Math.random() * 1000000) + 1;
|
||||
|
||||
const newItem = {
|
||||
source: `source: ${source}`,
|
||||
target: `target: ${target}`,
|
||||
value: randomValue,
|
||||
};
|
||||
|
||||
links.push(newItem);
|
||||
graph[source] = graph[source] || [];
|
||||
graph[source].push(target);
|
||||
|
||||
// If the desired number of records is reached, exit the loop early
|
||||
if (links.length === numRecords) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If the desired number of records is reached, exit the loop early
|
||||
if (links.length === numRecords) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract unique nodes from links
|
||||
const uniqueNodesSet = new Set<string>();
|
||||
for (const link of links) {
|
||||
uniqueNodesSet.add(link.source);
|
||||
uniqueNodesSet.add(link.target);
|
||||
}
|
||||
|
||||
const nodes = Array.from(uniqueNodesSet).map(node => ({ name: node }));
|
||||
|
||||
return { links, nodes };
|
||||
}
|
||||
|
||||
// Function to perform topological sorting
|
||||
function topologicalSort(graph: { [key: string]: string[] }): string[] {
|
||||
const visited = new Set<string>();
|
||||
const stack: string[] = [];
|
||||
|
||||
function dfs(node: string) {
|
||||
if (visited.has(node)) return;
|
||||
visited.add(node);
|
||||
|
||||
const neighbors = graph[node];
|
||||
if (neighbors) {
|
||||
for (const neighbor of neighbors) {
|
||||
dfs(neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
stack.push(node);
|
||||
}
|
||||
|
||||
for (const node of Object.keys(graph)) {
|
||||
dfs(node);
|
||||
}
|
||||
|
||||
return stack.reverse();
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { FC, useMemo } from 'react';
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
import { LoadingCard } from '../../../../components/loading/LoadingCard';
|
||||
import { chartColors } from '../../../../styles/Themes';
|
||||
import { getByTime } from '../../../../views/dashboard/widgets/helpers';
|
||||
@ -7,6 +6,7 @@ import styled from 'styled-components';
|
||||
import { useGetInvoicesQuery } from '../../../../graphql/queries/__generated__/getInvoices.generated';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import { useGetPaymentsQuery } from '../../../../graphql/queries/__generated__/getPayments.generated';
|
||||
import { BarChart } from '../../../../components/chart/BarChart';
|
||||
|
||||
const S = {
|
||||
row: styled.div`
|
||||
@ -48,12 +48,29 @@ export const TransactionsGraph: FC<TransactionsGraphProps> = ({
|
||||
showPay,
|
||||
type,
|
||||
}) => {
|
||||
const { data, loading } = useGetInvoicesQuery();
|
||||
const { data: invoiceData, loading } = useGetInvoicesQuery();
|
||||
const { data: paymentsData, loading: paymentsLoading } =
|
||||
useGetPaymentsQuery();
|
||||
|
||||
const labels = useMemo(() => {
|
||||
switch (type) {
|
||||
case 'amount':
|
||||
return {
|
||||
yAxisLabel: `Amount of ${showPay ? 'Payments' : 'Invoices'}`,
|
||||
title: `Amount of ${showPay ? 'Payments' : 'Invoices'}`,
|
||||
};
|
||||
case 'tokens':
|
||||
return {
|
||||
yAxisLabel: `${showPay ? 'Payments' : 'Invoices'} Volume (sats)`,
|
||||
title: `${showPay ? 'Payments' : 'Invoices'} Volume (sats)`,
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}, [type, showPay]);
|
||||
|
||||
const invoicesByDate = useMemo(() => {
|
||||
const invoices = data?.getInvoices.invoices || [];
|
||||
const invoices = invoiceData?.getInvoices.invoices || [];
|
||||
const filtered = invoices.filter(i => !!i.is_confirmed);
|
||||
|
||||
if (!filtered.length) {
|
||||
@ -70,7 +87,7 @@ export const TransactionsGraph: FC<TransactionsGraphProps> = ({
|
||||
const invoicesByDate = getByTime(filtered, difference);
|
||||
|
||||
return invoicesByDate;
|
||||
}, [data]);
|
||||
}, [invoiceData, showPay]);
|
||||
|
||||
const paymentsByDate = useMemo(() => {
|
||||
const payments = paymentsData?.getPayments.payments || [];
|
||||
@ -90,7 +107,7 @@ export const TransactionsGraph: FC<TransactionsGraphProps> = ({
|
||||
const paymentsByDate = getByTime(filtered, difference);
|
||||
|
||||
return paymentsByDate;
|
||||
}, [paymentsData]);
|
||||
}, [paymentsData, showPay]);
|
||||
|
||||
if (loading || paymentsLoading) {
|
||||
return (
|
||||
@ -102,10 +119,15 @@ export const TransactionsGraph: FC<TransactionsGraphProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (!data?.getInvoices.invoices.length) {
|
||||
if (
|
||||
(!showPay && !invoiceData?.getInvoices.invoices.length) ||
|
||||
(showPay && !paymentsData?.getPayments.payments.length)
|
||||
) {
|
||||
return (
|
||||
<S.wrapper>
|
||||
<S.contentWrapper>No transactions for this period.</S.contentWrapper>
|
||||
<S.contentWrapper>
|
||||
No {showPay ? 'payments' : 'invoices'} for this period.
|
||||
</S.contentWrapper>
|
||||
</S.wrapper>
|
||||
);
|
||||
}
|
||||
@ -117,7 +139,6 @@ export const TransactionsGraph: FC<TransactionsGraphProps> = ({
|
||||
<S.wrapper>
|
||||
<S.content>
|
||||
<BarChart
|
||||
priceLabel={type !== 'amount'}
|
||||
data={finalArray.map(f => {
|
||||
return {
|
||||
[showPay ? 'Payments' : 'Invoices']: f?.[type] || 0,
|
||||
@ -125,6 +146,8 @@ export const TransactionsGraph: FC<TransactionsGraphProps> = ({
|
||||
};
|
||||
})}
|
||||
colorRange={finalColor}
|
||||
title={labels.title || ''}
|
||||
dataKey={showPay ? 'Payments' : 'Invoices'}
|
||||
/>
|
||||
</S.content>
|
||||
</S.wrapper>
|
||||
|
@ -43,7 +43,7 @@ const options = [
|
||||
|
||||
const typeOptions = [
|
||||
{ label: 'Count', value: 'amount' },
|
||||
{ label: 'Amount', value: 'tokens' },
|
||||
{ label: 'Volume', value: 'tokens' },
|
||||
];
|
||||
|
||||
export const FlowBox = () => {
|
||||
|
@ -83,12 +83,13 @@ export const ForwardsGraph: FC<ForwardGraphProps> = ({ days, type }) => {
|
||||
<S.wrapper>
|
||||
<S.content>
|
||||
<BarChart
|
||||
priceLabel={type.value !== 'amount'}
|
||||
title="Forwards"
|
||||
data={forwards.map(f => ({
|
||||
Forward: f[type.value] || 0,
|
||||
date: f.date,
|
||||
}))}
|
||||
colorRange={[chartColors.purple]}
|
||||
dataKey="Forward"
|
||||
/>
|
||||
</S.content>
|
||||
</S.wrapper>
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { HorizontalBarChart } from '../../../../components/chart/HorizontalBarChart';
|
||||
import {
|
||||
Card,
|
||||
CardWithTitle,
|
||||
@ -10,6 +9,7 @@ import { useGetLiquidReportQuery } from '../../../../graphql/queries/__generated
|
||||
import { chartColors } from '../../../../styles/Themes';
|
||||
import styled from 'styled-components';
|
||||
import { WarningText } from '../../../../views/stats/styles';
|
||||
import { HorizontalBarChart } from '../../../../components/chart/HorizontalBarChart';
|
||||
|
||||
const S = {
|
||||
row: styled.div`
|
||||
@ -76,11 +76,11 @@ export const LiquidityGraph = () => {
|
||||
} = data.getChannelReport;
|
||||
|
||||
const liquidity = [
|
||||
{ label: 'Total Commit', Value: commit },
|
||||
{ label: 'Max Outgoing', Value: maxOut },
|
||||
{ label: 'Max Incoming', Value: maxIn },
|
||||
{ label: 'Local Balance', Value: local },
|
||||
{ label: 'Remote Balance', Value: remote },
|
||||
{ label: 'Local Balance', Value: local },
|
||||
{ label: 'Max Incoming', Value: maxIn },
|
||||
{ label: 'Max Outgoing', Value: maxOut },
|
||||
{ label: 'Total Commit', Value: commit },
|
||||
];
|
||||
|
||||
const htlc = [
|
||||
@ -96,7 +96,7 @@ export const LiquidityGraph = () => {
|
||||
<Card mobileCardPadding={'8px 0'}>
|
||||
<S.wrapper>
|
||||
<HorizontalBarChart
|
||||
priceLabel={true}
|
||||
dataKey="Value"
|
||||
data={liquidity}
|
||||
colorRange={[chartColors.green]}
|
||||
/>
|
||||
@ -119,7 +119,7 @@ export const LiquidityGraph = () => {
|
||||
) : (
|
||||
<S.wrapper>
|
||||
<HorizontalBarChart
|
||||
priceLabel={false}
|
||||
dataKey="Value"
|
||||
data={htlc}
|
||||
colorRange={[chartColors.green]}
|
||||
/>
|
||||
|
Loading…
Reference in New Issue
Block a user