victory-native
Version:
A charting library for React Native with a focus on performance and customization.
243 lines (242 loc) • 10.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformHorizontalInputData = void 0;
const getOffsetFromAngle_1 = require("../../utils/getOffsetFromAngle");
const tickHelpers_1 = require("../../utils/tickHelpers");
const getAxisLabelLayout_1 = require("./getAxisLabelLayout");
const getAxisTitleLayout_1 = require("./getAxisTitleLayout");
const getXAxisTicks_1 = require("./getXAxisTicks");
const getYScaleInputBounds_1 = require("./getYScaleInputBounds");
const makeScale_1 = require("./makeScale");
const transformHorizontalInputData = ({ data: _data, xKey, yKeys, outputWindow, domain, domainPadding, xAxis, yAxes, viewport, labelRotate, axisScales, }) => {
const data = [..._data];
const { xAxisScale = "linear" } = axisScales || {};
const isNumericalData = data.every((datum) => typeof datum[xKey] === "number");
if (isNumericalData) {
data.sort((a, b) => +a[xKey] - +b[xKey]);
}
const y = yKeys.reduce((acc, k) => {
acc[k] = { i: [], o: [] };
return acc;
}, {});
const ix = data.map((datum) => datum[xKey]);
const categoryIndexes = ix.map((_, index) => index);
const categoryAxisLayouts = yAxes.map((yAxis) => {
const ticks = yAxis.tickValues
? (0, tickHelpers_1.downsampleTicks)(yAxis.tickValues, yAxis.tickCount)
: (0, tickHelpers_1.downsampleTicks)(categoryIndexes, yAxis.tickCount);
const labelLayouts = ticks.map((tick, index) => {
const categoryValue = ix[tick];
const labelValue = yAxis.formatYLabel
? yAxis.formatYLabel(categoryValue)
: String(categoryValue !== null && categoryValue !== void 0 ? categoryValue : tick);
return (0, getAxisLabelLayout_1.getAxisLabelLayout)({
axis: "y",
orientation: "horizontal",
value: categoryValue,
text: String(labelValue),
index,
font: yAxis.font,
labelRenderer: yAxis.labelRenderer,
});
});
const maxLabelLayout = (0, getAxisLabelLayout_1.getMaxAxisLabelLayout)(labelLayouts);
const titleLayout = (0, getAxisTitleLayout_1.getAxisTitleLayout)({
title: yAxis.title,
font: yAxis.font,
});
const titleOutset = titleLayout.hasContent
? titleLayout.height + titleLayout.offset
: 0;
return {
ticks,
maxLabelLayout,
titleOutset,
};
});
const valueTickValues = xAxis.tickValues;
const valueTickCount = xAxis.tickCount;
const tickDomainsX = (0, tickHelpers_1.getDomainFromTicks)(valueTickValues);
const valueInputBounds = getHorizontalValueInputBounds({
data,
yKeys: yKeys,
domain: domain === null || domain === void 0 ? void 0 : domain.x,
tickDomain: tickDomainsX,
includeZero: !(domain === null || domain === void 0 ? void 0 : domain.x) && !tickDomainsX,
});
const rawChartWidth = outputWindow.xMax - outputWindow.xMin;
const xTempScale = (0, makeScale_1.makeScale)({
inputBounds: valueInputBounds,
outputBounds: [0, rawChartWidth],
axisScale: xAxisScale,
});
const xTicksForLabelLayout = (0, getXAxisTicks_1.getXAxisTicks)({
isNumericalData: true,
ix: [],
tickCount: valueTickCount,
tickValues: valueTickValues,
xScale: xTempScale,
});
const xAxisLabelLayouts = xTicksForLabelLayout.map((xTick, index) => {
const labelValue = xAxis.formatXLabel
? xAxis.formatXLabel(xTick)
: String(xTick);
return (0, getAxisLabelLayout_1.getAxisLabelLayout)({
axis: "x",
orientation: "horizontal",
value: xTick,
text: String(labelValue),
index,
font: xAxis.font,
labelRenderer: xAxis.labelRenderer,
});
});
const maxXLabelLayout = (0, getAxisLabelLayout_1.getMaxAxisLabelLayout)(xAxisLabelLayouts);
const xAxisTitleLayout = (0, getAxisTitleLayout_1.getAxisTitleLayout)({
title: xAxis.title,
font: xAxis.font,
});
const xAxisTitleOutset = xAxisTitleLayout.hasContent
? xAxisTitleLayout.height + xAxisTitleLayout.offset
: 0;
const adjustedOutputWindow = Object.assign({}, outputWindow);
if (labelRotate && xAxis.labelPosition === "outset") {
const rotateOffset = Math.abs(maxXLabelLayout.width * (0, getOffsetFromAngle_1.getOffsetFromAngle)(labelRotate));
if (xAxis.axisSide === "bottom") {
adjustedOutputWindow.yMax -= rotateOffset;
}
else if (xAxis.axisSide === "top") {
adjustedOutputWindow.yMin += rotateOffset;
}
}
const xRange = (() => {
let xMinAdjustment = 0;
let xMaxAdjustment = 0;
yAxes.forEach((axis, index) => {
var _a, _b, _c, _d;
const labelWidth = (_b = (_a = categoryAxisLayouts[index]) === null || _a === void 0 ? void 0 : _a.maxLabelLayout.width) !== null && _b !== void 0 ? _b : 0;
const titleOutset = (_d = (_c = categoryAxisLayouts[index]) === null || _c === void 0 ? void 0 : _c.titleOutset) !== null && _d !== void 0 ? _d : 0;
if (axis.axisSide === "left") {
xMinAdjustment += titleOutset;
if (axis.labelPosition === "outset" &&
axis.tickCount > 0 &&
labelWidth > 0) {
xMinAdjustment += labelWidth + axis.labelOffset;
}
}
if (axis.axisSide === "right") {
xMaxAdjustment -= titleOutset;
if (axis.labelPosition === "outset" &&
axis.tickCount > 0 &&
labelWidth > 0) {
xMaxAdjustment -= labelWidth + axis.labelOffset;
}
}
});
return [
adjustedOutputWindow.xMin + xMinAdjustment,
adjustedOutputWindow.xMax + xMaxAdjustment,
];
})();
const categoryRange = (() => {
var _a;
const xLabelOffset = (_a = xAxis.labelOffset) !== null && _a !== void 0 ? _a : 0;
const xLabelOutset = valueTickCount > 0 && maxXLabelLayout.width > 0
? maxXLabelLayout.height + xLabelOffset * 2
: 0;
const xAxisOutset = xAxisTitleOutset + (xAxis.labelPosition === "outset" ? xLabelOutset : 0);
if (xAxis.axisSide === "bottom") {
return [
adjustedOutputWindow.yMin,
adjustedOutputWindow.yMax - xAxisOutset,
];
}
if (xAxis.axisSide === "top") {
return [
adjustedOutputWindow.yMin + xAxisOutset,
adjustedOutputWindow.yMax,
];
}
return [adjustedOutputWindow.yMin, adjustedOutputWindow.yMax];
})();
const xScale = (0, makeScale_1.makeScale)({
inputBounds: valueInputBounds,
outputBounds: xRange,
viewport: viewport === null || viewport === void 0 ? void 0 : viewport.x,
padStart: typeof domainPadding === "number" ? domainPadding : domainPadding === null || domainPadding === void 0 ? void 0 : domainPadding.left,
padEnd: typeof domainPadding === "number" ? domainPadding : domainPadding === null || domainPadding === void 0 ? void 0 : domainPadding.right,
axisScale: xAxisScale,
});
const categoryInputBounds = getCategoryInputBounds(categoryIndexes);
const yScale = (0, makeScale_1.makeScale)({
inputBounds: categoryInputBounds,
outputBounds: categoryRange,
viewport: viewport === null || viewport === void 0 ? void 0 : viewport.y,
padStart: typeof domainPadding === "number" ? domainPadding : domainPadding === null || domainPadding === void 0 ? void 0 : domainPadding.top,
padEnd: typeof domainPadding === "number" ? domainPadding : domainPadding === null || domainPadding === void 0 ? void 0 : domainPadding.bottom,
});
const yData = yKeys.reduce((acc, key) => {
acc[key] = {
i: data.map((datum) => datum[key]),
o: data.map((datum) => typeof datum[key] === "number"
? xScale(datum[key])
: datum[key]),
};
return acc;
}, {});
yKeys.forEach((yKey) => {
y[yKey].i = data.map((datum) => datum[yKey]);
y[yKey].o = data.map((datum) => (typeof datum[yKey] === "number"
? xScale(datum[yKey])
: datum[yKey]));
});
const ox = categoryIndexes.map((index) => yScale(index));
const xTicksNormalized = (0, getXAxisTicks_1.getXAxisTicks)({
isNumericalData: true,
ix: [],
tickCount: valueTickCount,
tickValues: valueTickValues,
xScale,
});
const yAxesTransformed = yAxes.map((_, index) => {
var _a, _b, _c, _d;
return ({
yScale,
yTicksNormalized: (_b = (_a = categoryAxisLayouts[index]) === null || _a === void 0 ? void 0 : _a.ticks) !== null && _b !== void 0 ? _b : [],
yData,
maxYLabel: (_d = (_c = categoryAxisLayouts[index]) === null || _c === void 0 ? void 0 : _c.maxLabelLayout.width) !== null && _d !== void 0 ? _d : 0,
});
});
return {
ix,
y,
isNumericalData,
ox,
xScale,
xTicksNormalized,
yAxes: [yAxesTransformed[0], ...yAxesTransformed.slice(1)],
};
};
exports.transformHorizontalInputData = transformHorizontalInputData;
const getCategoryInputBounds = (indexes) => {
var _a, _b;
const first = (_a = indexes.at(0)) !== null && _a !== void 0 ? _a : 0;
const last = (_b = indexes.at(-1)) !== null && _b !== void 0 ? _b : 0;
return first === last ? [first - 1, last + 1] : [first, last];
};
const getHorizontalValueInputBounds = ({ data, yKeys, domain, tickDomain, includeZero, }) => {
const { yMin, yMax } = (0, getYScaleInputBounds_1.getYScaleInputBounds)({
data,
yKeys,
domain,
tickDomain,
});
if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {
return [-1, 1];
}
const valueMin = includeZero ? Math.min(0, yMin) : yMin;
const valueMax = includeZero ? Math.max(0, yMax) : yMax;
return valueMin === valueMax
? [valueMin - 1, valueMax + 1]
: [valueMin, valueMax];
};