devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
297 lines (286 loc) • 12.7 kB
JavaScript
/**
* DevExtreme (cjs/viz/series/helpers/range_data_calculator.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
exports.default = void 0;
var _utils = require("../../core/utils");
var _type = require("../../../core/utils/type");
var _common = require("../../../core/utils/common");
const DISCRETE = "discrete";
const {
abs: abs,
floor: floor,
ceil: ceil,
min: min
} = Math;
function continuousRangeCalculator(range, minValue, maxValue) {
range.min = range.min < minValue ? range.min : minValue;
range.max = range.max > maxValue ? range.max : maxValue
}
function createGetLogFunction(axisType, axis) {
if ("logarithmic" !== axisType) {
return null
}
const base = axis.getOptions().logarithmBase;
return value => {
const log = (0, _utils.getLog)(abs(value), base);
const round = log < 0 ? floor : ceil;
return round(log)
}
}
function getRangeCalculator(axisType, axis, getLog) {
let rangeCalculator = continuousRangeCalculator;
if (axisType === DISCRETE) {
rangeCalculator = function(range, minValue, maxValue) {
if (minValue !== maxValue) {
range.categories.push(maxValue)
}
range.categories.push(minValue)
}
} else if (axis) {
rangeCalculator = function(range, value) {
const interval = axis.calculateInterval(value, range.prevValue);
const minInterval = range.interval;
range.interval = (minInterval < interval ? minInterval : interval) || minInterval;
range.prevValue = value;
continuousRangeCalculator(range, value, value)
}
}
if (getLog) {
return (range, minValue, maxValue) => {
const minArgs = [];
rangeCalculator(range, minValue, maxValue);
0 !== minValue && minArgs.push(getLog(minValue));
0 !== maxValue && minArgs.push(getLog(maxValue));
const linearThreshold = min.apply(null, minArgs);
range.linearThreshold = range.linearThreshold < linearThreshold ? range.linearThreshold : linearThreshold
}
}
return rangeCalculator
}
function getInitialRange(axisType, dataType, firstValue) {
const range = {
axisType: axisType,
dataType: dataType
};
if (axisType === DISCRETE) {
range.categories = []
} else {
range.min = (0, _type.isObject)(firstValue) ? firstValue.min : firstValue;
range.max = (0, _type.isObject)(firstValue) ? firstValue.max : firstValue
}
return range
}
function processCategories(range) {
if (range.categories) {
range.categories = (0, _utils.unique)(range.categories)
}
return range
}
function getValueForArgument(point, extraPoint, x, range) {
if (extraPoint && (0, _type.isDefined)(extraPoint.value)) {
const y1 = point.value;
const y2 = extraPoint.value;
const x1 = point.argument;
const x2 = extraPoint.argument;
const r = (x - x1) * (y2 - y1) / (x2 - x1) + y1.valueOf();
return "datetime" === range.dataType ? new Date(r) : r
} else {
return point.value
}
}
function calculateRangeBetweenPoints(rangeCalculator, range, point, prevPoint, bound) {
const value = getValueForArgument(point, prevPoint, bound, range);
rangeCalculator(range, value, value)
}
function isLineSeries(series) {
return series.type.toLowerCase().indexOf("line") >= 0 || series.type.toLowerCase().indexOf("area") >= 0
}
function getViewportReducer(series) {
const rangeCalculator = getRangeCalculator(series.valueAxisType);
const argumentAxis = series.getArgumentAxis();
const viewport = argumentAxis && series.getArgumentAxis().visualRange() || {};
const calculatePointBetweenPoints = isLineSeries(series) ? calculateRangeBetweenPoints : _common.noop;
if (argumentAxis && argumentAxis.getMarginOptions().checkInterval) {
const range = series.getArgumentAxis().getTranslator().getBusinessRange();
const add = (0, _utils.getAddFunction)(range, false);
const interval = range.interval;
if (isFinite(interval) && (0, _type.isDefined)(viewport.startValue) && (0, _type.isDefined)(viewport.endValue)) {
viewport.startValue = add(viewport.startValue, interval, -1);
viewport.endValue = add(viewport.endValue, interval)
}
}
const viewportFilter = getViewPortFilter(viewport);
return function(range, point, index, points) {
const argument = point.argument;
if (!point.hasValue()) {
return range
}
if (viewportFilter(argument)) {
if (!range.startCalc) {
range.startCalc = true;
calculatePointBetweenPoints(rangeCalculator, range, point, points[index - 1], viewport.startValue)
}
rangeCalculator(range, point.getMinValue(), point.getMaxValue())
} else if (!viewport.categories && (0, _type.isDefined)(viewport.startValue) && argument > viewport.startValue) {
if (!range.startCalc) {
calculatePointBetweenPoints(rangeCalculator, range, point, points[index - 1], viewport.startValue)
}
range.endCalc = true;
calculatePointBetweenPoints(rangeCalculator, range, point, points[index - 1], viewport.endValue)
}
return range
}
}
function getViewPortFilter(viewport) {
if (viewport.categories) {
const dictionary = viewport.categories.reduce(((result, category) => {
result[category.valueOf()] = true;
return result
}), {});
return argument => (0, _type.isDefined)(argument) && dictionary[argument.valueOf()]
}
if (!(0, _type.isDefined)(viewport.startValue) && !(0, _type.isDefined)(viewport.endValue)) {
return () => true
}
if (!(0, _type.isDefined)(viewport.endValue)) {
return argument => argument >= viewport.startValue
}
if (!(0, _type.isDefined)(viewport.startValue)) {
return argument => argument <= viewport.endValue
}
return argument => argument >= viewport.startValue && argument <= viewport.endValue
}
var _default = exports.default = {
getViewPortFilter: getViewPortFilter,
getArgumentRange: function(series) {
const data = series._data || [];
let range = {};
if (data.length) {
if (series.argumentAxisType === DISCRETE) {
range = {
categories: data.map((item => item.argument))
}
} else {
let interval;
if (data.length > 1) {
const i1 = series.getArgumentAxis().calculateInterval(data[0].argument, data[1].argument);
const i2 = series.getArgumentAxis().calculateInterval(data[data.length - 1].argument, data[data.length - 2].argument);
interval = min(i1, i2)
}
range = {
min: data[0].argument,
max: data[data.length - 1].argument,
interval: interval
}
}
}
return processCategories(range)
},
getRangeData: function(series) {
const points = series.getPoints();
const useAggregation = series.useAggregation();
const argumentAxis = series.getArgumentAxis();
const argumentCalculator = getRangeCalculator(series.argumentAxisType, points.length > 1 && argumentAxis, createGetLogFunction(series.argumentAxisType, argumentAxis));
const valueRangeCalculator = getRangeCalculator(series.valueAxisType, null, createGetLogFunction(series.valueAxisType, series.getValueAxis()));
const viewportReducer = getViewportReducer(series);
const range = points.reduce((function(range, point, index, points) {
const argument = point.argument;
if (!point.isArgumentCorrect()) {
return range
}
argumentCalculator(range.arg, argument, argument);
if (point.hasValue()) {
valueRangeCalculator(range.val, point.getMinValue(), point.getMaxValue());
viewportReducer(range.viewport, point, index, points)
}
return range
}), {
arg: getInitialRange(series.argumentAxisType, series.argumentType, null !== argumentAxis && void 0 !== argumentAxis && argumentAxis.aggregatedPointBetweenTicks() ? void 0 : series.getArgumentRangeInitialValue()),
val: getInitialRange(series.valueAxisType, series.valueType, points.length ? series.getValueRangeInitialValue() : void 0),
viewport: getInitialRange(series.valueAxisType, series.valueType, points.length ? series.getValueRangeInitialValue() : void 0)
});
if (useAggregation) {
const argumentRange = this.getArgumentRange(series);
if (series.argumentAxisType === DISCRETE) {
range.arg = argumentRange
} else {
const viewport = argumentAxis.getViewport();
if ((0, _type.isDefined)(viewport.startValue) || (0, _type.isDefined)(viewport.length)) {
argumentCalculator(range.arg, argumentRange.min, argumentRange.min)
}
if ((0, _type.isDefined)(viewport.endValue) || (0, _type.isDefined)(viewport.length) && (0, _type.isDefined)(viewport.startValue)) {
argumentCalculator(range.arg, argumentRange.max, argumentRange.max)
}
}
}
processCategories(range.arg);
processCategories(range.val);
return range
},
getViewport: function(series) {
const points = series.getPoints();
let range = {};
const reducer = getViewportReducer(series);
range = getInitialRange(series.valueAxisType, series.valueType, points.length ? series.getValueRangeInitialValue() : void 0);
points.some((function(point, index) {
reducer(range, point, index, points);
return range.endCalc
}));
return range
},
getPointsInViewPort: function(series) {
const argumentViewPortFilter = getViewPortFilter(series.getArgumentAxis().visualRange() || {});
const valueViewPort = series.getValueAxis().visualRange() || {};
const valueViewPortFilter = getViewPortFilter(valueViewPort);
const points = series.getPoints();
const addValue = function(values, point, isEdge) {
const minValue = point.getMinValue();
const maxValue = point.getMaxValue();
const isMinValueInViewPort = valueViewPortFilter(minValue);
const isMaxValueInViewPort = valueViewPortFilter(maxValue);
if (isMinValueInViewPort) {
values.push(minValue)
}
if (maxValue !== minValue && isMaxValueInViewPort) {
values.push(maxValue)
}
if (isEdge && !isMinValueInViewPort && !isMaxValueInViewPort) {
if (!values.length) {
values.push(valueViewPort.startValue)
} else {
values.push(valueViewPort.endValue)
}
}
};
const addEdgePoints = isLineSeries(series) ? function(result, points, index) {
const point = points[index];
const prevPoint = points[index - 1];
const nextPoint = points[index + 1];
if (nextPoint && argumentViewPortFilter(nextPoint.argument)) {
addValue(result[1], point, true)
}
if (prevPoint && argumentViewPortFilter(prevPoint.argument)) {
addValue(result[1], point, true)
}
} : _common.noop;
return points.reduce((function(result, point, index) {
if (argumentViewPortFilter(point.argument)) {
addValue(result[0], point)
} else {
addEdgePoints(result, points, index)
}
return result
}), [
[],
[]
])
}
};
module.exports = exports.default;
module.exports.default = exports.default;