@runaid/lactate-curve 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +356 -0
- package/dist/index.cjs +1051 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +150 -0
- package/dist/index.d.ts +150 -0
- package/dist/index.js +1016 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/LactateCurveChart.tsx","../src/lib/generateLactateCurve.ts","../src/lib/chart-defaults.ts","../src/lib/projectMarkerToCurve.ts","../src/lib/resolveZones.ts","../src/lib/utils.ts","../src/components/ui/chart.tsx","../src/examples.tsx"],"sourcesContent":["import * as React from \"react\"\nimport {\n CartesianGrid,\n Label,\n Line,\n LineChart,\n ReferenceArea,\n ReferenceDot,\n ReferenceLine,\n XAxis,\n YAxis,\n} from \"recharts\"\n\nimport { generateLactateCurve } from \"../lib/generateLactateCurve\"\nimport { DEFAULT_THEME } from \"../lib/chart-defaults\"\nimport {\n projectIntensityToCurve,\n projectMarkerToCurve,\n} from \"../lib/projectMarkerToCurve\"\nimport { resolveZones } from \"../lib/resolveZones\"\nimport { cn } from \"../lib/utils\"\nimport type {\n LactateCurveChartProps,\n ProjectedRaceMarker,\n ThresholdKey,\n XAxisCompression,\n} from \"../types\"\nimport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n type ChartConfig,\n} from \"./ui/chart\"\n\nconst mergeTheme = (theme?: LactateCurveChartProps[\"theme\"]) => ({\n ...DEFAULT_THEME,\n ...theme,\n})\n\nconst formatNumber = (value: number, precision: number) =>\n value.toFixed(Math.max(0, precision))\n\nconst markerLabelStyle = (color: string, fontFamily: string) => ({\n fill: color,\n fontFamily,\n fontSize: 12,\n fontWeight: 600,\n})\n\nconst resolveCompressionEnd = (\n compression: XAxisCompression | undefined,\n values: {\n lt1: number\n lt2: number\n vo2max?: number\n },\n) => {\n if (!compression) return null\n const end = compression.endIntensity\n\n if (typeof end === \"number\") return end\n if (end === \"lt1\") return values.lt1\n if (end === \"lt2\") return values.lt2\n if (end === \"vo2max\") return values.vo2max ?? null\n return null\n}\n\nconst defaultThresholdLabel = (key: ThresholdKey) => {\n switch (key) {\n case \"lt1\":\n return \"LT1\"\n case \"lt2\":\n return \"LT2\"\n case \"vo2max\":\n return \"VO2max\"\n }\n}\n\nexport const LactateCurveChart = ({\n baselineLactate,\n lt1,\n lt2,\n vo2max,\n zones,\n raceMarkers,\n xAxisLabel = \"Intensity\",\n yAxisLabel = \"Blood lactate (mmol/L)\",\n xAxisPrecision = 1,\n yAxisPrecision = 1,\n showXAxisTicks = true,\n xAxisCompression,\n title = \"Approximate lactate curve\",\n description = \"A physiologically plausible lactate curve with thresholds, optional domains, and optional race markers.\",\n showThresholdLabels = true,\n showThresholdGuides = true,\n showThresholdCircles = true,\n showGrid = true,\n showLegend = true,\n thresholdAnnotations,\n theme,\n icon,\n labels,\n minIntensity,\n xAxisMax,\n maxIntensity,\n intensityStep,\n curveSamples = 96,\n height = 420,\n style,\n className,\n}: LactateCurveChartProps) => {\n const resolvedTheme = React.useMemo(() => mergeTheme(theme), [theme])\n const curve = React.useMemo(\n () =>\n generateLactateCurve({\n baselineLactate,\n lt1,\n lt2,\n vo2max,\n minIntensity,\n maxIntensity: xAxisMax ?? maxIntensity,\n intensityStep,\n samples: curveSamples,\n }),\n [\n baselineLactate,\n curveSamples,\n intensityStep,\n lt1,\n lt2,\n maxIntensity,\n minIntensity,\n vo2max,\n xAxisMax,\n ],\n )\n\n const resolvedZones = React.useMemo(\n () => (zones === null ? [] : resolveZones({ zones, curve })),\n [curve, zones],\n )\n\n const compression = React.useMemo(() => {\n const end = resolveCompressionEnd(xAxisCompression, {\n lt1: lt1.intensity,\n lt2: lt2.intensity,\n vo2max: vo2max?.intensity,\n })\n const scale = xAxisCompression?.scale ?? 0.42\n\n if (!end || end <= curve.domain.minIntensity || end >= curve.domain.maxIntensity) {\n return null\n }\n\n if (!(scale > 0 && scale < 1)) {\n return null\n }\n\n const transform = (value: number) => {\n if (value <= end) {\n return curve.domain.minIntensity + (value - curve.domain.minIntensity) * scale\n }\n\n return (\n curve.domain.minIntensity +\n (end - curve.domain.minIntensity) * scale +\n (value - end)\n )\n }\n\n const inverse = (value: number) => {\n const compressedEnd =\n curve.domain.minIntensity + (end - curve.domain.minIntensity) * scale\n\n if (value <= compressedEnd) {\n return curve.domain.minIntensity + (value - curve.domain.minIntensity) / scale\n }\n\n return end + (value - compressedEnd)\n }\n\n return {\n end,\n scale,\n transform,\n inverse,\n }\n }, [\n curve.domain.maxIntensity,\n curve.domain.minIntensity,\n lt1.intensity,\n lt2.intensity,\n vo2max?.intensity,\n xAxisCompression,\n ])\n\n const displayPoints = React.useMemo(\n () =>\n curve.points.map((point) => ({\n ...point,\n displayIntensity: compression?.transform(point.intensity) ?? point.intensity,\n })),\n [compression, curve.points],\n )\n\n const projectedMarkers = React.useMemo<ProjectedRaceMarker[]>(\n () => (raceMarkers ?? []).map((marker) => projectMarkerToCurve(marker, curve.points)),\n [curve.points, raceMarkers],\n )\n\n const chartConfig = React.useMemo<ChartConfig>(\n () => ({\n lactate: {\n label: labels?.curve ?? \"Lactate curve\",\n color: resolvedTheme.curveColor,\n },\n raceMarkers: {\n label: labels?.raceMarkers ?? \"Race intensities\",\n color: resolvedTheme.curveColor,\n },\n }),\n [labels?.curve, labels?.raceMarkers, resolvedTheme.curveColor],\n )\n\n const thresholdEntries = [\n { key: \"lt1\" as const, point: { ...lt1, ...projectIntensityToCurve(lt1.intensity, curve.points) } },\n { key: \"lt2\" as const, point: { ...lt2, ...projectIntensityToCurve(lt2.intensity, curve.points) } },\n vo2max\n ? {\n key: \"vo2max\" as const,\n point: { ...vo2max, ...projectIntensityToCurve(vo2max.intensity, curve.points) },\n }\n : null,\n ].filter(Boolean) as Array<{ key: ThresholdKey; point: { intensity: number; lactate: number } }>\n\n const displayDomain = React.useMemo(\n () => ({\n min: compression?.transform(curve.domain.minIntensity) ?? curve.domain.minIntensity,\n max: compression?.transform(curve.domain.maxIntensity) ?? curve.domain.maxIntensity,\n }),\n [compression, curve.domain.maxIntensity, curve.domain.minIntensity],\n )\n\n const toDisplayIntensity = React.useCallback(\n (value: number) => compression?.transform(value) ?? value,\n [compression],\n )\n\n const iconNode =\n typeof icon === \"function\"\n ? icon({\n width: 18,\n height: 18,\n viewBox: \"0 0 18 18\",\n })\n : icon\n\n return (\n <figure\n className={cn(className)}\n style={{\n margin: 0,\n color: resolvedTheme.labelColor,\n fontFamily: resolvedTheme.fontFamily,\n ...style,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 16,\n marginBottom: 16,\n }}\n >\n <figcaption>\n <div style={{ fontSize: 18, fontWeight: 700 }}>{title}</div>\n <div style={{ fontSize: 14, opacity: 0.78, marginTop: 4 }}>{description}</div>\n </figcaption>\n {iconNode ? <div aria-hidden=\"true\">{iconNode}</div> : null}\n </div>\n\n {showLegend ? (\n <div\n aria-label=\"Chart legend\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 14,\n flexWrap: \"wrap\",\n marginBottom: 12,\n fontSize: 12,\n color: resolvedTheme.labelColor,\n }}\n >\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 8 }}>\n <span\n aria-hidden=\"true\"\n style={{\n width: 24,\n height: 0,\n borderTop: `3px solid ${resolvedTheme.curveColor}`,\n borderRadius: 999,\n display: \"inline-block\",\n }}\n />\n {chartConfig.lactate.label}\n </span>\n {projectedMarkers.length ? (\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 8 }}>\n <span\n aria-hidden=\"true\"\n style={{\n width: 10,\n height: 10,\n borderRadius: 999,\n background: resolvedTheme.curveColor,\n display: \"inline-block\",\n }}\n />\n {chartConfig.raceMarkers.label}\n </span>\n ) : null}\n </div>\n ) : null}\n\n <ChartContainer\n config={chartConfig}\n height={height}\n className=\"lactate-curve-chart\"\n role=\"img\"\n aria-label={title}\n style={{\n background: resolvedTheme.backgroundColor,\n border: \"1px solid rgba(148, 163, 184, 0.22)\",\n borderRadius: 20,\n padding: 12,\n }}\n >\n <LineChart\n data={displayPoints}\n margin={{ top: 24, right: 28, bottom: 28, left: 14 }}\n >\n {showGrid ? (\n <CartesianGrid\n stroke={resolvedTheme.gridColor}\n strokeDasharray=\"3 3\"\n vertical={false}\n />\n ) : null}\n\n {resolvedZones.map((zone) => (\n <ReferenceArea\n key={`${zone.label}-${zone.startIntensity}-${zone.endIntensity}`}\n x1={toDisplayIntensity(zone.startIntensity)}\n x2={toDisplayIntensity(zone.endIntensity)}\n fill={zone.color}\n fillOpacity={zone.opacity}\n strokeOpacity={0}\n ifOverflow=\"visible\"\n />\n ))}\n\n <XAxis\n type=\"number\"\n dataKey=\"displayIntensity\"\n domain={[displayDomain.min, displayDomain.max]}\n tick={\n showXAxisTicks\n ? { fill: resolvedTheme.axisColor, fontFamily: resolvedTheme.fontFamily }\n : false\n }\n axisLine={{ stroke: resolvedTheme.axisColor }}\n tickLine={showXAxisTicks ? { stroke: resolvedTheme.axisColor } : false}\n tickFormatter={(value) =>\n formatNumber(\n compression?.inverse(Number(value)) ?? Number(value),\n xAxisPrecision,\n )\n }\n >\n <Label\n value={xAxisLabel}\n position=\"insideBottom\"\n offset={-14}\n style={{\n fill: resolvedTheme.labelColor,\n fontFamily: resolvedTheme.fontFamily,\n }}\n />\n </XAxis>\n\n <YAxis\n type=\"number\"\n domain={[curve.domain.minLactate, curve.domain.maxLactate]}\n tick={{ fill: resolvedTheme.axisColor, fontFamily: resolvedTheme.fontFamily }}\n axisLine={{ stroke: resolvedTheme.axisColor }}\n tickLine={{ stroke: resolvedTheme.axisColor }}\n tickFormatter={(value) => formatNumber(Number(value), yAxisPrecision)}\n width={64}\n >\n <Label\n angle={-90}\n position=\"insideLeft\"\n value={yAxisLabel}\n style={{\n fill: resolvedTheme.labelColor,\n fontFamily: resolvedTheme.fontFamily,\n textAnchor: \"middle\",\n }}\n />\n </YAxis>\n\n <ChartTooltip\n cursor={{ stroke: resolvedTheme.gridColor, strokeDasharray: \"3 3\" }}\n content={\n <ChartTooltipContent\n labelFormatter={(value) =>\n `${xAxisLabel}: ${formatNumber(\n compression?.inverse(Number(value)) ?? Number(value),\n xAxisPrecision,\n )}`\n }\n valueFormatter={(value, name) =>\n name === \"lactate\"\n ? `${formatNumber(Number(value), yAxisPrecision)} mmol/L`\n : `${formatNumber(Number(value), xAxisPrecision)}`\n }\n />\n }\n />\n\n <Line\n type=\"monotone\"\n dataKey=\"lactate\"\n name=\"lactate\"\n stroke={resolvedTheme.curveColor}\n strokeWidth={3}\n dot={false}\n isAnimationActive={false}\n />\n\n {thresholdEntries.map(({ key, point }) => {\n const annotation = thresholdAnnotations?.[key]\n const color = annotation?.color ?? resolvedTheme.thresholdColor\n const showGuide = annotation?.showGuide ?? showThresholdGuides\n const showCircle = annotation?.showCircle ?? showThresholdCircles\n const labelText = annotation?.label ?? labels?.[key] ?? defaultThresholdLabel(key)\n\n return (\n <React.Fragment key={key}>\n {showGuide ? (\n <ReferenceLine\n x={toDisplayIntensity(point.intensity)}\n stroke={color}\n strokeDasharray={annotation?.strokeDasharray ?? \"6 4\"}\n strokeWidth={annotation?.lineWidth ?? 1.5}\n ifOverflow=\"visible\"\n label={\n showThresholdLabels\n ? {\n value: labelText,\n position: \"top\",\n fill: color,\n fontSize: 12,\n fontWeight: 700,\n fontFamily: resolvedTheme.fontFamily,\n }\n : undefined\n }\n />\n ) : null}\n {showCircle ? (\n <ReferenceDot\n x={toDisplayIntensity(point.intensity)}\n y={point.lactate}\n r={annotation?.circleRadius ?? 5}\n fill={color}\n stroke={resolvedTheme.backgroundColor}\n strokeWidth={2}\n ifOverflow=\"visible\"\n />\n ) : null}\n </React.Fragment>\n )\n })}\n\n {projectedMarkers.map((marker) => (\n <ReferenceDot\n key={`${marker.label}-${marker.intensity}`}\n x={toDisplayIntensity(marker.intensity)}\n y={marker.lactate}\n r={marker.radius ?? 5}\n fill={marker.color ?? resolvedTheme.curveColor}\n stroke={resolvedTheme.backgroundColor}\n strokeWidth={2}\n ifOverflow=\"visible\"\n label={\n marker.showLabel === false\n ? undefined\n : {\n value: marker.label,\n position: \"top\",\n offset: 10,\n fill: resolvedTheme.markerLabelColor,\n fontSize: 12,\n fontWeight: 600,\n fontFamily: resolvedTheme.fontFamily,\n }\n }\n />\n ))}\n </LineChart>\n </ChartContainer>\n\n {compression ? (\n <div\n style={{\n marginTop: 10,\n fontSize: 12,\n color: resolvedTheme.labelColor,\n opacity: 0.78,\n }}\n >\n X-axis break: the low-intensity region up to {formatNumber(\n compression.end,\n xAxisPrecision,\n )} is visually compressed.\n </div>\n ) : null}\n\n {resolvedZones.length ? (\n <div\n aria-label={labels?.zones ?? \"Intensity domains\"}\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: 10,\n marginTop: 14,\n }}\n >\n {resolvedZones.map((zone) => (\n <span\n key={`${zone.label}-${zone.startIntensity}-${zone.endIntensity}-legend`}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 8,\n fontSize: 12,\n color: resolvedTheme.labelColor,\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: 12,\n height: 12,\n borderRadius: 999,\n background: zone.color,\n opacity: Math.max(zone.opacity, 0.35),\n }}\n />\n {zone.label}\n </span>\n ))}\n </div>\n ) : null}\n </figure>\n )\n}\n","import type {\n AnchorPoint,\n GeneratedLactateCurve,\n IntensityAnchor,\n LactateCurvePoint,\n} from \"../types\"\n\ntype CurveInputs = {\n baselineLactate: number\n lt1: AnchorPoint\n lt2: AnchorPoint\n vo2max?: IntensityAnchor\n minIntensity?: number\n maxIntensity?: number\n intensityStep?: number\n samples?: number\n}\n\nconst MAX_LT1_BASELINE_DIP = 0.45\n\nconst clamp = (value: number, min: number, max: number) =>\n Math.min(max, Math.max(min, value))\n\nconst round = (value: number) => Math.round(value * 1000) / 1000\n\nconst assertFinitePositive = (value: number, label: string) => {\n if (!Number.isFinite(value)) {\n throw new Error(`${label} must be a finite number.`)\n }\n}\n\nconst buildModerateDomainFunction = ({\n minIntensity,\n baselineLactate,\n lt1,\n}: {\n minIntensity: number\n baselineLactate: number\n lt1: AnchorPoint\n}) => {\n const span = lt1.intensity - minIntensity\n const delta = lt1.lactate - baselineLactate\n\n if (span <= 0) {\n throw new Error(\"Moderate domain span must be greater than 0.\")\n }\n\n if (Math.abs(delta) < 0.0001) {\n return () => baselineLactate\n }\n\n if (delta > 0) {\n return (intensity: number) => {\n const t = clamp((intensity - minIntensity) / span, 0, 1)\n return baselineLactate + delta * Math.pow(t, 4)\n }\n }\n\n const dip = baselineLactate - lt1.lactate\n const dipAccent = 0.32\n\n return (intensity: number) => {\n const t = clamp((intensity - minIntensity) / span, 0, 1)\n return baselineLactate - dip * (t + dipAccent * 4 * t * (1 - t))\n }\n}\n\nconst buildHeavyDomainFunction = ({\n lt1,\n lt2,\n}: {\n lt1: AnchorPoint\n lt2: AnchorPoint\n}) => {\n const span = lt2.intensity - lt1.intensity\n\n if (span <= 0) {\n throw new Error(\"Heavy domain span must be greater than 0.\")\n }\n\n const slope = (lt2.lactate - lt1.lactate) / span\n\n return {\n slope,\n project: (intensity: number) => lt1.lactate + slope * (intensity - lt1.intensity),\n }\n}\n\nconst buildSevereDomainFunction = ({\n lt2,\n maxIntensity,\n heavySlope,\n}: {\n lt2: AnchorPoint\n maxIntensity: number\n heavySlope: number\n}) => {\n const span = maxIntensity - lt2.intensity\n\n if (span <= 0) {\n throw new Error(\"Severe domain span must be greater than 0.\")\n }\n\n const curvature = clamp(2.4 / span, 0.02, 0.9)\n const initialSevereSlope = heavySlope * 1.4\n\n return {\n curvature,\n initialSevereSlope,\n project: (intensity: number) => {\n const delta = Math.max(0, intensity - lt2.intensity)\n return (\n lt2.lactate +\n (initialSevereSlope / curvature) * (Math.exp(curvature * delta) - 1)\n )\n },\n }\n}\n\nexport const generateLactateCurve = ({\n baselineLactate,\n lt1,\n lt2,\n vo2max,\n minIntensity = 0,\n maxIntensity,\n intensityStep,\n samples = 80,\n}: CurveInputs): GeneratedLactateCurve => {\n assertFinitePositive(baselineLactate, \"baselineLactate\")\n assertFinitePositive(lt1.intensity, \"lt1 intensity\")\n assertFinitePositive(lt1.lactate, \"lt1 lactate\")\n assertFinitePositive(lt2.intensity, \"lt2 intensity\")\n assertFinitePositive(lt2.lactate, \"lt2 lactate\")\n\n if (baselineLactate <= 0) {\n throw new Error(\"baselineLactate must be greater than 0.\")\n }\n\n if (baselineLactate - lt1.lactate > MAX_LT1_BASELINE_DIP) {\n throw new Error(\n `LT1 lactate can sit slightly below baseline, but the dip must be <= ${MAX_LT1_BASELINE_DIP} mmol/L.`,\n )\n }\n\n if (lt1.intensity <= minIntensity) {\n throw new Error(\"LT1 intensity must be above the minimum chart intensity.\")\n }\n\n if (lt1.intensity >= lt2.intensity) {\n throw new Error(\"LT1 intensity must be below LT2 intensity.\")\n }\n\n if (lt1.lactate >= lt2.lactate) {\n throw new Error(\"LT1 lactate must be below LT2 lactate.\")\n }\n\n if (vo2max) {\n assertFinitePositive(vo2max.intensity, \"vo2max intensity\")\n\n if (lt2.intensity >= vo2max.intensity) {\n throw new Error(\"VO2max intensity must be greater than LT2 intensity.\")\n }\n }\n\n const maxX =\n maxIntensity ??\n round(\n vo2max\n ? vo2max.intensity * 1.08\n : lt2.intensity + Math.max((lt2.intensity - lt1.intensity) * 0.6, lt2.intensity * 0.12),\n )\n\n if (maxX <= lt2.intensity) {\n throw new Error(\"maxIntensity must extend beyond LT2.\")\n }\n\n const moderateDomain = buildModerateDomainFunction({\n minIntensity,\n baselineLactate,\n lt1,\n })\n const heavyDomain = buildHeavyDomainFunction({ lt1, lt2 })\n const severeDomain = buildSevereDomainFunction({\n lt2,\n maxIntensity: maxX,\n heavySlope: heavyDomain.slope,\n })\n\n const points: LactateCurvePoint[] = []\n const pointCount = intensityStep\n ? Math.max(2, Math.floor((maxX - minIntensity) / intensityStep) + 1)\n : samples\n\n for (let index = 0; index < pointCount; index += 1) {\n const intensity =\n index === pointCount - 1\n ? maxX\n : intensityStep\n ? minIntensity + intensityStep * index\n : minIntensity + ((maxX - minIntensity) * index) / (pointCount - 1)\n\n let lactate: number\n\n if (intensity <= lt1.intensity) {\n lactate = moderateDomain(intensity)\n } else if (intensity <= lt2.intensity) {\n lactate = heavyDomain.project(intensity)\n } else {\n lactate = severeDomain.project(intensity)\n }\n\n points.push({\n intensity: round(intensity),\n lactate: round(lactate),\n })\n }\n\n const endPoint = points[points.length - 1]\n const minimumModerateEstimate =\n lt1.lactate < baselineLactate\n ? lt1.lactate - (baselineLactate - lt1.lactate) * 0.12\n : Math.min(baselineLactate, lt1.lactate)\n\n return {\n points,\n anchors: {\n baseline: { intensity: minIntensity, lactate: baselineLactate },\n lt1,\n lt2,\n vo2max,\n max: endPoint,\n },\n domain: {\n minIntensity,\n maxIntensity: maxX,\n minLactate: round(Math.max(0, minimumModerateEstimate - 0.12)),\n maxLactate: round(endPoint.lactate * 1.08),\n },\n }\n}\n","import type { LactateCurveTheme, ZoneConfig } from \"../types\"\n\nexport const DEFAULT_THEME: Required<LactateCurveTheme> = {\n curveColor: \"#e11d48\",\n axisColor: \"#334155\",\n gridColor: \"#cbd5e1\",\n labelColor: \"#0f172a\",\n thresholdColor: \"#0f172a\",\n fontFamily: \"ui-sans-serif, system-ui, sans-serif\",\n backgroundColor: \"#ffffff\",\n markerLabelColor: \"#0f172a\",\n}\n\nexport const DEFAULT_ZONE_OPACITY = 0.12\n\nexport const getDefaultZones = (): ZoneConfig[] => [\n {\n startIntensity: \"min\",\n endIntensity: \"lt1\",\n label: \"Moderate domain\",\n color: \"#22c55e\",\n opacity: DEFAULT_ZONE_OPACITY,\n },\n {\n startIntensity: \"lt1\",\n endIntensity: \"lt2\",\n label: \"Heavy domain\",\n color: \"#f59e0b\",\n opacity: DEFAULT_ZONE_OPACITY,\n },\n {\n startIntensity: \"lt2\",\n endIntensity: \"max\",\n label: \"Severe domain\",\n color: \"#ef4444\",\n opacity: DEFAULT_ZONE_OPACITY,\n },\n]\n","import type {\n LactateCurvePoint,\n ProjectedRaceMarker,\n RaceMarker,\n} from \"../types\"\n\nexport const projectIntensityToCurve = (\n intensity: number,\n points: LactateCurvePoint[],\n): { intensity: number; lactate: number } => {\n if (points.length < 2) {\n throw new Error(\"At least two curve points are required to project onto the curve.\")\n }\n\n const clampedIntensity = Math.min(\n points[points.length - 1].intensity,\n Math.max(points[0].intensity, intensity),\n )\n\n for (let index = 0; index < points.length - 1; index += 1) {\n const current = points[index]\n const next = points[index + 1]\n\n if (\n clampedIntensity >= current.intensity &&\n clampedIntensity <= next.intensity\n ) {\n const span = next.intensity - current.intensity || 1\n const ratio = (clampedIntensity - current.intensity) / span\n const lactate = current.lactate + (next.lactate - current.lactate) * ratio\n\n return {\n intensity: clampedIntensity,\n lactate: Math.round(lactate * 1000) / 1000,\n }\n }\n }\n\n return {\n intensity: clampedIntensity,\n lactate: points[points.length - 1].lactate,\n }\n}\n\nexport const projectMarkerToCurve = (\n marker: RaceMarker,\n points: LactateCurvePoint[],\n): ProjectedRaceMarker => ({\n ...marker,\n ...projectIntensityToCurve(marker.intensity, points),\n})\n","import { DEFAULT_ZONE_OPACITY, getDefaultZones } from \"./chart-defaults\"\nimport type {\n AnchorPoint,\n GeneratedLactateCurve,\n IntensityAnchor,\n ResolvedZone,\n ZoneBoundary,\n ZoneConfig,\n} from \"../types\"\n\ntype ResolveZonesInput = {\n zones?: ZoneConfig[]\n curve: GeneratedLactateCurve\n}\n\nconst resolveBoundary = (\n boundary: ZoneBoundary | undefined,\n anchors: {\n baseline: AnchorPoint\n lt1: AnchorPoint\n lt2: AnchorPoint\n vo2max?: IntensityAnchor\n max: AnchorPoint\n },\n fallback: number,\n) => {\n if (boundary === undefined) return fallback\n if (typeof boundary === \"number\") return boundary\n\n switch (boundary) {\n case \"min\":\n case \"baseline\":\n return anchors.baseline.intensity\n case \"lt1\":\n return anchors.lt1.intensity\n case \"lt2\":\n return anchors.lt2.intensity\n case \"vo2max\":\n return anchors.vo2max?.intensity ?? anchors.max.intensity\n case \"max\":\n return anchors.max.intensity\n }\n}\n\nexport const resolveZones = ({\n zones,\n curve,\n}: ResolveZonesInput): ResolvedZone[] => {\n const sourceZones = zones ?? getDefaultZones()\n\n return sourceZones\n .map((zone) => {\n const startIntensity = resolveBoundary(\n zone.startIntensity,\n curve.anchors,\n curve.domain.minIntensity,\n )\n const endIntensity = resolveBoundary(\n zone.endIntensity,\n curve.anchors,\n curve.domain.maxIntensity,\n )\n\n return {\n label: zone.label,\n color: zone.color,\n opacity: zone.opacity ?? DEFAULT_ZONE_OPACITY,\n startIntensity,\n endIntensity,\n }\n })\n .filter((zone) => zone.endIntensity > zone.startIntensity)\n}\n","import { clsx } from \"clsx\"\n\nexport const cn = (...inputs: Array<string | false | null | undefined>) =>\n clsx(inputs)\n","import * as React from \"react\"\nimport { ResponsiveContainer, Tooltip } from \"recharts\"\nimport type {\n NameType,\n ValueType,\n} from \"recharts/types/component/DefaultTooltipContent\"\nimport type { Payload } from \"recharts/types/component/DefaultTooltipContent\"\n\nimport { cn } from \"../../lib/utils\"\n\nexport type ChartConfig = Record<\n string,\n {\n label?: string\n color?: string\n }\n>\n\ntype ChartContextValue = {\n config: ChartConfig\n}\n\nconst ChartContext = React.createContext<ChartContextValue | null>(null)\n\nexport const useChart = () => {\n const context = React.useContext(ChartContext)\n\n if (!context) {\n throw new Error(\"Chart components must be used within a ChartContainer.\")\n }\n\n return context\n}\n\ntype ChartContainerProps = React.HTMLAttributes<HTMLDivElement> & {\n config?: ChartConfig\n height?: number\n children: React.ReactNode\n}\n\nexport const ChartContainer = React.forwardRef<HTMLDivElement, ChartContainerProps>(\n ({ config = {}, className, style, height = 360, children, ...props }, ref) => (\n <ChartContext.Provider value={{ config }}>\n <div\n ref={ref}\n className={cn(\"w-full\", className)}\n style={{ width: \"100%\", height, ...style }}\n {...props}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n {children}\n </ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n ),\n)\n\nChartContainer.displayName = \"ChartContainer\"\n\nexport const ChartTooltip = Tooltip\n\ntype ChartTooltipContentProps = React.HTMLAttributes<HTMLDivElement> & {\n active?: boolean\n payload?: Payload<ValueType, NameType>[]\n label?: NameType\n indicator?: \"dot\" | \"line\"\n labelFormatter?: (label: NameType) => React.ReactNode\n valueFormatter?: (value: ValueType, name: NameType) => React.ReactNode\n}\n\nexport const ChartTooltipContent = React.forwardRef<\n HTMLDivElement,\n ChartTooltipContentProps\n>(\n (\n {\n active,\n payload,\n label,\n className,\n indicator = \"dot\",\n labelFormatter,\n valueFormatter,\n ...props\n },\n ref,\n ) => {\n const { config } = useChart()\n\n if (!active || !payload?.length) {\n return null\n }\n\n return (\n <div\n ref={ref}\n className={cn(className)}\n style={{\n border: \"1px solid rgba(15, 23, 42, 0.15)\",\n borderRadius: 12,\n background: \"rgba(255,255,255,0.96)\",\n boxShadow: \"0 12px 40px rgba(15, 23, 42, 0.12)\",\n padding: \"0.75rem\",\n minWidth: 180,\n }}\n {...props}\n >\n <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 8 }}>\n {labelFormatter ? labelFormatter(label ?? \"\") : label}\n </div>\n <div style={{ display: \"grid\", gap: 6 }}>\n {payload.map((item) => {\n const key = String(item.dataKey ?? item.name ?? \"\")\n const entry = config[key]\n const color = item.color ?? entry?.color ?? \"#0f172a\"\n\n return (\n <div\n key={key}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 12,\n fontSize: 12,\n }}\n >\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 8 }}>\n <span\n aria-hidden=\"true\"\n style={{\n width: indicator === \"dot\" ? 8 : 12,\n height: 8,\n borderRadius: indicator === \"dot\" ? 999 : 2,\n background: color,\n display: \"inline-block\",\n }}\n />\n <span>{entry?.label ?? item.name}</span>\n </span>\n <span style={{ fontWeight: 600 }}>\n {valueFormatter\n ? valueFormatter(item.value ?? \"\", item.name ?? \"\")\n : item.value}\n </span>\n </div>\n )\n })}\n </div>\n </div>\n )\n },\n)\n\nChartTooltipContent.displayName = \"ChartTooltipContent\"\n","import * as React from \"react\"\n\nimport { LactateCurveChart } from \"./components/LactateCurveChart\"\n\nconst baseProps = {\n baselineLactate: 1.1,\n lt1: { intensity: 220, lactate: 1.9 },\n lt2: { intensity: 305, lactate: 4.1 },\n}\n\nexport const BasicCurveExample = () => <LactateCurveChart {...baseProps} />\n\nexport const CurveWithVo2maxExample = () => (\n <LactateCurveChart\n {...baseProps}\n vo2max={{ intensity: 360 }}\n description=\"The severe-domain tail is anchored explicitly with a VO2max point.\"\n xAxisCompression={{ endIntensity: \"lt1\", scale: 0.34 }}\n />\n)\n\nexport const DomainsOverlayExample = () => (\n <LactateCurveChart\n {...baseProps}\n vo2max={{ intensity: 355 }}\n xAxisLabel=\"Running power (W)\"\n />\n)\n\nexport const RaceMarkerOverlayExample = () => (\n <LactateCurveChart\n {...baseProps}\n vo2max={{ intensity: 360 }}\n raceMarkers={[\n { intensity: 252, label: \"Marathon\", color: \"#0f766e\" },\n { intensity: 300, label: \"Half\", color: \"#0369a1\" },\n { intensity: 312, label: \"10k\", color: \"#7c3aed\" },\n { intensity: 329, label: \"5k\", color: \"#dc2626\" },\n { intensity: 342, label: \"3k\", color: \"#ea580c\" },\n ]}\n />\n)\n\nconst BrandMark = () => (\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" fill=\"none\">\n <circle cx=\"11\" cy=\"11\" r=\"10\" fill=\"#102a43\" />\n <path\n d=\"M6 13.8C8.7 13.8 10.8 12 11.8 8.8C12.7 12.7 14.8 15 17 15\"\n stroke=\"#f0b429\"\n strokeWidth=\"2.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n)\n\nexport const FullyThemedExample = () => (\n <LactateCurveChart\n {...baseProps}\n vo2max={{ intensity: 362 }}\n title=\"Threshold Map\"\n description=\"A branded version for article embeds and product UI.\"\n xAxisLabel=\"Power (W)\"\n yAxisLabel=\"Lactate (mmol/L)\"\n icon={<BrandMark />}\n labels={{\n curve: \"Athlete curve\",\n zones: \"Training domains\",\n lt1: \"Aerobic threshold\",\n lt2: \"Critical threshold\",\n vo2max: \"VO2 ceiling\",\n }}\n raceMarkers={[\n { intensity: 255, label: \"M\", color: \"#166534\", radius: 6 },\n { intensity: 298, label: \"HM\", color: \"#0f766e\", radius: 6 },\n { intensity: 313, label: \"10k\", color: \"#1d4ed8\", radius: 6 },\n { intensity: 332, label: \"5k\", color: \"#b91c1c\", radius: 6 },\n ]}\n theme={{\n curveColor: \"#b91c1c\",\n thresholdColor: \"#102a43\",\n axisColor: \"#243b53\",\n gridColor: \"#d9e2ec\",\n labelColor: \"#102a43\",\n markerLabelColor: \"#102a43\",\n backgroundColor: \"#f8fbff\",\n fontFamily: \"Avenir Next, ui-sans-serif, system-ui, sans-serif\",\n }}\n zones={[\n {\n startIntensity: \"min\",\n endIntensity: \"lt1\",\n label: \"Easy / moderate\",\n color: \"#a7f3d0\",\n },\n {\n startIntensity: \"lt1\",\n endIntensity: \"lt2\",\n label: \"Threshold / heavy\",\n color: \"#fde68a\",\n },\n {\n startIntensity: \"lt2\",\n endIntensity: \"max\",\n label: \"VO2 / severe\",\n color: \"#fecaca\",\n },\n ]}\n />\n)\n"],"mappings":"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","names":["React","jsx","jsxs","jsxs","jsx","jsx","jsxs"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@runaid/lactate-curve",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Reusable React lactate curve chart component built on shadcn/ui charts. Generate approximate physiological lactate curves from baseline lactate, LT1, LT2, and optional VO2max.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"check": "tsc --noEmit",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"playground": "npm --prefix playground run dev",
|
|
30
|
+
"playground:build": "npm --prefix playground run build"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/CzarSimon/lactate-curve.git"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/CzarSimon/lactate-curve#readme",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/CzarSimon/lactate-curve/issues"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"react",
|
|
42
|
+
"chart",
|
|
43
|
+
"lactate",
|
|
44
|
+
"endurance",
|
|
45
|
+
"recharts",
|
|
46
|
+
"shadcn"
|
|
47
|
+
],
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"react": "^18.2.0 || ^19.0.0",
|
|
50
|
+
"react-dom": "^18.2.0 || ^19.0.0",
|
|
51
|
+
"recharts": "^2.15.0 || ^3.0.0"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"clsx": "^2.1.1"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/react": "^19.2.14",
|
|
58
|
+
"@types/react-dom": "^19.2.3",
|
|
59
|
+
"react": "^19.2.0",
|
|
60
|
+
"react-dom": "^19.2.0",
|
|
61
|
+
"recharts": "^3.2.1",
|
|
62
|
+
"tsup": "^8.5.1",
|
|
63
|
+
"typescript": "^6.0.2",
|
|
64
|
+
"vitest": "^4.1.4"
|
|
65
|
+
}
|
|
66
|
+
}
|