state election map
This commit is contained in:
parent
2f25093a51
commit
72a2c86012
63
web/components/usa-map/state-election-map.tsx
Normal file
63
web/components/usa-map/state-election-map.tsx
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { zip } from 'lodash'
|
||||||
|
import Router from 'next/router'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import { getProbability } from 'common/calculate'
|
||||||
|
import { Contract, CPMMBinaryContract } from 'common/contract'
|
||||||
|
import { Customize, USAMap } from './usa-map'
|
||||||
|
import { getContractFromSlug } from 'web/lib/firebase/contracts'
|
||||||
|
|
||||||
|
export interface StateElectionMarket {
|
||||||
|
creatorUsername: string
|
||||||
|
slug: string
|
||||||
|
isWinRepublican: boolean
|
||||||
|
state: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StateElectionMap(props: { markets: StateElectionMarket[] }) {
|
||||||
|
const { markets } = props
|
||||||
|
|
||||||
|
const contracts = useContracts(markets.map((m) => m.slug))
|
||||||
|
const probs = contracts.map((c) =>
|
||||||
|
c ? getProbability(c as CPMMBinaryContract) : 0.5
|
||||||
|
)
|
||||||
|
const marketsWithProbs = zip(markets, probs) as [
|
||||||
|
StateElectionMarket,
|
||||||
|
number
|
||||||
|
][]
|
||||||
|
|
||||||
|
const stateInfo = marketsWithProbs.map(([market, prob]) => [
|
||||||
|
market.state,
|
||||||
|
{
|
||||||
|
fill: probToColor(prob, market.isWinRepublican),
|
||||||
|
clickHandler: () =>
|
||||||
|
Router.push(`/${market.creatorUsername}/${market.slug}`),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const config = Object.fromEntries(stateInfo) as Customize
|
||||||
|
|
||||||
|
return <USAMap customize={config} />
|
||||||
|
}
|
||||||
|
|
||||||
|
const probToColor = (prob: number, isWinRepublican: boolean) => {
|
||||||
|
const p = isWinRepublican ? prob : 1 - prob
|
||||||
|
const hue = p > 0.5 ? 350 : 240
|
||||||
|
const saturation = 100
|
||||||
|
const lightness = 100 - 50 * Math.abs(p - 0.5)
|
||||||
|
return `hsl(${hue}, ${saturation}%, ${lightness}%)`
|
||||||
|
}
|
||||||
|
|
||||||
|
const useContracts = (slugs: string[]) => {
|
||||||
|
const [contracts, setContracts] = useState<(Contract | undefined)[]>(
|
||||||
|
slugs.map(() => undefined)
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Promise.all(slugs.map((slug) => getContractFromSlug(slug))).then(
|
||||||
|
(contracts) => setContracts(contracts)
|
||||||
|
)
|
||||||
|
}, [slugs])
|
||||||
|
|
||||||
|
return contracts
|
||||||
|
}
|
|
@ -64,8 +64,7 @@ export const USAMap = ({
|
||||||
|
|
||||||
const stateClickHandler = (state: string) =>
|
const stateClickHandler = (state: string) =>
|
||||||
customize?.[state]?.clickHandler
|
customize?.[state]?.clickHandler
|
||||||
? (customize[state].clickHandler as ClickHandler)
|
|
||||||
: onClick
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
import clsx from 'clsx'
|
||||||
import { ClickHandler } from './usa-map'
|
import { ClickHandler } from './usa-map'
|
||||||
|
|
||||||
type USAStateProps = {
|
type USAStateProps = {
|
||||||
state: string
|
state: string
|
||||||
dimensions: string
|
dimensions: string
|
||||||
fill: string
|
fill: string
|
||||||
onClickState: ClickHandler
|
onClickState?: ClickHandler
|
||||||
stateName: string
|
stateName: string
|
||||||
hideStateTitle?: boolean
|
hideStateTitle?: boolean
|
||||||
}
|
}
|
||||||
|
@ -21,14 +22,14 @@ export const USAState = ({
|
||||||
d={dimensions}
|
d={dimensions}
|
||||||
fill={fill}
|
fill={fill}
|
||||||
data-name={state}
|
data-name={state}
|
||||||
className={`${state} state hover:cursor-pointer hover:contrast-125`}
|
className={clsx(
|
||||||
|
!!onClickState && 'hover:cursor-pointer hover:contrast-125'
|
||||||
|
)}
|
||||||
onClick={onClickState}
|
onClick={onClickState}
|
||||||
id={state}
|
id={state}
|
||||||
>
|
>
|
||||||
<text>
|
<text>
|
||||||
<textPath xlinkHref={`#${state}`}>
|
<textPath xlinkHref={`#${state}`}>{stateName}</textPath>
|
||||||
{stateName}
|
|
||||||
</textPath>
|
|
||||||
</text>
|
</text>
|
||||||
{hideStateTitle ? null : <title>{stateName}</title>}
|
{hideStateTitle ? null : <title>{stateName}</title>}
|
||||||
</path>
|
</path>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user