import React from "react"; import { StyleSheet } from "react-native"; import { Line, Text, vec } from "@shopify/react-native-skia"; import { DEFAULT_TICK_COUNT, downsampleTicks } from "../../utils/tickHelpers"; import type { InputDatum, InputFields, ValueOf, XAxisProps, XAxisPropsWithDefaults, } from "../../types"; export const XAxis = < RawData extends Record, XK extends keyof InputFields, >({ xScale, yScale, axisSide = "bottom", yAxisSide = "left", labelPosition = "outset", tickCount = DEFAULT_TICK_COUNT, tickValues, labelOffset = 2, labelColor = "#000000", lineWidth = StyleSheet.hairlineWidth, lineColor = "hsla(0, 0%, 0%, 0.25)", font, formatXLabel = (label: ValueOf) => String(label), ix = [], isNumericalData, linePathEffect, }: XAxisProps) => { const [y1 = 0, y2 = 0] = yScale.domain(); const [x1r = 0, x2r = 0] = xScale.range(); const fontSize = font?.getSize() ?? 0; const xTicksNormalized = tickValues ? downsampleTicks(tickValues, tickCount) : xScale.ticks(tickCount); // console.log('xTicksNormalized', xTicksNormalized); // console.log('ix', ix); const xAxisNodes = xTicksNormalized.map((tick) => { const val = isNumericalData || typeof tick === 'object' ? tick : ix[tick]; // console.log('AXIS NODE tick', tick); // console.log('AXIS NODE val', val); const contentX = formatXLabel(val as never); const labelWidth = font ?.getGlyphWidths?.(font.getGlyphIDs(contentX)) .reduce((sum, value) => sum + value, 0) ?? 0; const labelX = xScale(tick) - (labelWidth ?? 0) / 2; const canFitLabelContent = yAxisSide === "left" ? labelX + labelWidth < x2r : x1r < labelX; const labelY = (() => { // bottom, outset if (axisSide === "bottom" && labelPosition === "outset") { return yScale(y2) + labelOffset + fontSize; } // bottom, inset if (axisSide === "bottom" && labelPosition === "inset") { return yScale(y2) - labelOffset; } // top, outset if (axisSide === "top" && labelPosition === "outset") { return yScale(y1) - labelOffset; } // top, inset return yScale(y1) + fontSize + labelOffset; })(); return ( {lineWidth > 0 ? ( {linePathEffect ? linePathEffect : null} ) : null} {font && labelWidth && canFitLabelContent ? ( ) : null} <> ); }); return xAxisNodes; }; export const XAxisDefaults = { lineColor: "hsla(0, 0%, 0%, 0.25)", lineWidth: StyleSheet.hairlineWidth, tickCount: 5, labelOffset: 2, axisSide: "bottom", yAxisSide: "left", labelPosition: "outset", formatXLabel: (label: ValueOf) => String(label), labelColor: "#000000", } satisfies XAxisPropsWithDefaults;