173 lines
6.1 KiB
JavaScript
173 lines
6.1 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.useBarPlotData = useBarPlotData;
|
|
var _getColor = _interopRequireDefault(require("./seriesConfig/getColor"));
|
|
var _hooks = require("../hooks");
|
|
var _checkScaleErrors = require("./checkScaleErrors");
|
|
var _useBarSeries = require("../hooks/useBarSeries");
|
|
function useBarPlotData(drawingArea, xAxes, yAxes) {
|
|
const seriesData = (0, _useBarSeries.useBarSeriesContext)() ?? {
|
|
series: {},
|
|
stackingGroups: [],
|
|
seriesOrder: []
|
|
};
|
|
const defaultXAxisId = (0, _hooks.useXAxes)().xAxisIds[0];
|
|
const defaultYAxisId = (0, _hooks.useYAxes)().yAxisIds[0];
|
|
const chartId = (0, _hooks.useChartId)();
|
|
const {
|
|
series,
|
|
stackingGroups
|
|
} = seriesData;
|
|
const masks = {};
|
|
const data = stackingGroups.flatMap(({
|
|
ids: seriesIds
|
|
}, groupIndex) => {
|
|
const xMin = drawingArea.left;
|
|
const xMax = drawingArea.left + drawingArea.width;
|
|
const yMin = drawingArea.top;
|
|
const yMax = drawingArea.top + drawingArea.height;
|
|
return seriesIds.map(seriesId => {
|
|
const xAxisId = series[seriesId].xAxisId ?? defaultXAxisId;
|
|
const yAxisId = series[seriesId].yAxisId ?? defaultYAxisId;
|
|
const xAxisConfig = xAxes[xAxisId];
|
|
const yAxisConfig = yAxes[yAxisId];
|
|
const verticalLayout = series[seriesId].layout === 'vertical';
|
|
(0, _checkScaleErrors.checkScaleErrors)(verticalLayout, seriesId, series[seriesId], xAxisId, xAxes, yAxisId, yAxes);
|
|
const baseScaleConfig = verticalLayout ? xAxisConfig : yAxisConfig;
|
|
const xScale = xAxisConfig.scale;
|
|
const yScale = yAxisConfig.scale;
|
|
const colorGetter = (0, _getColor.default)(series[seriesId], xAxes[xAxisId], yAxes[yAxisId]);
|
|
const bandWidth = baseScaleConfig.scale.bandwidth();
|
|
const {
|
|
barWidth,
|
|
offset
|
|
} = getBandSize({
|
|
bandWidth,
|
|
numberOfGroups: stackingGroups.length,
|
|
gapRatio: baseScaleConfig.barGapRatio
|
|
});
|
|
const barOffset = groupIndex * (barWidth + offset);
|
|
const {
|
|
stackedData,
|
|
data: currentSeriesData,
|
|
layout,
|
|
minBarSize
|
|
} = series[seriesId];
|
|
const seriesDataPoints = baseScaleConfig.data.map((baseValue, dataIndex) => {
|
|
if (currentSeriesData[dataIndex] == null) {
|
|
return null;
|
|
}
|
|
const values = stackedData[dataIndex];
|
|
const valueCoordinates = values.map(v => verticalLayout ? yScale(v) : xScale(v));
|
|
const minValueCoord = Math.round(Math.min(...valueCoordinates));
|
|
const maxValueCoord = Math.round(Math.max(...valueCoordinates));
|
|
const stackId = series[seriesId].stack;
|
|
const {
|
|
barSize,
|
|
startCoordinate
|
|
} = getValueCoordinate(verticalLayout, minValueCoord, maxValueCoord, currentSeriesData[dataIndex], minBarSize);
|
|
const result = {
|
|
seriesId,
|
|
dataIndex,
|
|
layout,
|
|
x: verticalLayout ? xScale(baseValue) + barOffset : startCoordinate,
|
|
y: verticalLayout ? startCoordinate : yScale(baseValue) + barOffset,
|
|
xOrigin: xScale(0) ?? 0,
|
|
yOrigin: yScale(0) ?? 0,
|
|
height: verticalLayout ? barSize : barWidth,
|
|
width: verticalLayout ? barWidth : barSize,
|
|
color: colorGetter(dataIndex),
|
|
value: currentSeriesData[dataIndex],
|
|
maskId: `${chartId}_${stackId || seriesId}_${groupIndex}_${dataIndex}`
|
|
};
|
|
if (result.x > xMax || result.x + result.width < xMin || result.y > yMax || result.y + result.height < yMin) {
|
|
return null;
|
|
}
|
|
if (!masks[result.maskId]) {
|
|
masks[result.maskId] = {
|
|
id: result.maskId,
|
|
width: 0,
|
|
height: 0,
|
|
hasNegative: false,
|
|
hasPositive: false,
|
|
layout: result.layout,
|
|
xOrigin: xScale(0),
|
|
yOrigin: yScale(0),
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
}
|
|
const mask = masks[result.maskId];
|
|
mask.width = result.layout === 'vertical' ? result.width : mask.width + result.width;
|
|
mask.height = result.layout === 'vertical' ? mask.height + result.height : result.height;
|
|
mask.x = Math.min(mask.x === 0 ? Infinity : mask.x, result.x);
|
|
mask.y = Math.min(mask.y === 0 ? Infinity : mask.y, result.y);
|
|
mask.hasNegative = mask.hasNegative || (result.value ?? 0) < 0;
|
|
mask.hasPositive = mask.hasPositive || (result.value ?? 0) > 0;
|
|
return result;
|
|
}).filter(rectangle => rectangle !== null);
|
|
return {
|
|
seriesId,
|
|
data: seriesDataPoints
|
|
};
|
|
});
|
|
});
|
|
return {
|
|
completedData: data,
|
|
masksData: Object.values(masks)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Solution of the equations
|
|
* W = barWidth * N + offset * (N-1)
|
|
* offset / (offset + barWidth) = r
|
|
* @param bandWidth The width available to place bars.
|
|
* @param numberOfGroups The number of bars to place in that space.
|
|
* @param gapRatio The ratio of the gap between bars over the bar width.
|
|
* @returns The bar width and the offset between bars.
|
|
*/
|
|
function getBandSize({
|
|
bandWidth: W,
|
|
numberOfGroups: N,
|
|
gapRatio: r
|
|
}) {
|
|
if (r === 0) {
|
|
return {
|
|
barWidth: W / N,
|
|
offset: 0
|
|
};
|
|
}
|
|
const barWidth = W / (N + (N - 1) * r);
|
|
const offset = r * barWidth;
|
|
return {
|
|
barWidth,
|
|
offset
|
|
};
|
|
}
|
|
function getValueCoordinate(isVertical, minValueCoord, maxValueCoord, baseValue, minBarSize) {
|
|
if (baseValue === 0 || baseValue == null) {
|
|
return {
|
|
barSize: 0,
|
|
startCoordinate: minValueCoord
|
|
};
|
|
}
|
|
const isSizeLessThanMin = maxValueCoord - minValueCoord < minBarSize;
|
|
const barSize = isSizeLessThanMin ? minBarSize : maxValueCoord - minValueCoord;
|
|
const isVerticalAndPositive = isVertical && baseValue >= 0;
|
|
const isHorizontalAndNegative = !isVertical && baseValue < 0;
|
|
if (isSizeLessThanMin && (isVerticalAndPositive || isHorizontalAndNegative)) {
|
|
return {
|
|
barSize,
|
|
startCoordinate: maxValueCoord - barSize
|
|
};
|
|
}
|
|
return {
|
|
barSize,
|
|
startCoordinate: minValueCoord
|
|
};
|
|
} |