Skip to content

Commit

Permalink
feat: display the time-to-type a character histogram
Browse files Browse the repository at this point in the history
  • Loading branch information
aradzie committed Nov 6, 2024
1 parent a6cf7ca commit c364dcc
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 0 deletions.
87 changes: 87 additions & 0 deletions packages/keybr-chart/lib/TimeToTypeHistogram.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { useFormatter } from "@keybr/lesson-ui";
import { Range, Vector } from "@keybr/math";
import { timeToSpeed } from "@keybr/result";
import { Canvas, type Rect, type ShapeList, Shapes } from "@keybr/widget";
import { type ReactNode } from "react";
import { Chart, chartArea, type SizeProps } from "./Chart.tsx";
import { withStyles } from "./decoration.ts";
import { bucketize } from "./dist/util.ts";
import { type TimeToType } from "./types.ts";
import { type ChartStyles, useChartStyles } from "./use-chart-styles.ts";

export function TimeToTypeHistogram({
steps,
width,
height,
}: {
readonly steps: readonly TimeToType[];
} & SizeProps): ReactNode {
const styles = useChartStyles();
const paint = usePaint(styles, steps);
return (
<Chart width={width} height={height}>
<Canvas paint={chartArea(styles, paint)} />
</Chart>
);
}

function usePaint(styles: ChartStyles, steps: readonly TimeToType[]) {
const { formatSpeed } = useFormatter();
const g = withStyles(styles);

const histogram = buildHistogram(steps);

const vIndex = new Vector();
const vValue = new Vector();
for (let index = 0; index < histogram.length; index++) {
vIndex.add(index);
vValue.add(histogram[index]);
}
const rIndex = Range.from(vIndex);
const rValue = Range.from(vValue);

return (box: Rect): ShapeList => {
return [
g.paintGrid(box, "vertical", { lines: 5 }),
g.paintGrid(box, "horizontal", { lines: 5 }),
paintHistogram(),
g.paintAxis(box, "bottom"),
g.paintAxis(box, "left"),
g.paintTicks(box, rIndex, "bottom", {
lines: 5,
fmt: formatSpeed,
style: styles.valueLabel,
}),
];

function paintHistogram(): ShapeList {
return Shapes.fill(
styles.speed,
[...rIndex.steps()].map((index) => {
const w = Math.ceil(box.width / rIndex.span);
const x = Math.round(rIndex.normalize(index, 1) * box.width);
const y = Math.round(rValue.normalize(vValue.at(index)) * box.height);
return Shapes.rect({
x: box.x + x,
y: box.y + box.height - y,
width: w,
height: y,
});
}),
);
}
};
}

function buildHistogram(steps: readonly TimeToType[]) {
const histogram = new Array(1501).fill(0);
for (const { timeToType } of steps) {
if (timeToType > 0) {
const index = Math.round(timeToSpeed(timeToType));
if (index >= 0 && index < histogram.length) {
histogram[index] += 1;
}
}
}
return bucketize(histogram, 30);
}
1 change: 1 addition & 0 deletions packages/keybr-chart/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export * from "./Marker.tsx";
export * from "./ProgressOverviewChart.tsx";
export * from "./SpeedChart.tsx";
export * from "./SpeedHistogram.tsx";
export * from "./TimeToTypeHistogram.tsx";
export * from "./types.ts";
2 changes: 2 additions & 0 deletions packages/keybr-chart/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export type Threshold = {
readonly label: string;
readonly value: number;
};

export type TimeToType = { readonly timeToType: number };
11 changes: 11 additions & 0 deletions packages/page-typing-test/lib/components/Report.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
makeAccuracyDistribution,
makeSpeedDistribution,
SpeedHistogram,
TimeToTypeHistogram,
} from "@keybr/chart";
import { useIntlNumbers } from "@keybr/intl";
import { useFormatter } from "@keybr/lesson-ui";
Expand Down Expand Up @@ -118,6 +119,16 @@ export const Report = memo(function Report({
</Name>
</Para>

<Box alignItems="center" justifyContent="center">
<TimeToTypeHistogram
steps={result.steps}
width="45rem"
height="15rem"
/>
</Box>

<Para align="center">Time to type a character histogram.</Para>

<Spacer size={3} />

<Replay settings={settings} result={result} />
Expand Down

0 comments on commit c364dcc

Please sign in to comment.