Files
temetro/frontend/components/charts/bar-depth-geometry.ts
T
Khalid Abdi 321a6298a4 frontend: pharmacy inventory, lab add-result & analysis charts
- Pharmacy: the sidebar entry now expands into Pharmacy + a new Inventory page
  (searchable medication stock with derived in-stock/low/out availability,
  backed by /api/inventory). Fix the dispensing-queue "Expiring" badge so it
  only flags courses ending within the next 7 days, not ones already elapsed.
- Lab "Add analysis result": the patient picker no longer lists patients until
  you type and supports arrow-key + Enter selection; the test field offers a
  catalog of common analyses with an Advanced option (custom analysis + ref
  range); submitted results now show immediately in a Recent results feed.
- Analysis: add a Live panel (real-time line chart) and replace the flat trend
  sparklines with bklit-ui area + bar charts (installed from the @bklit shadcn
  registry; chart CSS variables wired into the theme for light and dark).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:22:07 +03:00

35 lines
1.4 KiB
TypeScript

export const BAR_DEPTH_MAX_PX = 7;
/** The side parallelogram's back edge lifts by `depth * this ratio`, giving a
* subtle head-on perspective slope. */
export const BAR_DEPTH_PERSPECTIVE_RATIO = 0.45;
/**
* Maximum side-face depth in px for a chart, clamped so depth never spills past
* the gap between bars. `stepWidth` is d3-scaleBand's `step()` (bandwidth +
* gap); `bandWidth` is a single bar's width. Returns 0 for gapless/dense charts.
*/
export function barDepthMaxDepth(stepWidth: number, bandWidth: number): number {
const gap = Math.max(0, stepWidth - bandWidth);
return Math.min(bandWidth * 0.22, Math.max(0, gap - 1), BAR_DEPTH_MAX_PX);
}
/**
* Per-bar side-face depth + perspective rise.
*
* - `absOffset` ∈ [0, 1]: the bar's normalized distance from the chart's
* horizontal center. 0 = dead center (no depth); 1 = chart edge (full depth).
* - `naturalHeight`: the bar's pixel height. Depth is capped by it so a short
* bar's side never reads wider than the bar is tall.
* - `maxDepth`: from `barDepthMaxDepth`.
*/
export function barDepthAndRise(
absOffset: number,
naturalHeight: number,
maxDepth: number
): { depth: number; perspectiveRise: number } {
const offset = Math.min(1, Math.max(0, absOffset));
const cappedMaxDepth = Math.min(maxDepth, Math.max(0, naturalHeight));
const depth = offset * cappedMaxDepth;
return { depth, perspectiveRise: depth * BAR_DEPTH_PERSPECTIVE_RATIO };
}