manifold/web/components/charts/contract/numeric.tsx

66 lines
2.2 KiB
TypeScript

import { useMemo, useRef } from 'react'
import { range } from 'lodash'
import { scaleLinear } from 'd3-scale'
import { formatLargeNumber } from 'common/util/format'
import { getDpmOutcomeProbabilities } from 'common/calculate-dpm'
import { NumericContract } from 'common/contract'
import { NUMERIC_GRAPH_COLOR } from 'common/numeric-constants'
import { useIsMobile } from 'web/hooks/use-is-mobile'
import { TooltipProps, MARGIN_X, MARGIN_Y, formatPct } from '../helpers'
import { DistributionPoint, DistributionChart } from '../generic-charts'
import { useElementWidth } from 'web/hooks/use-element-width'
const getNumericChartData = (contract: NumericContract) => {
const { totalShares, bucketCount, min, max } = contract
const step = (max - min) / bucketCount
const bucketProbs = getDpmOutcomeProbabilities(totalShares)
return range(bucketCount).map((i) => ({
x: min + step * (i + 0.5),
y: bucketProbs[`${i}`],
}))
}
const NumericChartTooltip = (props: TooltipProps<DistributionPoint>) => {
const { x, y } = props.p
return (
<>
<span className="text-semibold">{formatLargeNumber(x)}</span>
<span className="text-greyscale-6">{formatPct(y, 2)}</span>
</>
)
}
export const NumericContractChart = (props: {
contract: NumericContract
height?: number
onMouseOver?: (p: DistributionPoint | undefined) => void
}) => {
const { contract, onMouseOver } = props
const { min, max } = contract
const data = useMemo(() => getNumericChartData(contract), [contract])
const isMobile = useIsMobile(800)
const containerRef = useRef<HTMLDivElement>(null)
const width = useElementWidth(containerRef) ?? 0
const height = props.height ?? (isMobile ? 150 : 250)
const maxY = Math.max(...data.map((d) => d.y))
const xScale = scaleLinear([min, max], [0, width - MARGIN_X])
const yScale = scaleLinear([0, maxY], [height - MARGIN_Y, 0])
return (
<div ref={containerRef}>
{width > 0 && (
<DistributionChart
w={width}
h={height}
xScale={xScale}
yScale={yScale}
data={data}
color={NUMERIC_GRAPH_COLOR}
onMouseOver={onMouseOver}
Tooltip={NumericChartTooltip}
/>
)}
</div>
)
}