graph-cases.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import React from 'react';
  2. import format from 'date-fns/format';
  3. import { LineChart, XAxis, YAxis, Line, CartesianGrid } from 'recharts';
  4. import { lighten } from 'polished';
  5. import { Countries, CountryCases, Data } from '../types';
  6. import { getCases } from '../utils/get-cases';
  7. import { processCases } from '../utils/regression';
  8. const margin = {
  9. top: 0,
  10. right: 0,
  11. bottom: 0,
  12. left: 0,
  13. };
  14. const dateTickFormatter = (date: Date): string => {
  15. return format(new Date(date), 'LLL do'); // 'Do MMM');
  16. };
  17. type Props = {
  18. countries: Countries;
  19. };
  20. const GraphCases: React.FC<Props> = ({ countries }) => {
  21. const [showCumulative, setCumulative] = React.useState<boolean>(true);
  22. const toggleCumulative = React.useCallback(() => setCumulative(last => !last), []);
  23. const countryCases = React.useMemo<CountryCases>(
  24. () =>
  25. countries.map(({ country }) => ({
  26. country,
  27. dataSource: getCases(country),
  28. })),
  29. [countries],
  30. );
  31. const data = React.useMemo<Data>(() => processCases(countryCases, showCumulative), [
  32. countryCases,
  33. showCumulative,
  34. ]);
  35. if (!data.length) {
  36. return (
  37. <div>
  38. <h3>No data!</h3>
  39. </div>
  40. );
  41. }
  42. return (
  43. <div>
  44. <>
  45. {countries.map(({ country }, index) => (
  46. <React.Fragment key={country}>
  47. <h3>Country: {country}</h3>
  48. <p>
  49. Source:{' '}
  50. <a href={countryCases[index].dataSource.source}>
  51. {countryCases[index].dataSource.source}
  52. </a>
  53. </p>
  54. </React.Fragment>
  55. ))}
  56. </>
  57. <p>
  58. <input type="checkbox" onChange={toggleCumulative} checked={showCumulative} /> Cumulative
  59. cases
  60. </p>
  61. <LineChart width={640} height={480} data={data} margin={margin}>
  62. <XAxis
  63. dataKey="xValue"
  64. domain={['auto', 'auto']}
  65. tickFormatter={dateTickFormatter}
  66. type="number"
  67. />
  68. <YAxis tick yAxisId="left" />
  69. <CartesianGrid stroke="#f5f5f5" />
  70. {countries.map(({ country, color }) => (
  71. <Line
  72. key={`actual-${country}`}
  73. type="monotone"
  74. dataKey={`value.${country}`}
  75. stroke={color}
  76. yAxisId="left"
  77. dot={false}
  78. strokeWidth={2}
  79. />
  80. ))}
  81. {countries.map(({ country, color }) => (
  82. <Line
  83. key={`regression-${country}`}
  84. type="monotone"
  85. dataKey={`regression.${country}`}
  86. stroke={lighten(0.1)(color)}
  87. yAxisId="left"
  88. dot={false}
  89. />
  90. ))}
  91. </LineChart>
  92. </div>
  93. );
  94. };
  95. export default GraphCases;