victory-native
Version:
A charting library for React Native with a focus on performance and customization.
593 lines (592 loc) • 29.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CartesianChart = void 0;
const React = __importStar(require("react"));
const react_native_skia_1 = require("@shopify/react-native-skia");
const react_native_reanimated_1 = require("react-native-reanimated");
const its_fine_1 = require("its-fine");
const react_native_gesture_handler_1 = require("react-native-gesture-handler");
const react_fast_compare_1 = __importDefault(require("react-fast-compare"));
const transformInputData_1 = require("./utils/transformInputData");
const transformHorizontalInputData_1 = require("./utils/transformHorizontalInputData");
const valueFromSidedNumber_1 = require("../utils/valueFromSidedNumber");
const asNumber_1 = require("../utils/asNumber");
const useFunctionRef_1 = require("../hooks/useFunctionRef");
const CartesianChartContext_1 = require("./contexts/CartesianChartContext");
const XAxis_1 = require("./components/XAxis");
const YAxis_1 = require("./components/YAxis");
const CategoryYAxis_1 = require("./components/CategoryYAxis");
const Frame_1 = require("./components/Frame");
const useBuildChartAxis_1 = require("./hooks/useBuildChartAxis");
const transformGestures_1 = require("./utils/transformGestures");
const CartesianTransformContext_1 = require("./contexts/CartesianTransformContext");
const tickHelpers_1 = require("../utils/tickHelpers");
const GestureHandler_1 = require("../shared/GestureHandler");
const ChartWrapper_1 = require("../shared/ChartWrapper");
const useChartCanvasSize_1 = require("../shared/useChartCanvasSize");
const boundsToClip_1 = require("../utils/boundsToClip");
const normalizeYAxisTicks_1 = require("../utils/normalizeYAxisTicks");
const applyChartPressPanConfig_1 = require("./utils/applyChartPressPanConfig");
const createFallbackChartState_1 = require("./utils/createFallbackChartState");
const getCartesianTouchCoordinates_1 = require("./utils/getCartesianTouchCoordinates");
const resetChartPressState_1 = require("./utils/resetChartPressState");
const getClosestDatumIndex_1 = require("./utils/getClosestDatumIndex");
const getStackedBarTouchSegmentIndex_1 = require("./utils/getStackedBarTouchSegmentIndex");
const chartPressBootstrap_1 = require("./utils/chartPressBootstrap");
const createSafeZoomTransform_1 = require("./utils/createSafeZoomTransform");
const getCartesianChartBounds_1 = require("./utils/getCartesianChartBounds");
function CartesianChart(_a) {
var { transformState, children, ref } = _a, rest = __rest(_a, ["transformState", "children", "ref"]);
return (<its_fine_1.FiberProvider>
<CartesianTransformContext_1.CartesianTransformProvider transformState={transformState}>
<CartesianChartContent {...Object.assign(Object.assign({}, rest), { transformState })} ref={ref}>
{children}
</CartesianChartContent>
</CartesianTransformContext_1.CartesianTransformProvider>
</its_fine_1.FiberProvider>);
}
exports.CartesianChart = CartesianChart;
function CartesianCanvas(_a) {
var { children } = _a, props = __rest(_a, ["children"]);
const Bridge = (0, its_fine_1.useContextBridge)();
return (<ChartWrapper_1.ChartWrapper {...props} chartContent={children} wrapCanvasContent={(content) => <Bridge>{content}</Bridge>}/>);
}
function CartesianChartContent({ data, xKey, yKeys, orientation = "vertical", padding, domainPadding, children, renderOutside = () => null, axisOptions, domain, chartPressState, chartPressConfig, gestureHandlerConfig, onChartBoundsChange, onScaleChange, gestureLongPressDelay = 100, xAxis, yAxis, frame, transformState, transformConfig, customGestures, actionsRef, viewport, ref, explicitSize, headless, }) {
var _a, _b, _c, _d, _e;
const { size, hasMeasuredLayoutSize, onLayout, isHeadless } = (0, useChartCanvasSize_1.useChartCanvasSize)({ explicitSize, headless });
const chartBoundsRef = React.useRef(undefined);
const xScaleRef = React.useRef(undefined);
const yScaleRef = React.useRef(undefined);
const canvasRef = React.useRef(null);
const chartPressStateRef = React.useRef(chartPressState);
chartPressStateRef.current = chartPressState;
const yKeysKey = yKeys.join("\u0000");
const normalizedAxisProps = (0, useBuildChartAxis_1.useBuildChartAxis)({
xAxis: xAxis,
yAxis: yAxis,
frame,
yKeys,
axisOptions: axisOptions,
});
const axisScales = axisOptions === null || axisOptions === void 0 ? void 0 : axisOptions.axisScales;
// create a d3-zoom transform object based on the current transform state. This
// is used for rescaling the X and Y axes.
const transform = (0, CartesianTransformContext_1.useCartesianTransformContext)();
const zoomX = React.useMemo(() => (0, createSafeZoomTransform_1.createSafeZoomTransform)(transform.k, transform.tx, transform.ty), [transform.k, transform.tx, transform.ty]);
const zoomY = React.useMemo(() => (0, createSafeZoomTransform_1.createSafeZoomTransform)(transform.ky, transform.tx, transform.ty), [transform.ky, transform.tx, transform.ty]);
const tData = (0, react_native_reanimated_1.useSharedValue)({
ix: [],
ox: [],
y: yKeys.reduce((acc, key) => {
acc[key] = { i: [], o: [] };
return acc;
}, {}),
});
const { yAxes, xScale, chartBounds, isNumericalData, xTicksNormalized, _tData, } = React.useMemo(() => {
if (!data.length) {
return (0, createFallbackChartState_1.createFallbackChartState)(yKeys);
}
const transformArgs = {
data,
xKey,
yKeys,
outputWindow: {
xMin: (0, valueFromSidedNumber_1.valueFromSidedNumber)(padding, "left"),
xMax: size.width - (0, valueFromSidedNumber_1.valueFromSidedNumber)(padding, "right"),
yMin: (0, valueFromSidedNumber_1.valueFromSidedNumber)(padding, "top"),
yMax: size.height - (0, valueFromSidedNumber_1.valueFromSidedNumber)(padding, "bottom"),
},
domain,
domainPadding,
viewport,
labelRotate: normalizedAxisProps.xAxis.labelRotate,
axisScales,
};
const transformed = orientation === "horizontal"
? (0, transformHorizontalInputData_1.transformHorizontalInputData)(Object.assign(Object.assign({}, transformArgs), { xAxis: normalizedAxisProps.xAxis, yAxes: normalizedAxisProps.yAxes }))
: (0, transformInputData_1.transformInputData)(Object.assign(Object.assign({}, transformArgs), { xAxis: normalizedAxisProps.xAxis, yAxes: normalizedAxisProps.yAxes }));
const { xScale, yAxes, isNumericalData, xTicksNormalized } = transformed, _tData = __rest(transformed, ["xScale", "yAxes", "isNumericalData", "xTicksNormalized"]);
const primaryYAxis = yAxes[0];
const primaryYScale = primaryYAxis.yScale;
const chartBounds = (0, getCartesianChartBounds_1.getCartesianChartBounds)({
xScale,
yScale: primaryYScale,
viewport,
domainPadding,
orientation,
});
return {
xTicksNormalized,
yAxes,
xScale,
chartBounds,
isNumericalData,
_tData,
};
}, [
data,
xKey,
yKeys,
padding,
size.width,
size.height,
domain,
domainPadding,
normalizedAxisProps,
axisScales,
viewport,
orientation,
]);
React.useEffect(() => {
tData.value = _tData;
}, [_tData, tData]);
const primaryYAxis = yAxes[0];
const primaryYScale = primaryYAxis.yScale;
// stacked bar values
const chartHeight = chartBounds.bottom;
const yScaleTop = primaryYAxis.yScale.domain().at(0);
const yScaleBottom = primaryYAxis.yScale.domain().at(-1);
const chartWidth = chartBounds.right - chartBounds.left;
const xScaleLeft = xScale.invert(chartBounds.left);
const xScaleRight = xScale.invert(chartBounds.right);
// end stacked bar values
/**
* Pan gesture handling
*/
const lastIdx = (0, react_native_reanimated_1.useSharedValue)(null);
/**
* Take a "press value" and an x-value and update the shared values accordingly.
*/
const handleTouch = React.useCallback((v, x, y) => {
"worklet";
const idx = (0, getClosestDatumIndex_1.getClosestDatumIndex)({
orientation,
categoryPositions: tData.value.ox,
touchX: x,
touchY: y,
});
if (typeof idx !== "number")
return;
const isInYs = (yk) => yKeys.includes(yk);
// begin stacked bar handling:
// store the heights of each bar segment
const barHeights = [];
for (const yk in v.y) {
if (isInYs(yk)) {
const height = (0, asNumber_1.asNumber)(tData.value.y[yk].i[idx]);
barHeights.push(height);
}
}
if (orientation === "horizontal") {
const chartXPressed = x - chartBounds.left;
const xDomainValue = chartWidth > 0 &&
xScaleLeft !== undefined &&
xScaleRight !== undefined
? (chartXPressed / chartWidth) * (xScaleRight - xScaleLeft) +
xScaleLeft
: NaN;
v.yIndex.value = (0, getStackedBarTouchSegmentIndex_1.getStackedBarTouchSegmentIndex)({
values: barHeights,
touchValue: xDomainValue,
});
}
else {
const chartYPressed = chartHeight - y; // Invert y-coordinate, since RNGH gives us the absolute Y, and we want to know where in the chart they clicked
// Calculate the actual yValue of the touch within the domain of the yScale
const yDomainValue = (chartYPressed / chartHeight) * (yScaleTop - yScaleBottom);
// track the cumulative height and the y-index of the touched segment
let cumulativeHeight = 0;
let yIndex = -1;
// loop through the bar heights to find which bar was touched
for (let i = 0; i < barHeights.length; i++) {
// Accumulate the height as we go along
cumulativeHeight += barHeights[i];
// Check if the y-value touched falls within the current segment
if (yDomainValue <= cumulativeHeight) {
// If it does, set yIndex to the current segment index and break
yIndex = i;
break;
}
}
// Update the yIndex value in the state or context
v.yIndex.value = yIndex;
}
// end stacked bar handling
if (v) {
try {
v.matchedIndex.value = idx;
v.x.value.value = tData.value.ix[idx];
v.x.position.value = (0, asNumber_1.asNumber)(tData.value.ox[idx]);
for (const yk in v.y) {
if (isInYs(yk)) {
v.y[yk].value.value = (0, asNumber_1.asNumber)(tData.value.y[yk].i[idx]);
v.y[yk].position.value = (0, asNumber_1.asNumber)(tData.value.y[yk].o[idx]);
}
}
}
catch (err) {
// no-op
}
}
lastIdx.value = idx;
}, [
chartBounds.left,
chartHeight,
chartWidth,
lastIdx,
orientation,
tData,
xScaleLeft,
xScaleRight,
yKeys,
yScaleBottom,
yScaleTop,
]);
React.useImperativeHandle(ref, () => ({
canvas: canvasRef.current,
actions: {
handleTouch,
},
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[canvasRef]);
const handleTouchRef = (0, useFunctionRef_1.useFunctionRef)(handleTouch);
const mutableActionsRef = actionsRef && "current" in actionsRef ? actionsRef : undefined;
const sharedActionsRef = actionsRef && "value" in actionsRef ? actionsRef : undefined;
React.useImperativeHandle(mutableActionsRef, () => ({
handleTouch: (value, x, y) => {
var _a;
(_a = handleTouchRef.current) === null || _a === void 0 ? void 0 : _a.call(handleTouchRef, value, x, y);
},
}), [handleTouchRef]);
React.useEffect(() => {
if (!sharedActionsRef)
return;
sharedActionsRef.value = {
handleTouch,
};
return () => {
sharedActionsRef.value = null;
};
}, [handleTouch, sharedActionsRef]);
/**
* Touch gesture is a modified Pan gesture handler that allows for multiple presses:
* - Using Pan Gesture handler effectively _just_ for the .activateAfterLongPress functionality.
* - Tracking the finger is handled with .onTouchesMove instead of .onUpdate, because
* .onTouchesMove gives us access to each individual finger.
* - The activation gets a bit complicated because we want to wait til "start" state before updating Press Value
* which gives time for the gesture to get cancelled before we start updating the shared values.
* Therefore we use gestureState.bootstrap to store some "bootstrap" information if gesture isn't active when finger goes down.
*/
// touch ID -> value index mapping to keep track of which finger updates which value
const touchMap = (0, react_native_reanimated_1.useSharedValue)({});
const activePressSharedValues = Array.isArray(chartPressState)
? chartPressState
: [chartPressState];
const gestureState = (0, react_native_reanimated_1.useSharedValue)({
isGestureActive: false,
bootstrap: [],
});
React.useEffect(() => {
const vals = chartPressStateRef.current;
const states = Array.isArray(vals) ? vals : [vals];
for (const state of states) {
if (state)
(0, resetChartPressState_1.resetChartPressState)(state);
}
touchMap.value = {};
gestureState.value = {
isGestureActive: false,
bootstrap: [],
};
lastIdx.value = null;
}, [data, gestureState, lastIdx, touchMap, xKey, yKeysKey]);
const panGesture = react_native_gesture_handler_1.Gesture.Pan()
/**
* When a finger goes down, either update the state or store in the bootstrap array.
*/
.onTouchesDown((e) => {
const vals = activePressSharedValues || [];
if (!vals.length || e.numberOfTouches === 0)
return;
for (let i = 0; i < Math.min(e.allTouches.length, vals.length); i++) {
const touch = e.allTouches[i];
const v = vals[i];
if (!v || !touch)
continue;
if (gestureState.value.isGestureActive) {
// Update the mapping
if (typeof touchMap.value[touch.id] !== "number")
touchMap.value[touch.id] = i;
v.isActive.value = true;
const touchPoint = (0, getCartesianTouchCoordinates_1.getCartesianTouchCoordinates)({
touch,
transform: transformState === null || transformState === void 0 ? void 0 : transformState.matrix.value,
});
handleTouch(v, touchPoint.x, touchPoint.y);
}
else {
gestureState.value.bootstrap.push({
pressIndex: i,
state: v,
touch,
});
}
}
})
/**
* On start, check if we have any bootstrapped updates we need to apply.
*/
.onStart(() => {
gestureState.value.isGestureActive = true;
const bootstrap = gestureState.value.bootstrap.slice(0);
gestureState.value.bootstrap = [];
for (let i = 0; i < bootstrap.length; i++) {
const { pressIndex, state: v, touch } = bootstrap[i];
// Update the mapping
if (typeof touchMap.value[touch.id] !== "number")
touchMap.value[touch.id] = pressIndex;
v.isActive.value = true;
const touchPoint = (0, getCartesianTouchCoordinates_1.getCartesianTouchCoordinates)({
touch,
transform: transformState === null || transformState === void 0 ? void 0 : transformState.matrix.value,
});
handleTouch(v, touchPoint.x, touchPoint.y);
}
})
/**
* Clear gesture state on gesture end.
*/
.onFinalize(() => {
const vals = activePressSharedValues || [];
for (const val of vals) {
if (val) {
val.isActive.value = false;
}
}
touchMap.value = {};
gestureState.value = {
isGestureActive: false,
bootstrap: [],
};
})
/**
* As fingers move, update the shared values accordingly.
*/
.onTouchesMove((e) => {
const vals = activePressSharedValues || [];
if (!vals.length || e.numberOfTouches === 0)
return;
for (let i = 0; i < Math.min(e.allTouches.length, vals.length); i++) {
const touch = e.allTouches[i];
const touchId = touch === null || touch === void 0 ? void 0 : touch.id;
const idx = typeof touchId === "number" && touchMap.value[touchId];
const v = typeof idx === "number" && (vals === null || vals === void 0 ? void 0 : vals[idx]);
if (!v || !touch)
continue;
if (!v.isActive.value)
v.isActive.value = true;
const touchPoint = (0, getCartesianTouchCoordinates_1.getCartesianTouchCoordinates)({
touch,
transform: transformState === null || transformState === void 0 ? void 0 : transformState.matrix.value,
});
handleTouch(v, touchPoint.x, touchPoint.y);
}
})
/**
* On each finger up, start to update values and "free up" the touch map.
*/
.onTouchesUp((e) => {
gestureState.value.bootstrap = (0, chartPressBootstrap_1.pruneChartPressBootstrap)({
bootstrap: gestureState.value.bootstrap,
changedTouches: e.changedTouches,
numberOfTouches: e.numberOfTouches,
});
for (const touch of e.changedTouches) {
const vals = activePressSharedValues || [];
// Set active state to false
const touchId = touch === null || touch === void 0 ? void 0 : touch.id;
const idx = typeof touchId === "number" && touchMap.value[touchId];
const val = typeof idx === "number" && vals[idx];
if (val) {
val.isActive.value = false;
}
// Free up touch map for this touch
touchMap.value[touch.id] = undefined;
}
})
/**
* Once the gesture ends, ensure all active values are falsified.
*/
.onEnd(() => {
const vals = activePressSharedValues || [];
// Set active state to false for all vals
for (const val of vals) {
if (val) {
val.isActive.value = false;
}
}
});
(0, applyChartPressPanConfig_1.applyChartPressPanConfig)({
panGesture,
panConfig: chartPressConfig === null || chartPressConfig === void 0 ? void 0 : chartPressConfig.pan,
gestureLongPressDelay,
});
const points = React.useMemo(() => {
const cache = {};
return new Proxy({}, {
get(_, property) {
const key = property;
if (!yKeys.includes(key))
return undefined;
if (cache[key])
return cache[key];
cache[key] = _tData.ix.map((x, i) => ({
x: orientation === "horizontal"
? (0, asNumber_1.asNumber)(_tData.y[key].o[i])
: (0, asNumber_1.asNumber)(_tData.ox[i]),
xValue: x,
y: orientation === "horizontal"
? (0, asNumber_1.asNumber)(_tData.ox[i])
: _tData.y[key].o[i],
yValue: _tData.y[key].i[i],
}));
return cache[key];
},
});
}, [_tData, orientation, yKeys]);
// On bounds change, emit
const onChartBoundsRef = (0, useFunctionRef_1.useFunctionRef)(onChartBoundsChange);
React.useEffect(() => {
var _a;
if (!(0, react_fast_compare_1.default)(chartBounds, chartBoundsRef.current)) {
chartBoundsRef.current = chartBounds;
(_a = onChartBoundsRef.current) === null || _a === void 0 ? void 0 : _a.call(onChartBoundsRef, chartBounds);
}
}, [chartBounds, onChartBoundsRef]);
const onScaleRef = (0, useFunctionRef_1.useFunctionRef)(onScaleChange);
React.useEffect(() => {
var _a, _b, _c, _d, _e;
const rescaledX = zoomX.rescaleX(xScale);
const rescaledY = zoomY.rescaleY(primaryYScale);
if (!(0, react_fast_compare_1.default)((_a = xScaleRef.current) === null || _a === void 0 ? void 0 : _a.domain(), rescaledX.domain()) ||
!(0, react_fast_compare_1.default)((_b = yScaleRef.current) === null || _b === void 0 ? void 0 : _b.domain(), rescaledY.domain()) ||
!(0, react_fast_compare_1.default)((_c = xScaleRef.current) === null || _c === void 0 ? void 0 : _c.range(), rescaledX.range()) ||
!(0, react_fast_compare_1.default)((_d = yScaleRef.current) === null || _d === void 0 ? void 0 : _d.range(), rescaledY.range())) {
xScaleRef.current = xScale;
yScaleRef.current = primaryYScale;
(_e = onScaleRef.current) === null || _e === void 0 ? void 0 : _e.call(onScaleRef, rescaledX, rescaledY);
}
}, [onScaleChange, onScaleRef, xScale, zoomX, zoomY, primaryYScale]);
const renderArg = {
xScale,
xTicks: xTicksNormalized,
yScale: primaryYScale,
yTicks: primaryYAxis.yTicksNormalized,
chartBounds,
canvasSize: size,
points,
};
const clipRect = (0, boundsToClip_1.boundsToClip)(chartBounds);
const YAxisComponents = hasMeasuredLayoutSize && (axisOptions || yAxes)
? (_a = normalizedAxisProps.yAxes) === null || _a === void 0 ? void 0 : _a.map((axis, index) => {
const yAxis = yAxes[index];
if (!yAxis)
return null;
if (orientation === "horizontal") {
return (<CategoryYAxis_1.CategoryYAxis key={index} {...axis} formatYLabel={axis.formatYLabel} labelRenderer={axis.labelRenderer} xScale={zoomX.rescaleX(xScale)} yScale={zoomY.rescaleY(yAxis.yScale)} yTicksNormalized={yAxis.yTicksNormalized} ix={_tData.ix} chartBounds={chartBounds}/>);
}
const primaryAxisProps = normalizedAxisProps.yAxes[0];
const primaryRescaled = zoomY.rescaleY(primaryYScale);
const rescaled = zoomY.rescaleY(yAxis.yScale);
const rescaledTicks = axis.tickValues
? (0, tickHelpers_1.downsampleTicks)(axis.tickValues, axis.tickCount)
: axis.enableRescaling
? rescaled.ticks(axis.tickCount)
: yAxis.yScale.ticks(axis.tickCount);
const primaryTicksRescaled = primaryAxisProps.tickValues
? (0, tickHelpers_1.downsampleTicks)(primaryAxisProps.tickValues, primaryAxisProps.tickCount)
: primaryAxisProps.enableRescaling
? primaryRescaled.ticks(primaryAxisProps.tickCount)
: primaryYScale.ticks(primaryAxisProps.tickCount);
return (<YAxis_1.YAxis key={index} {...axis} xScale={zoomX.rescaleX(xScale)} yScale={rescaled} yTicksNormalized={index > 0 && !axis.tickValues
? (0, normalizeYAxisTicks_1.normalizeYAxisTicks)(primaryTicksRescaled, primaryRescaled, rescaled)
: rescaledTicks} chartBounds={chartBounds} orientation={orientation}/>);
})
: null;
const XAxisComponents = hasMeasuredLayoutSize && (axisOptions || xAxis) ? (<XAxis_1.XAxis {...normalizedAxisProps.xAxis} xScale={xScale} yScale={zoomY.rescaleY(primaryYScale)} ix={_tData.ix} isNumericalData={orientation === "horizontal" ? true : isNumericalData} chartBounds={chartBounds} orientation={orientation} zoom={zoomX}/>) : null;
const FrameComponent = hasMeasuredLayoutSize && (axisOptions || frame) ? (<Frame_1.Frame {...normalizedAxisProps.frame} xScale={xScale} yScale={primaryYScale}/>) : null;
const chartContent = (<>
{YAxisComponents}
{XAxisComponents}
{FrameComponent}
<react_native_skia_1.Group clip={clipRect}>
<react_native_skia_1.Group matrix={transformState === null || transformState === void 0 ? void 0 : transformState.matrix}>
{hasMeasuredLayoutSize && children(renderArg)}
</react_native_skia_1.Group>
</react_native_skia_1.Group>
{hasMeasuredLayoutSize && (renderOutside === null || renderOutside === void 0 ? void 0 : renderOutside(renderArg))}
</>);
let gestureOverlay;
if (!isHeadless) {
let composed = customGestures !== null && customGestures !== void 0 ? customGestures : react_native_gesture_handler_1.Gesture.Race();
if (transformState) {
let gestures = react_native_gesture_handler_1.Gesture.Simultaneous();
if ((_c = (_b = transformConfig === null || transformConfig === void 0 ? void 0 : transformConfig.pinch) === null || _b === void 0 ? void 0 : _b.enabled) !== null && _c !== void 0 ? _c : true) {
gestures = react_native_gesture_handler_1.Gesture.Simultaneous(gestures, (0, transformGestures_1.pinchTransformGesture)(transformState, transformConfig === null || transformConfig === void 0 ? void 0 : transformConfig.pinch));
}
if ((_e = (_d = transformConfig === null || transformConfig === void 0 ? void 0 : transformConfig.pan) === null || _d === void 0 ? void 0 : _d.enabled) !== null && _e !== void 0 ? _e : true) {
gestures = react_native_gesture_handler_1.Gesture.Simultaneous(gestures, (0, transformGestures_1.panTransformGesture)(transformState, transformConfig === null || transformConfig === void 0 ? void 0 : transformConfig.pan));
}
composed = react_native_gesture_handler_1.Gesture.Race(composed, react_native_gesture_handler_1.Gesture.Simultaneous(gestures));
}
if (chartPressState) {
composed = react_native_gesture_handler_1.Gesture.Race(composed, panGesture);
}
gestureOverlay = (<GestureHandler_1.GestureHandler config={gestureHandlerConfig} gesture={composed}/>);
}
return (<CartesianTransformContext_1.CartesianTransformValueProvider value={transform}>
<CartesianChartContext_1.CartesianChartProvider yScale={primaryYScale} xScale={xScale} orientation={orientation}>
<CartesianCanvas isHeadless={isHeadless} explicitSize={explicitSize} onLayout={onLayout} hasMeasuredLayoutSize={hasMeasuredLayoutSize} canvasSize={size} canvasRef={canvasRef} gestureOverlay={gestureOverlay}>
{chartContent}
</CartesianCanvas>
</CartesianChartContext_1.CartesianChartProvider>
</CartesianTransformContext_1.CartesianTransformValueProvider>);
}