manifold/web/components/analytics/charts.tsx

137 lines
3.5 KiB
TypeScript
Raw Normal View History

2022-05-19 20:14:13 +00:00
import { Point, ResponsiveLine } from '@nivo/line'
import clsx from 'clsx'
import { formatPercent } from 'common/util/format'
import dayjs from 'dayjs'
import { zip } from 'lodash'
import { useWindowSize } from 'web/hooks/use-window-size'
2022-05-19 20:14:13 +00:00
import { Col } from '../layout/col'
export function DailyCountChart(props: {
startDate: number
dailyCounts: number[]
2022-03-03 20:59:12 +00:00
small?: boolean
}) {
2022-03-03 20:59:12 +00:00
const { dailyCounts, startDate, small } = props
const { width } = useWindowSize()
const dates = dailyCounts.map((_, i) =>
dayjs(startDate).add(i, 'day').toDate()
)
const points = zip(dates, dailyCounts).map(([date, betCount]) => ({
x: date,
y: betCount,
}))
2022-03-03 20:59:12 +00:00
const data = [{ id: 'Count', data: points, color: '#11b981' }]
const bottomAxisTicks = width && width < 600 ? 6 : undefined
return (
<div
className={clsx(
'h-[250px] w-full overflow-hidden',
!small && 'md:h-[400px]'
)}
>
<ResponsiveLine
data={data}
2022-03-03 20:59:12 +00:00
yScale={{ type: 'linear', stacked: false }}
xScale={{
type: 'time',
}}
axisBottom={{
tickValues: bottomAxisTicks,
format: (date) => dayjs(date).format('MMM DD'),
}}
colors={{ datum: 'color' }}
2022-03-20 21:23:25 +00:00
pointSize={0}
pointBorderWidth={1}
pointBorderColor="#fff"
enableSlices="x"
enableGridX={!!width && width >= 800}
enableArea
margin={{ top: 20, right: 28, bottom: 22, left: 40 }}
2022-05-19 20:14:13 +00:00
sliceTooltip={({ slice }) => {
const point = slice.points[0]
return <Tooltip point={point} />
}}
/>
</div>
)
}
2022-03-22 21:24:26 +00:00
export function DailyPercentChart(props: {
startDate: number
dailyPercent: number[]
small?: boolean
}) {
const { dailyPercent, startDate, small } = props
const { width } = useWindowSize()
const dates = dailyPercent.map((_, i) =>
dayjs(startDate).add(i, 'day').toDate()
)
const points = zip(dates, dailyPercent).map(([date, percent]) => ({
2022-03-22 21:24:26 +00:00
x: date,
y: percent,
2022-03-22 21:24:26 +00:00
}))
const data = [{ id: 'Percent', data: points, color: '#11b981' }]
const bottomAxisTicks = width && width < 600 ? 6 : undefined
2022-03-22 21:24:26 +00:00
return (
<div
className={clsx(
'h-[250px] w-full overflow-hidden',
!small && 'md:h-[400px]'
)}
2022-03-22 21:24:26 +00:00
>
<ResponsiveLine
data={data}
yScale={{ type: 'linear', stacked: false }}
xScale={{
type: 'time',
}}
axisLeft={{
format: formatPercent,
2022-03-22 21:24:26 +00:00
}}
axisBottom={{
tickValues: bottomAxisTicks,
2022-03-22 21:24:26 +00:00
format: (date) => dayjs(date).format('MMM DD'),
}}
colors={{ datum: 'color' }}
pointSize={0}
pointBorderWidth={1}
pointBorderColor="#fff"
enableSlices="x"
enableGridX={!!width && width >= 800}
enableArea
margin={{ top: 20, right: 28, bottom: 22, left: 40 }}
2022-05-19 20:14:13 +00:00
sliceTooltip={({ slice }) => {
const point = slice.points[0]
return <Tooltip point={point} isPercent />
2022-05-19 20:14:13 +00:00
}}
2022-03-22 21:24:26 +00:00
/>
</div>
)
}
2022-05-19 20:14:13 +00:00
function Tooltip(props: { point: Point; isPercent?: boolean }) {
const { point, isPercent } = props
2022-05-19 20:14:13 +00:00
return (
<Col className="border border-gray-300 bg-white py-2 px-3">
2022-05-19 20:14:13 +00:00
<div
className="pb-1"
2022-05-19 20:14:13 +00:00
style={{
color: point.serieColor,
}}
>
<strong>{point.serieId}</strong>{' '}
{isPercent ? formatPercent(+point.data.y) : point.data.yFormatted}
2022-05-19 20:14:13 +00:00
</div>
<div>{dayjs(point.data.x).format('MMM DD')}</div>
</Col>
)
}