import React from "react"; import { StyleSheet } from "react-native"; import { Group, Line, Text, vec } from "@shopify/react-native-skia"; import { boundsToClip } from "../../utils/boundsToClip"; import type { InputDatum, NumericalFields, ValueOf, YAxisProps, YAxisPropsWithDefaults, } from "../../types"; export const YAxis = < RawData extends Record, YK extends keyof NumericalFields, >({ xScale, yScale, yTicksNormalized, axisSide, labelPosition, labelOffset, labelColor, lineWidth, lineColor, font, formatYLabel = (label: ValueOf) => String(label), linePathEffect, chartBounds, }: YAxisProps) => { const [x1 = 0, x2 = 0] = xScale.domain(); const [_ = 0, y2 = 0] = yScale.domain(); const fontSize = font?.getSize() ?? 0; const yAxisNodes = yTicksNormalized.map((tick) => { const contentY = formatYLabel(tick as never); const labelWidth = font ?.getGlyphWidths?.(font.getGlyphIDs(contentY)) .reduce((sum, value) => sum + value, 0) ?? 0; const labelY = yScale(tick) + fontSize / 3; const labelX = (() => { // left, outset if (axisSide === "left" && labelPosition === "outset") { return chartBounds.left - (labelWidth + labelOffset); } // left, inset if (axisSide === "left" && labelPosition === "inset") { return chartBounds.left + labelOffset; } // right, outset if (axisSide === "right" && labelPosition === "outset") { return chartBounds.right + labelOffset; } // right, inset return chartBounds.right - (labelWidth + labelOffset); })(); const canFitLabelContent = labelY > fontSize && labelY < yScale(y2); return ( {lineWidth > 0 ? ( {linePathEffect ? linePathEffect : null} ) : null} {font ? canFitLabelContent && ( ) : null} ); }); return yAxisNodes; }; export const YAxisDefaults = { lineColor: "hsla(0, 0%, 0%, 0.25)", lineWidth: StyleSheet.hairlineWidth, tickCount: 5, labelOffset: 4, axisSide: "left", labelPosition: "outset", formatYLabel: (label: ValueOf) => String(label), labelColor: "#000000", yKeys: [], domain: null, } satisfies YAxisPropsWithDefaults;