UNPKG

victory-native

Version:

A charting library for React Native with a focus on performance and customization.

198 lines (197 loc) 9.74 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.XAxis = exports.XAxisDefaults = void 0; const react_1 = __importDefault(require("react")); const react_native_1 = require("react-native"); const react_native_skia_1 = require("@shopify/react-native-skia"); const getOffsetFromAngle_1 = require("../../utils/getOffsetFromAngle"); const boundsToClip_1 = require("../../utils/boundsToClip"); const tickHelpers_1 = require("../../utils/tickHelpers"); const getXAxisLabelPosition_1 = require("../utils/getXAxisLabelPosition"); const getXAxisTicks_1 = require("../utils/getXAxisTicks"); const getAxisTitleLayout_1 = require("../utils/getAxisTitleLayout"); const getAxisLabelLayout_1 = require("../utils/getAxisLabelLayout"); var axisDefaults_1 = require("../utils/axisDefaults"); Object.defineProperty(exports, "XAxisDefaults", { enumerable: true, get: function () { return axisDefaults_1.XAxisDefaults; } }); const XAxis = ({ xScale: xScaleProp, yScale, axisSide = "bottom", labelPosition = "outset", labelRotate, tickCount = tickHelpers_1.DEFAULT_TICK_COUNT, tickValues, labelOffset = 2, labelColor = "#000000", lineWidth = react_native_1.StyleSheet.hairlineWidth, lineColor = "hsla(0, 0%, 0%, 0.25)", font, title, labelRenderer, formatXLabel = (label) => String(label), ix = [], isNumericalData, linePathEffect, chartBounds, orientation, enableRescaling, zoom, }) => { var _a; const xScale = zoom ? zoom.rescaleX(xScaleProp) : xScaleProp; const [y1 = 0, y2 = 0] = yScale.domain(); const fontSize = (_a = font === null || font === void 0 ? void 0 : font.getSize()) !== null && _a !== void 0 ? _a : 0; const xTicksNormalized = (0, getXAxisTicks_1.getXAxisTicks)({ isNumericalData, ix, tickCount, tickValues, xScale: enableRescaling ? xScale : xScaleProp, }); const xTickLabels = xTicksNormalized.map((tick, index) => { const tickPosition = xScale(tick); const val = (isNumericalData ? tick : ix[tick]); const contentX = String(formatXLabel(val)); const labelLayout = (0, getAxisLabelLayout_1.getAxisLabelLayout)({ axis: "x", orientation, value: val, text: contentX, index, font, labelRenderer, }); return { tick, tickPosition, labelLayout, }; }); const maxXLabelLayout = xTickLabels.reduce((max, { labelLayout }) => ({ width: Math.max(max.width, labelLayout.width), height: Math.max(max.height, labelLayout.height), }), { width: 0, height: 0 }); const titleLayout = (0, getAxisTitleLayout_1.getAxisTitleLayout)({ title, font }); const labelOutset = labelPosition === "outset" && xTickLabels.length > 0 && maxXLabelLayout.width > 0 ? maxXLabelLayout.height + labelOffset * 2 : 0; const titleX = (() => { if (titleLayout.position === "start") { return chartBounds.left; } if (titleLayout.position === "end") { return chartBounds.right - titleLayout.width; } return (chartBounds.left + (chartBounds.right - chartBounds.left) / 2 - titleLayout.width / 2); })(); const titleY = (() => { if (axisSide === "bottom") { return (chartBounds.bottom + labelOutset + titleLayout.offset + titleLayout.fontSize); } return (chartBounds.top - labelOutset - titleLayout.offset - Math.max(0, titleLayout.height - titleLayout.fontSize)); })(); const titleFont = titleLayout.font; const titleNodes = titleLayout.hasContent && titleFont ? titleLayout.lines.map((line, index) => { var _a; return (<react_native_skia_1.Text key={`x-axis-title-line-${index}`} color={(_a = titleLayout.color) !== null && _a !== void 0 ? _a : labelColor} text={line} font={titleFont} y={titleY + index * titleLayout.lineHeight} x={titleX}/>); }) : null; const xAxisNodes = xTickLabels.map(({ tick, tickPosition, labelLayout }) => { const p1 = (0, react_native_skia_1.vec)(tickPosition, yScale(y2)); const p2 = (0, react_native_skia_1.vec)(tickPosition, yScale(y1)); const labelWidth = labelLayout.width; const { canRenderLabel, labelX, labelCenterX } = (0, getXAxisLabelPosition_1.getXAxisLabelPosition)({ tickPosition, labelWidth, chartBounds, }); const labelY = (() => { const multilineOffset = Math.max(0, labelLayout.height - fontSize); // bottom, outset if (axisSide === "bottom" && labelPosition === "outset") { return chartBounds.bottom + labelOffset + fontSize; } // bottom, inset if (axisSide === "bottom" && labelPosition === "inset") { return yScale(y2) - labelOffset - multilineOffset; } // top, outset if (axisSide === "top" && labelPosition === "outset") { return yScale(y1) - labelOffset - multilineOffset; } // top, inset return yScale(y1) + fontSize + labelOffset; })(); const labelTopY = (() => { if (axisSide === "bottom" && labelPosition === "outset") { return chartBounds.bottom + labelOffset; } if (axisSide === "bottom" && labelPosition === "inset") { return yScale(y2) - labelOffset - labelLayout.height; } if (axisSide === "top" && labelPosition === "outset") { return yScale(y1) - labelOffset - labelLayout.height; } return yScale(y1) + labelOffset; })(); // Calculate origin and translate for label rotation const { origin, rotateOffset } = (() => { let rotateOffset = 0; let origin; // return defaults if no labelRotate is provided if (!labelRotate) return { origin, rotateOffset }; if (axisSide === "bottom" && labelPosition === "outset") { // bottom, outset origin = (0, react_native_skia_1.vec)(labelCenterX, labelY); rotateOffset = Math.abs((labelWidth / 2) * (0, getOffsetFromAngle_1.getOffsetFromAngle)(labelRotate)); } else if (axisSide === "bottom" && labelPosition === "inset") { // bottom, inset origin = (0, react_native_skia_1.vec)(labelCenterX, labelY); rotateOffset = -Math.abs((labelWidth / 2) * (0, getOffsetFromAngle_1.getOffsetFromAngle)(labelRotate)); } else if (axisSide === "top" && labelPosition === "inset") { // top, inset origin = (0, react_native_skia_1.vec)(labelCenterX, labelY - fontSize / 4); rotateOffset = Math.abs((labelWidth / 2) * (0, getOffsetFromAngle_1.getOffsetFromAngle)(labelRotate)); } else { // top, outset origin = (0, react_native_skia_1.vec)(labelCenterX, labelY - fontSize / 4); rotateOffset = -Math.abs((labelWidth / 2) * (0, getOffsetFromAngle_1.getOffsetFromAngle)(labelRotate)); } return { origin, rotateOffset }; })(); const customOrigin = (0, react_native_skia_1.vec)(labelX + labelLayout.width / 2, labelTopY + labelLayout.height / 2); const canRenderCustomLabel = labelWidth > 0 && labelLayout.height > 0 && canRenderLabel; return (<react_1.default.Fragment key={`x-tick-${tick}`}> {lineWidth > 0 ? (<react_native_skia_1.Group clip={(0, boundsToClip_1.boundsToClip)(chartBounds)}> <react_native_skia_1.Line p1={p1} p2={p2} color={lineColor} strokeWidth={lineWidth}> {linePathEffect ? linePathEffect : null} </react_native_skia_1.Line> </react_native_skia_1.Group>) : null} {labelRenderer ? (canRenderCustomLabel ? (labelRenderer.render({ axis: "x", orientation, value: labelLayout.value, text: labelLayout.text, index: labelLayout.index, x: labelX, y: labelTopY, width: labelLayout.width, height: labelLayout.height, fontSize: labelLayout.fontSize, lineHeight: labelLayout.lineHeight, color: labelColor, canFitContent: canRenderLabel, chartBounds, rotation: labelRotate, origin: customOrigin, })) : null) : font && labelWidth && canRenderLabel ? (<react_native_skia_1.Group transform={[{ translateY: rotateOffset }]}> {labelLayout.lines.map((line, index) => (<react_native_skia_1.Text key={`x-tick-${tick}-label-line-${index}`} transform={[ { rotate: (Math.PI / 180) * (labelRotate !== null && labelRotate !== void 0 ? labelRotate : 0), }, ]} origin={origin} color={labelColor} text={line} font={font} y={labelY + index * labelLayout.lineHeight} x={labelX}/>))} </react_native_skia_1.Group>) : null} <></> </react_1.default.Fragment>); }); return (<> {xAxisNodes} {titleNodes} </>); }; exports.XAxis = XAxis;