victory-core
Version:
365 lines (355 loc) • 14.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.findAxisComponents = findAxisComponents;
exports.getAxis = getAxis;
exports.getAxisComponent = getAxisComponent;
exports.getAxisComponentsWithParent = getAxisComponentsWithParent;
exports.getAxisValue = getAxisValue;
exports.getDomain = getDomain;
exports.getOrigin = getOrigin;
exports.getOriginSign = getOriginSign;
exports.getTickFormat = getTickFormat;
exports.getTicks = getTicks;
exports.isVertical = isVertical;
exports.modifyProps = modifyProps;
exports.stringTicks = stringTicks;
var _react = _interopRequireDefault(require("react"));
var _defaults = _interopRequireDefault(require("lodash/defaults"));
var _isObject = _interopRequireDefault(require("lodash/isObject"));
var _uniq = _interopRequireDefault(require("lodash/uniq"));
var _orderBy = _interopRequireDefault(require("lodash/orderBy"));
var Collection = _interopRequireWildcard(require("./collection"));
var Domain = _interopRequireWildcard(require("./domain"));
var Helpers = _interopRequireWildcard(require("./helpers"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Returns the first argument it receives
* @param value The value to return
* @returns The value given
*/
function identity(value) {
return value;
}
/**
* Returns the axis (x or y) of a particular axis component
* @param {Object} props: the props object.
* @param {Boolean} horizontal: true for horizontal charts
* @returns {String} the dimension appropriate for the axis given its props
*/
function getAxis(props) {
const {
dependentAxis
} = props;
return dependentAxis ? "y" : "x";
}
/**
* Returns all axis components that pass a given predicate
* @param {Array} childComponents: an array of children
* @param {Function} predicate: a predicate function that will be called with each
* @returns {Array} all axis components that pass the given predicate or []
*/
function findAxisComponents(childComponents, predicate) {
const predicateFunction = predicate || identity;
const findAxes = children => {
return children.reduce((memo, child) => {
if (child.type && child.type.role === "axis" && predicateFunction(child)) {
return memo.concat(child);
} else if (child.props && child.props.children) {
return memo.concat(findAxes(_react.default.Children.toArray(child.props.children)));
}
return memo;
}, []);
};
return findAxes(childComponents);
}
/**
* Returns a single axis component of the desired axis type (x or y)
* @param {Array} childComponents: an array of children
* @param {String} axis: desired axis either "x" or "y".
* @returns {ReactComponent} an axis component of the desired axis or undefined
*/
function getAxisComponent(childComponents, axis) {
const matchesAxis = component => {
const type = component.type.getAxis(component.props);
return type === axis;
};
return findAxisComponents(childComponents, matchesAxis)[0];
}
/**
* Returns all axis components of the desired axis type (x or y) along with any
* parent components excluding VictoryChart
* @param {Array} childComponents: an optional array of children.
* @param {String} type: desired axis either "dependent" or "independent".
* @returns {ReactComponent} an axis component of the desired type or undefined
*/
function getAxisComponentsWithParent(childComponents, type) {
const matchesType = child => {
return type === "dependent" ? child.props.dependentAxis : !child.props.dependentAxis;
};
const findComponents = children => {
return children.reduce((memo, child) => {
if (child.type && child.type.role === "axis" && matchesType(child)) {
return memo.concat(child);
} else if (child.props && child.props.children) {
const childAxis = findComponents(_react.default.Children.toArray(child.props.children));
return childAxis.length > 0 ? memo.concat(child) : memo;
}
return memo;
}, []);
};
return findComponents(childComponents);
}
function getOrigin(domain) {
const getSingleOrigin = d => {
const domainMin = Math.min(...d);
const domainMax = Math.max(...d);
return domainMax < 0 ? domainMax : Math.max(0, domainMin);
};
return {
x: Collection.containsDates(domain.x) ? new Date(Math.min(...domain.x)) : getSingleOrigin(domain.x),
y: Collection.containsDates(domain.y) ? new Date(Math.min(...domain.y)) : getSingleOrigin(domain.y)
};
}
function getOriginSign(origin, domain) {
const getSign = () => {
return origin <= 0 && Math.max(...domain) <= 0 ? "negative" : "positive";
};
return Collection.containsDates(domain) ? "positive" : getSign();
}
/**
* @param {Object} props: axis component props
* @returns {Boolean} true when the axis is vertical
*/
function isVertical(props) {
const orientation = props.orientation || (props.dependentAxis ? "left" : "bottom");
const vertical = {
top: false,
bottom: false,
left: true,
right: true
};
return vertical[orientation];
}
/**
* @param {Object} props: axis component props
* @returns {Boolean} true when tickValues contain strings
*/
function stringTicks(props) {
return props.tickValues !== undefined && Collection.containsStrings(props.tickValues);
}
function getDefaultTickFormat(props) {
const {
tickValues
} = props;
const axis = getAxis(props);
const stringMap = props.stringMap && props.stringMap[axis];
const fallbackFormat = tickValues && !Collection.containsDates(tickValues) ? x => x : undefined;
if (!stringMap) {
return stringTicks(props) ? (x, index) => tickValues[index] : fallbackFormat;
}
const invertedStringMap = stringMap && Helpers.invert(stringMap);
const tickValueArray = (0, _orderBy.default)(Object.values(stringMap), n => n);
const dataNames = tickValueArray.map(tick => invertedStringMap[tick]);
// string ticks should have one tick of padding at the beginning
const dataTicks = ["", ...dataNames, ""];
return x => dataTicks[x];
}
function getStringTicks(props) {
const axis = getAxis(props);
const stringMap = props.stringMap && props.stringMap[axis];
const categories = Array.isArray(props.categories) ? props.categories : props.categories && props.categories[axis];
const ticksFromCategories = categories && Collection.containsOnlyStrings(categories) ? categories.map(tick => stringMap[tick]) : undefined;
const ticksFromStringMap = stringMap && Object.values(stringMap);
return ticksFromCategories && ticksFromCategories.length !== 0 ? ticksFromCategories : ticksFromStringMap;
}
function getTickArray(props) {
const {
tickValues,
tickFormat
} = props;
if (tickValues?.length === 0) {
return [];
}
const axis = getAxis(props);
const stringMap = props.stringMap && props.stringMap[axis];
const getTicksFromFormat = () => {
if (!tickFormat || !Array.isArray(tickFormat)) {
return undefined;
}
return Collection.containsStrings(tickFormat) ? tickFormat.map((t, i) => i) : tickFormat;
};
let ticks = tickValues;
if (stringMap) {
ticks = getStringTicks(props);
}
if (tickValues && Collection.containsStrings(tickValues)) {
ticks = stringMap ? tickValues.map(tick => stringMap[tick]) : Helpers.range(1, tickValues.length + 1);
}
const tickArray = ticks ? (0, _uniq.default)(ticks) : getTicksFromFormat();
const buildTickArray = arr => {
const newTickArray = [];
const domain = props.domain && props.domain[axis] || props.domain;
if (arr) {
arr.forEach((t, index) => {
if (Array.isArray(domain)) {
if (t >= Collection.getMinValue(domain).valueOf() && t <= Collection.getMaxValue(domain).valueOf()) {
newTickArray.push({
value: t,
index
});
}
} else {
newTickArray.push({
value: t,
index
});
}
});
return newTickArray;
}
return undefined;
};
return Array.isArray(tickArray) && tickArray.length ? buildTickArray(tickArray) : undefined;
}
function getTickFormat(props, scale) {
const {
tickFormat
} = props;
const axis = getAxis(props);
const stringMap = props.stringMap && props.stringMap[axis];
if (!tickFormat) {
const defaultTickFormat = getDefaultTickFormat(props);
// If there is no user-provided tick format, we use d3's tickFormat function
// by default. This changed the default formatting for some scale types when
// we upgraded to d3-scale@4..
const scaleTickFormat = scale.tickFormat && Helpers.isFunction(scale.tickFormat) ? scale.tickFormat() : x => x;
return defaultTickFormat || scaleTickFormat;
} else if (tickFormat && Array.isArray(tickFormat)) {
const tickArray = getTickArray(props);
const tickArrayIndices = tickArray?.map(v => v.index);
const filteredTickFormat = tickFormat.filter((t, index) => tickArrayIndices?.includes(index));
return (x, index) => filteredTickFormat[index];
} else if (tickFormat && Helpers.isFunction(tickFormat)) {
const applyStringTicks = (tick, index, ticks) => {
const invertedStringMap = Helpers.invert(stringMap);
const stringTickArray = ticks.map(t => invertedStringMap[t]);
return props.tickFormat(invertedStringMap[tick], index, stringTickArray);
};
return stringMap ? applyStringTicks : tickFormat;
}
return x => x;
}
function downsampleTicks(ticks, tickCount) {
if (!tickCount || !Array.isArray(ticks) || ticks.length <= tickCount) {
return ticks;
}
const k = Math.floor(ticks.length / tickCount);
return ticks.filter((d, i) => i % k === 0);
}
function getTicks(props, scale, filterZero) {
if (filterZero === void 0) {
filterZero = false;
}
const {
tickCount
} = props;
const tickArray = getTickArray(props);
if (tickArray?.length === 0) {
return [""];
}
const tickValues = tickArray ? tickArray.map(v => v.value) : undefined;
if (tickValues) {
return downsampleTicks(tickValues, tickCount);
} else if (scale.ticks && Helpers.isFunction(scale.ticks)) {
// eslint-disable-next-line no-magic-numbers
const defaultTickCount = tickCount || 5;
const scaleTicks = scale.ticks(defaultTickCount);
const scaledTickArray = Array.isArray(scaleTicks) && scaleTicks.length ? scaleTicks : scale.domain();
const ticks = downsampleTicks(scaledTickArray, tickCount);
if (filterZero) {
const filteredTicks = ticks.filter(value => value !== 0);
return filteredTicks.length ? filteredTicks : ticks;
}
return ticks;
}
return scale.domain();
}
/**
* Returns a domain based tickValues
* @param {Object} props: the props object
* @param {String} axis: either x or y
* @returns {Array} returns a domain from tickValues
*/
function getDomainFromData(props, axis) {
const {
polar,
startAngle = 0,
endAngle = 360
} = props;
const tickArray = getTickArray(props);
const tickValues = tickArray && tickArray?.length !== 0 ? tickArray.map(v => v.value) : undefined;
if (!Array.isArray(tickValues)) {
return undefined;
}
const minDomain = Domain.getMinFromProps(props, axis);
const maxDomain = Domain.getMaxFromProps(props, axis);
const tickStrings = stringTicks(props);
const ticks = tickValues.map(value => Number(value));
const defaultMin = tickStrings ? 1 : Collection.getMinValue(ticks);
const defaultMax = tickStrings ? tickValues.length : Collection.getMaxValue(ticks);
const min = minDomain !== undefined ? minDomain : defaultMin;
const max = maxDomain !== undefined ? maxDomain : defaultMax;
const initialDomain = Domain.getDomainFromMinMax(min, max);
const domain = polar && axis === "x" && Math.abs(startAngle - endAngle) === 360 ? Domain.getSymmetricDomain(initialDomain, ticks) : initialDomain;
if (isVertical(props) && !polar) {
domain.reverse();
}
return domain;
}
// exposed for use by VictoryChart
function getDomain(props, axis) {
const inherentAxis = getAxis(props);
if (axis && axis !== inherentAxis) {
return undefined;
}
return Domain.createDomainFunction(getDomainFromData)(props, inherentAxis);
}
function getAxisValue(props, axis) {
if (!props.axisValue) {
return undefined;
}
const scaleAxis = axis === "x" ? "y" : "x";
const scale = (0, _isObject.default)(props.scale) && Helpers.isFunction(props.scale[scaleAxis]) ? props.scale[scaleAxis] : undefined;
if (!scale) {
return undefined;
}
const stringMapAxis = axis === "x" ? "y" : "x";
const stringMap = (0, _isObject.default)(props.stringMap) && props.stringMap[stringMapAxis];
const axisValue = stringMap && typeof props.axisValue === "string" ? stringMap[props.axisValue] : props.axisValue;
return scale(axisValue);
}
function modifyProps(props, fallbackProps) {
if (!(0, _isObject.default)(props.theme)) {
return Helpers.modifyProps(props, fallbackProps, "axis");
}
let role = "axis";
if (props.dependentAxis && props.theme.dependentAxis) {
role = "dependentAxis";
} else if (!props.dependentAxis && props.theme.independentAxis) {
role = "independentAxis";
}
if (role === "axis") {
return Helpers.modifyProps(props, fallbackProps, "axis");
}
const axisTheme = (0, _defaults.default)({}, props.theme[role], props.theme.axis);
const theme = Object.assign({}, props.theme, {
axis: axisTheme
});
return Helpers.modifyProps(Object.assign({}, props, {
theme
}), fallbackProps, "axis");
}