import type { CSSProperties, ReactElement, ReactNode, SVGAttributes, } from 'react'; import type { Scales, TicksType } from './types.js'; interface CoordinatesXY { x1?: number; x2?: number; y1?: number; y2?: number; } export interface TickProps { children?: ReactNode; line: CoordinatesXY; text: Omit; secondary?: boolean; dominantBaseline?: SVGAttributes['dominantBaseline']; strokeColor?: string; strokeHeight?: number; anchor?: SVGAttributes['textAnchor']; labelStyle?: CSSProperties; style?: CSSProperties; } export interface TicksProps extends Omit { primaryTicks: TicksType[]; secondaryTickLength: number; scale: Scales; secondaryTickStyle?: CSSProperties; getPositions: ( y: number, secondary?: boolean, ) => { line: CoordinatesXY; text: Omit; }; } export function Ticks(props: Omit) { const { primaryTicks, getPositions, secondaryTickLength, scale, secondaryTickStyle, style, ...otherProps } = props; const primaryTickElements = primaryTicks.map((tick) => { const { line, text } = getPositions(tick.position); return ( {tick.label} ); }); let secondaryTickElements: Array = []; if (secondaryTickLength !== 0) { // generate secondaryTicks according to the density of primaryTicks const range = Math.abs(scale?.range()[1] - scale?.range()[0]) || 0; const mainTicksDensity = range / primaryTicks.length; const density = mainTicksDensity < 50 ? 5 : 10; const secondaryTicks = scale?.ticks(primaryTicks.length * density) || []; secondaryTickElements = secondaryTicks.map((tick) => { // exclude the main ticks if (primaryTicks.map((tick) => tick.position).includes(scale(tick))) { return null; } const { line, text } = getPositions(scale(tick), true); return ( ); }) || []; } return ( <> {secondaryTickElements} {primaryTickElements} ); } export function Tick(props: TickProps) { const { line: { x1: lineX1 = 0, x2: lineX2 = 0, y1: lineY1 = 0, y2: lineY2 = 0 }, text: { x1: textX1 = 0, y1: textY1 = 0 }, children, strokeColor = 'black', strokeHeight = 1, anchor = 'end', secondary = false, labelStyle, style, dominantBaseline = 'middle', } = props; return ( {!secondary && ( {children} )} ); }