feat: easier to read evolution

This commit is contained in:
TresAbhi committed 2023-06-29 18:39:59 +00:00
1 parent 90d4b76b31
commit e34a6c6e4b
8 files changed
+85 -90

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js';
export default { export default {
inProduction: true, inProduction: true,
inDevelopment: false, inDevelopment: true,
inPublic: true, inPublic: true,
command: addStatTypeSubCommandGroups( command: addStatTypeSubCommandGroups(
+1 -1
View File
@@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js';
export default { export default {
inProduction: true, inProduction: true,
inDevelopment: true, inDevelopment: false,
inPublic: true, inPublic: true,
command: addStatTypeSubCommandGroups( command: addStatTypeSubCommandGroups(
+3 -1
View File
@@ -1,16 +1,18 @@
import { blue, green, red } from '@radix-ui/colors'; import { blue, green, red, slateDark } from '@radix-ui/colors';
import { GRAPH_HEIGHT, GRAPH_WIDTH } from './Root.js'; import { GRAPH_HEIGHT, GRAPH_WIDTH } from './Root.js';
export enum LineColor { export enum LineColor {
Red, Red,
Green, Green,
Blue, Blue,
White,
} }
const LINE_COLORS = { const LINE_COLORS = {
[LineColor.Red]: red.red9, [LineColor.Red]: red.red9,
[LineColor.Green]: green.green9, [LineColor.Green]: green.green9,
[LineColor.Blue]: blue.blue9, [LineColor.Blue]: blue.blue9,
[LineColor.White]: slateDark.slate11,
}; };
export enum LineStyle { export enum LineStyle {
@@ -1,32 +1,34 @@
import { times } from 'lodash'; import { times } from 'lodash';
import { theme } from '../../../stitches.config.js'; import { theme } from '../../../stitches.config.js';
import { MarginProps } from './Root.js'; import { MarginProps as RootMarginProps } from './Root.js';
export enum VerticalMarginAlign { export enum MarginOrientation {
Left, Vertical,
Right, Horizontal,
} }
export interface VerticalMarginProps extends MarginProps { export interface MarginProps extends RootMarginProps {
verticalSeparations: number; verticalSeparations: number;
align?: VerticalMarginAlign; orientation?: MarginOrientation;
} }
export function VerticalMargin({ export function Margin({
verticalSeparations, verticalSeparations,
max, max,
min, min,
suffix, suffix,
align = VerticalMarginAlign.Left, precision = 0,
}: VerticalMarginProps) { orientation = MarginOrientation.Vertical,
}: MarginProps) {
const isVertical = orientation === MarginOrientation.Vertical;
return ( return (
<div <div
style={{ style={{
width: 32, paddingLeft: isVertical ? 0 : 64,
width: isVertical ? 48 : '100%',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: isVertical ? 'column' : 'row-reverse',
alignItems:
align === VerticalMarginAlign.Right ? 'flex-end' : 'flex-start',
justifyContent: 'space-between', justifyContent: 'space-between',
}} }}
> >
@@ -43,7 +45,7 @@ export function VerticalMargin({
((verticalSeparations - (index + 1)) / ((verticalSeparations - (index + 1)) /
(verticalSeparations - 1)) + (verticalSeparations - 1)) +
min min
).toFixed(0)}${suffix ?? ''}`} ).toFixed(precision)}${suffix ?? ''}`}
</span> </span>
))} ))}
</div> </div>
+35 -38
View File
@@ -1,42 +1,55 @@
import { times } from 'lodash'; import { times } from 'lodash';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { theme } from '../../../stitches.config.js'; import { theme } from '../../../stitches.config.js';
import { VerticalMargin, VerticalMarginAlign } from './VerticalMargin.js'; import { Margin, MarginOrientation } from './Margin.js';
export const GRAPH_WIDTH = 512; export const GRAPH_WIDTH = 544;
export const GRAPH_HEIGHT = 320; export const GRAPH_HEIGHT = 320;
export interface MarginProps { export interface MarginProps {
min: number; min: number;
max: number; max: number;
suffix?: string; suffix?: string;
precision?: number;
} }
export interface RootProps { export interface RootProps {
children: ReactNode; children: ReactNode;
leftVerticalMargin?: MarginProps; verticalMargin?: MarginProps;
rightVerticalMargin?: MarginProps; horizontalMargin?: MarginProps;
verticalSeparations?: number; separations?: number;
xMinLabel: string; xMinLabel: string;
xMaxLabel: string; xMaxLabel: string;
} }
export function Root({ export function Root({
children, children,
leftVerticalMargin, verticalMargin,
rightVerticalMargin, horizontalMargin,
verticalSeparations = 5, separations = 5,
xMinLabel, xMinLabel,
xMaxLabel, xMaxLabel,
}: RootProps) { }: RootProps) {
return ( return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}> <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div
style={{
paddingLeft: 64,
display: 'flex',
justifyContent: 'space-between',
}}
>
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
{xMinLabel}
</span>
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
{xMaxLabel}
</span>
</div>
<div style={{ display: 'flex', gap: 16 }}> <div style={{ display: 'flex', gap: 16 }}>
{leftVerticalMargin && ( {verticalMargin && (
<VerticalMargin <Margin {...verticalMargin} verticalSeparations={separations} />
{...leftVerticalMargin}
verticalSeparations={verticalSeparations}
/>
)} )}
<svg <svg
@@ -49,8 +62,8 @@ export function Root({
border: theme.borderStyles.nonInteractive, border: theme.borderStyles.nonInteractive,
}} }}
> >
{times(verticalSeparations - 2, (index) => { {times(separations - 2, (index) => {
const y = GRAPH_HEIGHT * ((index + 1) / (verticalSeparations - 1)); const y = GRAPH_HEIGHT * ((index + 1) / (separations - 1));
return ( return (
<polyline <polyline
@@ -66,31 +79,15 @@ export function Root({
{children} {children}
</svg> </svg>
{rightVerticalMargin && (
<VerticalMargin
{...rightVerticalMargin}
verticalSeparations={verticalSeparations}
align={VerticalMarginAlign.Right}
/>
)}
</div> </div>
<div {horizontalMargin && (
style={{ <Margin
paddingLeft: 48, {...horizontalMargin}
paddingRight: 48, verticalSeparations={separations}
display: 'flex', orientation={MarginOrientation.Horizontal}
justifyContent: 'space-between', />
}} )}
>
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
{xMinLabel}
</span>
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
{xMaxLabel}
</span>
</div>
</div> </div>
); );
} }
+1 -1
View File
@@ -1,3 +1,3 @@
export * from './components/Line.js'; export * from './components/Line.js';
export * from './components/Margin.js';
export * from './components/Root.js'; export * from './components/Root.js';
export * from './components/VerticalMargin.js';
+27 -33
View File
@@ -61,24 +61,22 @@ export default async function evolution<Type extends StatType>(
}); });
} }
const careerWinrate = histories.map( const plot = histories.map(
(history) => (history) =>
[ [
history.last_battle_time, history.all.battles,
(history.all.wins / history.all.battles) * 100, (history.all.wins / history.all.battles) * 100,
] as Graph.PlotItem, ] as Graph.PlotItem,
); );
const careerBattles = histories.map( const times = histories.map((history) => history.last_battle_time);
(history) => const minTime = Math.min(...times);
[history.last_battle_time, history.all.battles] as Graph.PlotItem, const maxTime = Math.max(...times);
); const ys = plot.map(([, y]) => y);
const winrateYs = careerWinrate.map(([, y]) => y); const xs = plot.map(([x]) => x);
const maxWinrate = Math.max(...winrateYs); const maxY = Math.max(...ys);
const minWinrate = Math.min(...winrateYs); const minY = Math.min(...ys);
const battleYs = careerBattles.map(([, y]) => y); const maxX = Math.max(...xs);
const maxBattle = Math.max(...battleYs); const minX = Math.min(...xs);
const minBattle = Math.min(...battleYs);
const minTime = Math.min(...careerBattles.map(([x]) => x));
const accountInfo = await getWargamingResponse<AccountInfo>( const accountInfo = await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`,
@@ -96,37 +94,33 @@ export default async function evolution<Type extends StatType>(
/> />
{/* goofy ahh bug forces me to call them as functions */} {/* goofy ahh bug forces me to call them as functions */}
{careerWinrate.length > 0 && ( {plot.length > 0 && (
<Graph.Root <Graph.Root
xMinLabel={new Date(minTime * 1000).toDateString()} verticalMargin={{
xMaxLabel={new Date(end * 1000).toDateString()} min: minY,
leftVerticalMargin={{ max: maxY,
min: minWinrate,
max: maxWinrate,
suffix: '%', suffix: '%',
precision: 1,
}} }}
rightVerticalMargin={{ horizontalMargin={{
min: minBattle, min: minX,
max: maxBattle, max: maxX,
precision: 0,
}} }}
xMinLabel={new Date(minTime * 1000).toDateString()}
xMaxLabel={new Date(maxTime * 1000).toDateString()}
> >
{Graph.Line({
// total battles
plot: careerBattles!,
color: Graph.LineColor.Blue,
})}
{Graph.Line({ {Graph.Line({
// career winrate // career winrate
plot: careerWinrate!, color: Graph.LineColor.Red,
minY: minWinrate, plot: plot,
maxY: maxWinrate, minY,
maxY,
})} })}
</Graph.Root> </Graph.Root>
)} )}
{careerWinrate.length === 0 && ( {plot.length === 0 && <NoData type={NoDataType.BattlesInPeriod} />}
<NoData type={NoDataType.BattlesInPeriod} />
)}
<PoweredBy type={PoweredByType.BlitzStars} /> <PoweredBy type={PoweredByType.BlitzStars} />
</Wrapper> </Wrapper>
+1 -1
View File
@@ -6,7 +6,7 @@ import { RouteRegistry } from '../server.js';
export default { export default {
route: '/stats/:type/:period', route: '/stats/:type/:period',
inProduction: true, inProduction: true,
inDevelopment: true, inDevelopment: false,
async handler(req) { async handler(req) {
const type = req.params.type as StatType; const type = req.params.type as StatType;