Clean up chart sizing code (#977)
* Clean up chart sizing code * Do all the chart sizing work in same batch
This commit is contained in:
parent
38b7c898f6
commit
89e26d077e
|
@ -1,4 +1,4 @@
|
|||
import { useMemo, useRef } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { last, sortBy } from 'lodash'
|
||||
import { scaleTime, scaleLinear } from 'd3-scale'
|
||||
|
||||
|
@ -6,7 +6,6 @@ import { Bet } from 'common/bet'
|
|||
import { getProbability, getInitialProbability } from 'common/calculate'
|
||||
import { BinaryContract } from 'common/contract'
|
||||
import { DAY_MS } from 'common/util/time'
|
||||
import { useIsMobile } from 'web/hooks/use-is-mobile'
|
||||
import {
|
||||
TooltipProps,
|
||||
MARGIN_X,
|
||||
|
@ -17,7 +16,6 @@ import {
|
|||
formatPct,
|
||||
} from '../helpers'
|
||||
import { HistoryPoint, SingleValueHistoryChart } from '../generic-charts'
|
||||
import { useElementWidth } from 'web/hooks/use-element-width'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Avatar } from 'web/components/avatar'
|
||||
|
||||
|
@ -45,10 +43,11 @@ const BinaryChartTooltip = (props: TooltipProps<Date, HistoryPoint<Bet>>) => {
|
|||
export const BinaryContractChart = (props: {
|
||||
contract: BinaryContract
|
||||
bets: Bet[]
|
||||
height?: number
|
||||
width: number
|
||||
height: number
|
||||
onMouseOver?: (p: HistoryPoint<Bet> | undefined) => void
|
||||
}) => {
|
||||
const { contract, bets, onMouseOver } = props
|
||||
const { contract, bets, width, height, onMouseOver } = props
|
||||
const [start, end] = getDateRange(contract)
|
||||
const startP = getInitialProbability(contract)
|
||||
const endP = getProbability(contract)
|
||||
|
@ -67,28 +66,19 @@ export const BinaryContractChart = (props: {
|
|||
Date.now()
|
||||
)
|
||||
const visibleRange = [start, rightmostDate]
|
||||
const isMobile = useIsMobile(800)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const width = useElementWidth(containerRef) ?? 0
|
||||
const height = props.height ?? (isMobile ? 150 : 250)
|
||||
const xScale = scaleTime(visibleRange, [0, width - MARGIN_X])
|
||||
const yScale = scaleLinear([0, 1], [height - MARGIN_Y, 0])
|
||||
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
{width > 0 && (
|
||||
<SingleValueHistoryChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={xScale}
|
||||
yScale={yScale}
|
||||
data={data}
|
||||
color="#11b981"
|
||||
onMouseOver={onMouseOver}
|
||||
Tooltip={BinaryChartTooltip}
|
||||
pct
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<SingleValueHistoryChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={xScale}
|
||||
yScale={yScale}
|
||||
data={data}
|
||||
color="#11b981"
|
||||
onMouseOver={onMouseOver}
|
||||
Tooltip={BinaryChartTooltip}
|
||||
pct
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useMemo, useRef } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { last, sum, sortBy, groupBy } from 'lodash'
|
||||
import { scaleTime, scaleLinear } from 'd3-scale'
|
||||
|
||||
|
@ -6,7 +6,6 @@ import { Bet } from 'common/bet'
|
|||
import { Answer } from 'common/answer'
|
||||
import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
|
||||
import { getOutcomeProbability } from 'common/calculate'
|
||||
import { useIsMobile } from 'web/hooks/use-is-mobile'
|
||||
import { DAY_MS } from 'common/util/time'
|
||||
import {
|
||||
TooltipProps,
|
||||
|
@ -18,7 +17,6 @@ import {
|
|||
formatDateInRange,
|
||||
} from '../helpers'
|
||||
import { MultiPoint, MultiValueHistoryChart } from '../generic-charts'
|
||||
import { useElementWidth } from 'web/hooks/use-element-width'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Avatar } from 'web/components/avatar'
|
||||
|
||||
|
@ -146,10 +144,11 @@ const Legend = (props: { className?: string; items: LegendItem[] }) => {
|
|||
export const ChoiceContractChart = (props: {
|
||||
contract: FreeResponseContract | MultipleChoiceContract
|
||||
bets: Bet[]
|
||||
height?: number
|
||||
width: number
|
||||
height: number
|
||||
onMouseOver?: (p: MultiPoint<Bet> | undefined) => void
|
||||
}) => {
|
||||
const { contract, bets, onMouseOver } = props
|
||||
const { contract, bets, width, height, onMouseOver } = props
|
||||
const [start, end] = getDateRange(contract)
|
||||
const answers = useMemo(
|
||||
() => getTrackedAnswers(contract, CATEGORY_COLORS.length),
|
||||
|
@ -173,10 +172,6 @@ export const ChoiceContractChart = (props: {
|
|||
Date.now()
|
||||
)
|
||||
const visibleRange = [start, rightmostDate]
|
||||
const isMobile = useIsMobile(800)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const width = useElementWidth(containerRef) ?? 0
|
||||
const height = props.height ?? (isMobile ? 250 : 350)
|
||||
const xScale = scaleTime(visibleRange, [0, width - MARGIN_X])
|
||||
const yScale = scaleLinear([0, 1], [height - MARGIN_Y, 0])
|
||||
|
||||
|
@ -212,20 +207,16 @@ export const ChoiceContractChart = (props: {
|
|||
)
|
||||
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
{width > 0 && (
|
||||
<MultiValueHistoryChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={xScale}
|
||||
yScale={yScale}
|
||||
data={data}
|
||||
colors={CATEGORY_COLORS}
|
||||
onMouseOver={onMouseOver}
|
||||
Tooltip={ChoiceTooltip}
|
||||
pct
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<MultiValueHistoryChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={xScale}
|
||||
yScale={yScale}
|
||||
data={data}
|
||||
colors={CATEGORY_COLORS}
|
||||
onMouseOver={onMouseOver}
|
||||
Tooltip={ChoiceTooltip}
|
||||
pct
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ import { NumericContractChart } from './numeric'
|
|||
export const ContractChart = (props: {
|
||||
contract: Contract
|
||||
bets: Bet[]
|
||||
height?: number
|
||||
width: number
|
||||
height: number
|
||||
}) => {
|
||||
const { contract } = props
|
||||
switch (contract.outcomeType) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useMemo, useRef } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { range } from 'lodash'
|
||||
import { scaleLinear } from 'd3-scale'
|
||||
|
||||
|
@ -6,10 +6,8 @@ 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
|
||||
|
@ -36,33 +34,26 @@ const NumericChartTooltip = (
|
|||
|
||||
export const NumericContractChart = (props: {
|
||||
contract: NumericContract
|
||||
height?: number
|
||||
width: number
|
||||
height: number
|
||||
onMouseOver?: (p: DistributionPoint | undefined) => void
|
||||
}) => {
|
||||
const { contract, onMouseOver } = props
|
||||
const { contract, width, height, 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>
|
||||
<DistributionChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={xScale}
|
||||
yScale={yScale}
|
||||
data={data}
|
||||
color={NUMERIC_GRAPH_COLOR}
|
||||
onMouseOver={onMouseOver}
|
||||
Tooltip={NumericChartTooltip}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useMemo, useRef } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { last, sortBy } from 'lodash'
|
||||
import { scaleTime, scaleLog, scaleLinear } from 'd3-scale'
|
||||
|
||||
|
@ -8,7 +8,6 @@ import { getInitialProbability, getProbability } from 'common/calculate'
|
|||
import { formatLargeNumber } from 'common/util/format'
|
||||
import { PseudoNumericContract } from 'common/contract'
|
||||
import { NUMERIC_GRAPH_COLOR } from 'common/numeric-constants'
|
||||
import { useIsMobile } from 'web/hooks/use-is-mobile'
|
||||
import {
|
||||
TooltipProps,
|
||||
MARGIN_X,
|
||||
|
@ -18,7 +17,6 @@ import {
|
|||
formatDateInRange,
|
||||
} from '../helpers'
|
||||
import { HistoryPoint, SingleValueHistoryChart } from '../generic-charts'
|
||||
import { useElementWidth } from 'web/hooks/use-element-width'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Avatar } from 'web/components/avatar'
|
||||
|
||||
|
@ -59,10 +57,11 @@ const PseudoNumericChartTooltip = (
|
|||
export const PseudoNumericContractChart = (props: {
|
||||
contract: PseudoNumericContract
|
||||
bets: Bet[]
|
||||
height?: number
|
||||
width: number
|
||||
height: number
|
||||
onMouseOver?: (p: HistoryPoint<Bet> | undefined) => void
|
||||
}) => {
|
||||
const { contract, bets, onMouseOver } = props
|
||||
const { contract, bets, width, height, onMouseOver } = props
|
||||
const { min, max, isLogScale } = contract
|
||||
const [start, end] = getDateRange(contract)
|
||||
const scaleP = useMemo(
|
||||
|
@ -86,30 +85,21 @@ export const PseudoNumericContractChart = (props: {
|
|||
Date.now()
|
||||
)
|
||||
const visibleRange = [start, rightmostDate]
|
||||
const isMobile = useIsMobile(800)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const width = useElementWidth(containerRef) ?? 0
|
||||
const height = props.height ?? (isMobile ? 150 : 250)
|
||||
const xScale = scaleTime(visibleRange, [0, width - MARGIN_X])
|
||||
const xScale = scaleTime(visibleRange, [0, width ?? 0 - MARGIN_X])
|
||||
// clamp log scale to make sure zeroes go to the bottom
|
||||
const yScale = isLogScale
|
||||
? scaleLog([Math.max(min, 1), max], [height - MARGIN_Y, 0]).clamp(true)
|
||||
: scaleLinear([min, max], [height - MARGIN_Y, 0])
|
||||
|
||||
? scaleLog([Math.max(min, 1), max], [height ?? 0 - MARGIN_Y, 0]).clamp(true)
|
||||
: scaleLinear([min, max], [height ?? 0 - MARGIN_Y, 0])
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
{width > 0 && (
|
||||
<SingleValueHistoryChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={xScale}
|
||||
yScale={yScale}
|
||||
data={data}
|
||||
onMouseOver={onMouseOver}
|
||||
Tooltip={PseudoNumericChartTooltip}
|
||||
color={NUMERIC_GRAPH_COLOR}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<SingleValueHistoryChart
|
||||
w={width}
|
||||
h={height}
|
||||
xScale={xScale}
|
||||
yScale={yScale}
|
||||
data={data}
|
||||
onMouseOver={onMouseOver}
|
||||
Tooltip={PseudoNumericChartTooltip}
|
||||
color={NUMERIC_GRAPH_COLOR}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
import React from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { tradingAllowed } from 'web/lib/firebase/contracts'
|
||||
import { Col } from '../layout/col'
|
||||
import {
|
||||
BinaryContractChart,
|
||||
NumericContractChart,
|
||||
PseudoNumericContractChart,
|
||||
ChoiceContractChart,
|
||||
} from 'web/components/charts/contract'
|
||||
import { ContractChart } from 'web/components/charts/contract'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { Row } from '../layout/row'
|
||||
import { Linkify } from '../linkify'
|
||||
|
@ -48,8 +43,43 @@ const BetWidget = (props: { contract: CPMMContract }) => {
|
|||
)
|
||||
}
|
||||
|
||||
const NumericOverview = (props: { contract: NumericContract }) => {
|
||||
const { contract } = props
|
||||
const SizedContractChart = (props: {
|
||||
contract: Contract
|
||||
bets: Bet[]
|
||||
fullHeight: number
|
||||
mobileHeight: number
|
||||
}) => {
|
||||
const { contract, bets, fullHeight, mobileHeight } = props
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const [chartWidth, setChartWidth] = useState<number>()
|
||||
const [chartHeight, setChartHeight] = useState<number>()
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setChartHeight(window.innerWidth < 800 ? mobileHeight : fullHeight)
|
||||
setChartWidth(containerRef.current?.clientWidth)
|
||||
}
|
||||
handleResize()
|
||||
window.addEventListener('resize', handleResize)
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
}
|
||||
}, [fullHeight, mobileHeight])
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
{chartWidth != null && chartHeight != null && (
|
||||
<ContractChart
|
||||
contract={contract}
|
||||
bets={bets}
|
||||
width={chartWidth}
|
||||
height={chartHeight}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const NumericOverview = (props: { contract: NumericContract; bets: Bet[] }) => {
|
||||
const { contract, bets } = props
|
||||
return (
|
||||
<Col className="gap-1 md:gap-2">
|
||||
<Col className="gap-3 px-2 sm:gap-4">
|
||||
|
@ -66,7 +96,12 @@ const NumericOverview = (props: { contract: NumericContract }) => {
|
|||
contract={contract}
|
||||
/>
|
||||
</Col>
|
||||
<NumericContractChart contract={contract} />
|
||||
<SizedContractChart
|
||||
contract={contract}
|
||||
bets={bets}
|
||||
fullHeight={250}
|
||||
mobileHeight={150}
|
||||
/>
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
@ -86,7 +121,12 @@ const BinaryOverview = (props: { contract: BinaryContract; bets: Bet[] }) => {
|
|||
/>
|
||||
</Row>
|
||||
</Col>
|
||||
<BinaryContractChart contract={contract} bets={bets} />
|
||||
<SizedContractChart
|
||||
contract={contract}
|
||||
bets={bets}
|
||||
fullHeight={250}
|
||||
mobileHeight={150}
|
||||
/>
|
||||
<Row className="items-center justify-between gap-4 xl:hidden">
|
||||
{tradingAllowed(contract) && (
|
||||
<BinaryMobileBetting contract={contract} />
|
||||
|
@ -111,9 +151,12 @@ const ChoiceOverview = (props: {
|
|||
<FreeResponseResolutionOrChance contract={contract} truncate="none" />
|
||||
)}
|
||||
</Col>
|
||||
<Col className={'mb-1 gap-y-2'}>
|
||||
<ChoiceContractChart contract={contract} bets={bets} />
|
||||
</Col>
|
||||
<SizedContractChart
|
||||
contract={contract}
|
||||
bets={bets}
|
||||
fullHeight={350}
|
||||
mobileHeight={250}
|
||||
/>
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
@ -139,7 +182,12 @@ const PseudoNumericOverview = (props: {
|
|||
{tradingAllowed(contract) && <BetWidget contract={contract} />}
|
||||
</Row>
|
||||
</Col>
|
||||
<PseudoNumericContractChart contract={contract} bets={bets} />
|
||||
<SizedContractChart
|
||||
contract={contract}
|
||||
bets={bets}
|
||||
fullHeight={250}
|
||||
mobileHeight={150}
|
||||
/>
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
@ -153,7 +201,7 @@ export const ContractOverview = (props: {
|
|||
case 'BINARY':
|
||||
return <BinaryOverview contract={contract} bets={bets} />
|
||||
case 'NUMERIC':
|
||||
return <NumericOverview contract={contract} />
|
||||
return <NumericOverview contract={contract} bets={bets} />
|
||||
case 'PSEUDO_NUMERIC':
|
||||
return <PseudoNumericOverview contract={contract} bets={bets} />
|
||||
case 'FREE_RESPONSE':
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import { RefObject, useState, useEffect } from 'react'
|
||||
|
||||
// todo: consider consolidation with use-measure-size
|
||||
export const useElementWidth = <T extends Element>(ref: RefObject<T>) => {
|
||||
const [width, setWidth] = useState<number>()
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setWidth(ref.current?.clientWidth)
|
||||
}
|
||||
handleResize()
|
||||
window.addEventListener('resize', handleResize)
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
}
|
||||
}, [ref])
|
||||
return width
|
||||
}
|
|
@ -79,7 +79,7 @@ export function ContractEmbed(props: { contract: Contract; bets: Bet[] }) {
|
|||
|
||||
const href = `https://${DOMAIN}${contractPath(contract)}`
|
||||
|
||||
const { setElem, height: graphHeight } = useMeasureSize()
|
||||
const { setElem, width: graphWidth, height: graphHeight } = useMeasureSize()
|
||||
|
||||
const [betPanelOpen, setBetPanelOpen] = useState(false)
|
||||
|
||||
|
@ -132,7 +132,14 @@ export function ContractEmbed(props: { contract: Contract; bets: Bet[] }) {
|
|||
)}
|
||||
|
||||
<div className="mx-1 mb-2 min-h-0 flex-1" ref={setElem}>
|
||||
<ContractChart contract={contract} bets={bets} height={graphHeight} />
|
||||
{graphWidth != null && graphHeight != null && (
|
||||
<ContractChart
|
||||
contract={contract}
|
||||
bets={bets}
|
||||
width={graphWidth}
|
||||
height={graphHeight}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Col>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user