Add AreaWithTopStroke helper

This commit is contained in:
Marshall Polaris 2022-09-26 16:32:47 -07:00
parent 575740963c
commit dc14edad26
2 changed files with 44 additions and 34 deletions

View File

@ -15,7 +15,7 @@ import {
import { range } from 'lodash'
import dayjs from 'dayjs'
import { SVGChart, LinePath, AreaPath } from './helpers'
import { SVGChart, AreaPath, AreaWithTopStroke } from './helpers'
import { formatLargeNumber } from 'common/util/format'
import { useEvent } from 'web/hooks/use-event'
@ -90,21 +90,13 @@ export const SingleValueDistributionChart = (props: {
className="pointer-events-none absolute z-10 whitespace-pre rounded border-2 border-black bg-slate-600/75 p-2 text-white"
/>
<SVGChart w={w} h={h} xAxis={xAxis} yAxis={yAxis}>
<LinePath
<AreaWithTopStroke
color={color}
data={data}
curve={curveLinear}
px={px}
py={py1}
stroke={color}
/>
<AreaPath
data={data}
curve={curveLinear}
px={px}
py0={py0}
py1={py1}
fill={color}
opacity={0.3}
curve={curveLinear}
/>
</SVGChart>
</div>
@ -158,13 +150,6 @@ export const MultiValueHistoryChart = (props: {
<SVGChart w={w} h={h} xAxis={xAxis} yAxis={yAxis}>
{d3Stack(data).map((s, i) => (
<g key={s.key}>
<LinePath
data={s}
px={px}
py={py1}
curve={curveStepAfter}
stroke={colors[i]}
/>
<AreaPath
data={s}
px={px}
@ -246,21 +231,13 @@ export const SingleValueHistoryChart = (props: {
onMouseOver={onMouseOver}
onMouseLeave={onMouseLeave}
>
<LinePath
data={data}
px={px}
py={py1}
curve={curveStepAfter}
stroke={color}
/>
<AreaPath
<AreaWithTopStroke
color={color}
data={data}
px={px}
py0={py0}
py1={py1}
curve={curveStepAfter}
fill={color}
opacity={0.3}
/>
</SVGChart>
</div>

View File

@ -1,5 +1,13 @@
import { ReactNode, SVGProps, memo, useRef, useEffect } from 'react'
import { Axis, AxisDomain, CurveFactory, area, line, select } from 'd3'
import {
Axis,
AxisDomain,
CurveFactory,
area,
curveStepAfter,
line,
select,
} from 'd3'
import dayjs from 'dayjs'
import { Contract } from 'common/contract'
@ -50,11 +58,11 @@ const LinePathInternal = <P,>(
data: P[]
px: number | ((p: P) => number)
py: number | ((p: P) => number)
curve: CurveFactory
curve?: CurveFactory
} & SVGProps<SVGPathElement>
) => {
const { data, px, py, curve, ...rest } = props
const d3Line = line<P>(px, py).curve(curve)
const d3Line = line<P>(px, py).curve(curve ?? curveStepAfter)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return <path {...rest} fill="none" d={d3Line(data)!} />
}
@ -66,16 +74,41 @@ const AreaPathInternal = <P,>(
px: number | ((p: P) => number)
py0: number | ((p: P) => number)
py1: number | ((p: P) => number)
curve: CurveFactory
curve?: CurveFactory
} & SVGProps<SVGPathElement>
) => {
const { data, px, py0, py1, curve, ...rest } = props
const d3Area = area<P>(px, py0, py1).curve(curve)
const d3Area = area<P>(px, py0, py1).curve(curve ?? curveStepAfter)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return <path {...rest} d={d3Area(data)!} />
}
export const AreaPath = memo(AreaPathInternal) as typeof AreaPathInternal
export const AreaWithTopStroke = <P,>(props: {
color: string
data: P[]
px: number | ((p: P) => number)
py0: number | ((p: P) => number)
py1: number | ((p: P) => number)
curve?: CurveFactory
}) => {
const { color, data, px, py0, py1, curve } = props
return (
<g>
<AreaPath
data={data}
px={px}
py0={py0}
py1={py1}
curve={curve}
fill={color}
opacity={0.3}
/>
<LinePath data={data} px={px} py={py1} curve={curve} stroke={color} />
</g>
)
}
export const SVGChart = <X extends AxisDomain, Y extends AxisDomain>(props: {
children: ReactNode
w: number