SummaryChart.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import React from 'react'
  2. import { ResponsiveContainer, PieChart, Pie, Cell } from 'recharts'
  3. import { primary, greyscale, browns } from '../../constants/colors';
  4. import { toCurrency } from '../../util';
  5. function toPieData(top, other, idle) {
  6. let slices = []
  7. for (const i in top) {
  8. const allocation = top[i]
  9. const fill = allocation.name === "__unallocated__"
  10. ? "#212121"
  11. : primary[i % primary.length]
  12. slices.push({
  13. name: allocation.name,
  14. value: allocation.totalCost,
  15. fill: fill,
  16. })
  17. }
  18. for (const i in other) {
  19. const allocation = other[i]
  20. const fill = browns[i % browns.length]
  21. slices.push({
  22. name: allocation.name,
  23. value: allocation.totalCost,
  24. fill: fill,
  25. })
  26. }
  27. for (const i in idle) {
  28. const allocation = idle[i]
  29. const fill = greyscale[i % greyscale.length]
  30. slices.push({
  31. name: allocation.name,
  32. value: allocation.totalCost,
  33. fill: fill,
  34. })
  35. }
  36. return slices
  37. }
  38. const SummaryChart = ({ top, other, idle, currency, height }) => {
  39. const pieData = toPieData(top, other, idle)
  40. const renderLabel = (params) => {
  41. const {
  42. cx, cy, midAngle, outerRadius, percent, name, fill, value
  43. } = params
  44. const RADIAN = Math.PI / 180
  45. const radius = outerRadius * 1.1
  46. let x = cx + radius * Math.cos(-midAngle * RADIAN)
  47. x += x > cx ? 2 : -2
  48. let y = cy + radius * Math.sin(-midAngle * RADIAN)
  49. // y -= Math.min(Math.abs(2 / Math.cos(-midAngle * RADIAN)), 8)
  50. if (percent < 0.02) {
  51. return
  52. }
  53. return (
  54. <text x={x} y={y} fill={fill} textAnchor={x > cx ? 'start' : 'end'} dominantBaseline="central">
  55. {`${name}: ${toCurrency(value, currency)} (${(percent * 100).toFixed(1)}%)`}
  56. </text>
  57. )
  58. }
  59. return (
  60. <ResponsiveContainer width="100%" height={height}>
  61. <PieChart>
  62. <Pie
  63. data={pieData}
  64. dataKey="value"
  65. nameKey="name"
  66. label={renderLabel}
  67. labelLine
  68. // niko: if tooltips error, try disabling animation
  69. // isAnimationActive={false}
  70. animationDuration={400}
  71. cy="90%"
  72. outerRadius="140%"
  73. innerRadius="60%"
  74. startAngle={180}
  75. endAngle={0}
  76. >
  77. {pieData.map((datum, i) => <Cell key={i} fill={datum.fill} />)}
  78. </Pie>
  79. </PieChart>
  80. </ResponsiveContainer>
  81. )
  82. }
  83. export default SummaryChart