Files
horse/zenno/src/lib/CourseChart.svelte
T
zephyr 04be0b75a9
ci/woodpecker/push/horsebot Pipeline failed
ci/woodpecker/push/zenno Pipeline was successful
zenno: lint fixes
2026-10-31 13:23:15 -04:00

85 lines
2.0 KiB
Svelte

<script lang="ts">
import * as Plot from '@observablehq/plot';
import type { Attachment } from 'svelte/attachments';
import type { ClassValue } from 'svelte/elements';
import * as race from '$lib/race';
import * as racecourse from '$lib/data/racecourse';
export interface DrawSpan {
fy: string;
x1: number;
x2: number;
color: string;
label?: string;
}
interface Props {
course: racecourse.Course;
title?: string;
class?: ClassValue | null;
plotOptions?: Omit<Plot.PlotOptions, 'marks' | 'x' | 'y'>;
draw: DrawSpan[];
}
let { course, title, class: className, plotOptions, draw }: Props = $props();
let width = $state(0);
let height = $state(0);
const phases = $derived(race.phases(course.distance));
const phaseX = $derived([
0,
phases[race.Phase.EarlyRace],
phases[race.Phase.MidRace],
phases[race.Phase.LateRace],
phases[race.Phase.LastSpurt],
]);
const sectionX = $derived([0, ...racecourse.SECTIONS.map((s) => course.distance * s.endRate)]);
const drawTitles = $derived(draw.map((d) => d.fy));
const makeChart: Attachment = (el) => {
$effect(() => {
el?.firstChild?.remove();
el?.append(
Plot.plot({
width: width,
height,
clip: true,
title,
marginLeft: 50,
x: {
domain: [0, course.distance],
ticks: phaseX,
},
fy: {
label: null,
padding: 0,
domain: drawTitles,
},
...plotOptions,
marks: [
Plot.barX(draw, {
x1: 'x1',
x2: 'x2',
fy: 'fy',
fill: 'color',
fillOpacity: 0.8,
title: 'label',
}),
Plot.text(draw, { x: 'x1', fy: 'fy', text: 'label', dx: 2, textAnchor: 'start', fontSize: 16, fill: 'black' }),
Plot.ruleX(sectionX, { opacity: 0.25 }),
Plot.ruleX([phases[0], phases[1]], { opacity: 0.5 }),
],
}),
);
});
};
</script>
<div bind:clientWidth={width} bind:clientHeight={height} class={['flex h-full w-full flex-col md:flex-row', className]}>
<div role="img" {@attach makeChart}>
<span>the chart seems to have didn't</span>
</div>
</div>