chart.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import * as React from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import BaseChart from 'app/components/charts/baseChart';
  4. import {t} from 'app/locale';
  5. import {Project} from 'app/types';
  6. import {axisLabelFormatter} from 'app/utils/discover/charts';
  7. import NoEvents from './noEvents';
  8. type BaseChartProps = React.ComponentProps<typeof BaseChart>;
  9. type Props = {
  10. firstEvent: boolean;
  11. stats: Project['stats'];
  12. transactionStats?: Project['transactionStats'];
  13. };
  14. const Chart = ({firstEvent, stats, transactionStats}: Props) => {
  15. const series: BaseChartProps['series'] = [];
  16. const hasTransactions = transactionStats !== undefined;
  17. const theme = useTheme();
  18. if (transactionStats) {
  19. const transactionSeries = transactionStats.map(([timestamp, value]) => [
  20. timestamp * 1000,
  21. value,
  22. ]);
  23. series.push({
  24. cursor: 'normal' as const,
  25. name: t('Transactions'),
  26. type: 'bar',
  27. data: transactionSeries,
  28. barMinHeight: 1,
  29. xAxisIndex: 1,
  30. yAxisIndex: 1,
  31. itemStyle: {
  32. color: theme.gray200,
  33. opacity: 0.8,
  34. emphasis: {
  35. color: theme.gray200,
  36. opacity: 1.0,
  37. },
  38. },
  39. });
  40. }
  41. if (stats) {
  42. series.push({
  43. cursor: 'normal' as const,
  44. name: t('Errors'),
  45. type: 'bar',
  46. data: stats.map(([timestamp, value]) => [timestamp * 1000, value]),
  47. barMinHeight: 1,
  48. xAxisIndex: 0,
  49. yAxisIndex: 0,
  50. itemStyle: {
  51. color: theme.purple300,
  52. opacity: 0.6,
  53. emphasis: {
  54. color: theme.purple300,
  55. opacity: 0.8,
  56. },
  57. },
  58. });
  59. }
  60. const grid = hasTransactions
  61. ? [
  62. {
  63. top: 10,
  64. bottom: 60,
  65. left: 2,
  66. right: 2,
  67. },
  68. {
  69. top: 105,
  70. bottom: 0,
  71. left: 2,
  72. right: 2,
  73. },
  74. ]
  75. : [
  76. {
  77. top: 10,
  78. bottom: 0,
  79. left: 2,
  80. right: 2,
  81. },
  82. ];
  83. const chartOptions = {
  84. series,
  85. colors: [],
  86. height: 150,
  87. isGroupedByDate: true,
  88. showTimeInTooltip: true,
  89. grid,
  90. tooltip: {
  91. trigger: 'axis' as const,
  92. },
  93. xAxes: Array.from(new Array(series.length)).map((_i, index) => ({
  94. gridIndex: index,
  95. boundaryGap: true,
  96. axisLine: {
  97. show: false,
  98. },
  99. axisTick: {
  100. show: false,
  101. },
  102. axisLabel: {
  103. show: false,
  104. },
  105. axisPointer: {
  106. type: 'line' as const,
  107. label: {
  108. show: false,
  109. },
  110. lineStyle: {
  111. width: 0,
  112. },
  113. },
  114. })),
  115. yAxes: Array.from(new Array(series.length)).map((_i, index) => ({
  116. gridIndex: index,
  117. interval: Infinity,
  118. max(value: {max: number}) {
  119. // This keeps small datasets from looking 'scary'
  120. // by having full bars for < 10 values.
  121. return Math.max(10, value.max);
  122. },
  123. axisLabel: {
  124. margin: 2,
  125. showMaxLabel: true,
  126. showMinLabel: false,
  127. color: theme.chartLabel,
  128. fontFamily: theme.text.family,
  129. inside: true,
  130. lineHeight: 12,
  131. formatter: (value: number) => axisLabelFormatter(value, 'count()', true),
  132. textBorderColor: theme.backgroundSecondary,
  133. textBorderWidth: 1,
  134. },
  135. splitLine: {
  136. show: false,
  137. },
  138. zlevel: theme.zIndex.header,
  139. })),
  140. axisPointer: {
  141. // Link each x-axis together.
  142. link: [{xAxisIndex: [0, 1]}],
  143. },
  144. options: {
  145. animation: false,
  146. },
  147. };
  148. return (
  149. <React.Fragment>
  150. <BaseChart {...chartOptions} />
  151. {!firstEvent && <NoEvents seriesCount={series.length} />}
  152. </React.Fragment>
  153. );
  154. };
  155. export default Chart;