getting color graphs

This commit is contained in:
ingawei 2022-09-23 12:08:41 -07:00
parent c15d5e9e91
commit f916f2bd74
2 changed files with 180 additions and 45 deletions

View File

@ -15,20 +15,90 @@ export const PortfolioValueGraph = memo(function PortfolioValueGraph(props: {
const { portfolioHistory, height, includeTime, mode } = props const { portfolioHistory, height, includeTime, mode } = props
const { width } = useWindowSize() const { width } = useWindowSize()
const points = portfolioHistory.map((p) => { function getPoints(line: 'value' | 'posProfit' | 'negProfit') {
const { timestamp, balance, investmentValue, totalDeposits } = p let points = portfolioHistory.map((p) => {
const value = balance + investmentValue const { timestamp, balance, investmentValue, totalDeposits } = p
const profit = value - totalDeposits const value = balance + investmentValue
const profit = value - totalDeposits
let posProfit = null
let negProfit = null
return { // const profit = value - totalDeposits
x: new Date(timestamp), if (profit < 0) {
y: mode === 'value' ? value : profit, negProfit = profit
} } else {
}) posProfit = profit
const data = [{ id: 'Value', data: points, color: '#11b981' }] }
return {
x: new Date(timestamp),
y:
line === 'value'
? value
: line === 'posProfit'
? posProfit
: negProfit,
}
})
return points
}
let data
if (mode === 'value') {
data = [{ id: 'value', data: getPoints('value'), color: '#4f46e5' }]
} else {
data = [
{
id: 'negProfit',
data: getPoints('negProfit'),
color: '#dc2626',
},
{
id: 'posProfit',
data: getPoints('posProfit'),
color: '#14b8a6',
},
]
}
const firstPoints = data[0].data
const numXTickValues = !width || width < 800 ? 2 : 5 const numXTickValues = !width || width < 800 ? 2 : 5
const numYTickValues = 4 const numYTickValues = 4
const endDate = last(points)?.x const endDate = last(firstPoints)?.x
const firstPointsY = firstPoints
.filter((p) => {
return p.y !== null
})
.map((p) => p.y)
// console.log(firstPointsY)
console.log(
'MIN: ',
mode === 'value'
? Math.min(...firstPointsY)
: Math.min(
...firstPointsY,
...data[1].data
.filter((p) => {
return p.y !== null
})
.map((p) => p.y)
),
'MAX: ',
mode === 'value'
? Math.max(...firstPointsY)
: Math.max(
...firstPointsY,
...data[1].data
.filter((p) => {
return p.y !== null
})
.map((p) => p.y)
)
)
return ( return (
<div <div
className="w-full overflow-hidden" className="w-full overflow-hidden"
@ -39,16 +109,37 @@ export const PortfolioValueGraph = memo(function PortfolioValueGraph(props: {
margin={{ top: 20, right: 28, bottom: 22, left: 60 }} margin={{ top: 20, right: 28, bottom: 22, left: 60 }}
xScale={{ xScale={{
type: 'time', type: 'time',
min: points[0]?.x, min: firstPoints[0]?.x,
max: endDate, max: endDate,
}} }}
yScale={{ yScale={{
type: 'linear', type: 'linear',
stacked: false, stacked: false,
min: Math.min(...points.map((p) => p.y)), min:
mode === 'value'
? Math.min(...firstPointsY)
: Math.min(
...firstPointsY,
...data[1].data
.filter((p) => {
return p.y !== null
})
.map((p) => p.y)
),
max:
mode === 'value'
? Math.max(...firstPointsY)
: Math.max(
...firstPointsY,
...data[1].data
.filter((p) => {
return p.y !== null
})
.map((p) => p.y)
),
}} }}
gridYValues={numYTickValues} gridYValues={numYTickValues}
curve="stepAfter" curve="linear"
enablePoints={false} enablePoints={false}
colors={{ datum: 'color' }} colors={{ datum: 'color' }}
axisBottom={{ axisBottom={{
@ -56,7 +147,7 @@ export const PortfolioValueGraph = memo(function PortfolioValueGraph(props: {
format: (time) => formatTime(+time, !!includeTime), format: (time) => formatTime(+time, !!includeTime),
}} }}
pointBorderColor="#fff" pointBorderColor="#fff"
pointSize={points.length > 100 ? 0 : 6} pointSize={firstPoints.length > 100 ? 0 : 6}
axisLeft={{ axisLeft={{
tickValues: numYTickValues, tickValues: numYTickValues,
format: (value) => formatMoney(value), format: (value) => formatMoney(value),
@ -66,6 +157,21 @@ export const PortfolioValueGraph = memo(function PortfolioValueGraph(props: {
enableSlices="x" enableSlices="x"
animate={false} animate={false}
yFormat={(value) => formatMoney(+value)} yFormat={(value) => formatMoney(+value)}
// defs={[
// {
// id: 'purpleGradient',
// type: 'linearGradient',
// colors: [
// { offset: 0, color: '#7c3aed' },
// {
// offset: 100,
// color: '#inherit',
// opacity: 0,
// },
// ],
// },
// ]}
enableArea={true}
></ResponsiveLine> ></ResponsiveLine>
</div> </div>
) )

View File

@ -4,6 +4,7 @@ import { last } from 'lodash'
import { memo, useRef, useState } from 'react' import { memo, useRef, useState } from 'react'
import { usePortfolioHistory } from 'web/hooks/use-portfolio-history' import { usePortfolioHistory } from 'web/hooks/use-portfolio-history'
import { Period } from 'web/lib/firebase/users' import { Period } from 'web/lib/firebase/users'
import { PillButton } from '../buttons/pill-button'
import { Col } from '../layout/col' import { Col } from '../layout/col'
import { Row } from '../layout/row' import { Row } from '../layout/row'
import { Spacer } from '../layout/spacer' import { Spacer } from '../layout/spacer'
@ -15,6 +16,7 @@ export const PortfolioValueSection = memo(
const [portfolioPeriod, setPortfolioPeriod] = useState<Period>('weekly') const [portfolioPeriod, setPortfolioPeriod] = useState<Period>('weekly')
const portfolioHistory = usePortfolioHistory(userId, portfolioPeriod) const portfolioHistory = usePortfolioHistory(userId, portfolioPeriod)
const [graphMode, setGraphMode] = useState<'profit' | 'value'>('profit')
// Remember the last defined portfolio history. // Remember the last defined portfolio history.
const portfolioRef = useRef(portfolioHistory) const portfolioRef = useRef(portfolioHistory)
@ -32,38 +34,34 @@ export const PortfolioValueSection = memo(
return ( return (
<> <>
<Row className="gap-8"> <Row className="justify-between">
<Col className="flex-1 justify-center"> <Row className="gap-4 sm:gap-8 ">
<div className="text-sm text-gray-500">Profit</div> <Col>
<div className="text-lg">{formatMoney(totalProfit)}</div> <div className="text-greyscale-4 text-xs sm:text-sm">
</Col> Portfolio value
{/* <select </div>
className="select select-bordered self-start" <div className="text-lg text-indigo-600 sm:text-xl">
value={portfolioPeriod} {formatMoney(totalValue)}
onChange={(e) => { </div>
setPortfolioPeriod(e.target.value as Period) </Col>
}} <Col>
> <div className="text-greyscale-4 text-xs sm:text-sm">Profit</div>
<option value="allTime">All time</option> <div
<option value="monthly">Last Month</option> className={clsx(
<option value="weekly">Last 7d</option> totalProfit > 0 ? 'text-green-500' : 'text-red-600',
<option value="daily">Last 24h</option> 'text-lg sm:text-xl'
</select> */} )}
>
{formatMoney(totalProfit)}
</div>
</Col>
</Row>
<GraphToggle setGraphMode={setGraphMode} graphMode={graphMode} />
</Row> </Row>
<PortfolioValueGraph <PortfolioValueGraph
portfolioHistory={currPortfolioHistory} portfolioHistory={currPortfolioHistory}
includeTime={portfolioPeriod == 'daily'} includeTime={true}
mode="profit" mode={graphMode}
/>
<Spacer h={8} />
<Col className="flex-1 justify-center">
<div className="text-sm text-gray-500">Portfolio value</div>
<div className="text-lg">{formatMoney(totalValue)}</div>
</Col>
<PortfolioValueGraph
portfolioHistory={currPortfolioHistory}
includeTime={portfolioPeriod == 'daily'}
mode="value"
/> />
<PortfolioPeriodSelection <PortfolioPeriodSelection
portfolioPeriod={portfolioPeriod} portfolioPeriod={portfolioPeriod}
@ -85,7 +83,7 @@ export function PortfolioPeriodSelection(props: {
const { setPortfolioPeriod, portfolioPeriod, className, selectClassName } = const { setPortfolioPeriod, portfolioPeriod, className, selectClassName } =
props props
return ( return (
<Row className={className}> <Row className={clsx(className, 'text-greyscale-4')}>
<button <button
className={clsx(portfolioPeriod === 'daily' ? selectClassName : '')} className={clsx(portfolioPeriod === 'daily' ? selectClassName : '')}
onClick={() => setPortfolioPeriod('daily' as Period)} onClick={() => setPortfolioPeriod('daily' as Period)}
@ -113,3 +111,34 @@ export function PortfolioPeriodSelection(props: {
</Row> </Row>
) )
} }
export function GraphToggle(props: {
setGraphMode: (mode: 'profit' | 'value') => void
graphMode: string
}) {
const { setGraphMode, graphMode } = props
return (
<Row className="relative mt-1 ml-1 items-center gap-1.5 sm:ml-0 sm:gap-2">
<PillButton
selected={graphMode === 'value'}
onSelect={() => {
setGraphMode('value')
}}
xs={true}
className="z-50"
>
Value
</PillButton>
<PillButton
selected={graphMode === 'profit'}
onSelect={() => {
setGraphMode('profit')
}}
xs={true}
className="z-50"
>
Profit
</PillButton>
</Row>
)
}