victory-core
Version:
150 lines • 6.05 kB
JavaScript
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import React from "react";
import defaults from "lodash/defaults";
import pick from "lodash/pick";
import isEqual from "react-fast-compare";
import { VictoryAnimation } from "../victory-animation/victory-animation";
import * as Collection from "../victory-util/collection";
import * as Helpers from "../victory-util/helpers";
import TimerContext from "../victory-util/timer-context";
import * as Transitions from "../victory-util/transitions";
export class VictoryTransition extends React.Component {
static displayName = "VictoryTransition";
static contextType = TimerContext;
constructor(props, context) {
super(props, context);
this.state = {
nodesShouldLoad: false,
nodesDoneLoad: false
};
const child = this.props.children;
const polar = child.props.polar;
this.continuous = !polar && child.type && child.type.continuous === true;
this.timer = this.context.transitionTimer;
}
componentDidMount() {
this.setState({
nodesShouldLoad: true
});
}
shouldComponentUpdate(nextProps) {
if (!isEqual(this.props, nextProps)) {
this.timer.bypassAnimation();
this.setState(this.getTransitionState(this.props, nextProps), () => this.timer.resumeAnimation());
}
return true;
}
componentWillUnmount() {
this.timer.stop();
}
getTransitionState(props, nextProps) {
const {
animate
} = props;
if (!animate) {
return {};
} else if (animate.parentState) {
const state = animate.parentState;
const oldProps = state.nodesWillExit ? props : null;
return {
oldProps,
nextProps
};
}
const oldChildren = React.Children.toArray(props.children);
const nextChildren = React.Children.toArray(nextProps.children);
const {
nodesWillExit,
nodesWillEnter,
childrenTransitions,
nodesShouldEnter
} = Transitions.getInitialTransitionState(oldChildren, nextChildren);
return {
nodesWillExit,
nodesWillEnter,
childrenTransitions,
nodesShouldEnter,
oldProps: nodesWillExit ? props : null,
nextProps
};
}
getDomainFromChildren(props, axis) {
const getChildDomains = children => {
return children.reduce((memo, child) => {
if (child.type && Helpers.isFunction(child.type.getDomain)) {
const childDomain = child.props && child.type.getDomain(child.props, axis);
return childDomain ? memo.concat(childDomain) : memo;
} else if (child.props && child.props.children) {
return memo.concat(getChildDomains(React.Children.toArray(child.props.children)));
}
return memo;
}, []);
};
const child = React.Children.toArray(props.children)[0];
const childProps = child.props || {};
const domain = Array.isArray(childProps.domain) ? childProps.domain : childProps.domain && childProps.domain[axis];
if (!childProps.children && domain) {
return domain;
}
const childDomains = getChildDomains([child]);
return childDomains.length === 0 ? [0, 1] : [Collection.getMinValue(childDomains), Collection.getMaxValue(childDomains)];
}
pickProps() {
if (!this.state) {
return this.props;
}
return this.state.nodesWillExit ? this.state.oldProps || this.props : this.props;
}
pickDomainProps(props) {
const parentState = props.animate?.parentState;
if (parentState && parentState.nodesWillExit) {
return this.continuous || parentState.continuous ? parentState.nextProps || this.state.nextProps || props : props;
}
return this.continuous && this.state.nodesWillExit ? this.state.nextProps || props : props;
}
getClipWidth(props, child) {
const getDefaultClipWidth = () => {
const range = Helpers.getRange(child.props, "x");
return range ? Math.abs(range[1] - range[0]) : props.width;
};
const clipWidth = this.transitionProps ? this.transitionProps.clipWidth : undefined;
return clipWidth !== undefined ? clipWidth : getDefaultClipWidth();
}
render() {
const props = this.pickProps();
const getTransitionProps = this.props.animate?.getTransitions ? this.props.animate.getTransitions : Transitions.getTransitionPropsFactory(props, this.state, newState => this.setState(newState));
const child = React.Children.toArray(props.children)[0];
const transitionProps = getTransitionProps(child);
this.transitionProps = transitionProps;
const domain = {
x: this.getDomainFromChildren(this.pickDomainProps(props), "x"),
y: this.getDomainFromChildren(props, "y")
};
const clipWidth = this.getClipWidth(props, child);
const combinedProps = defaults({
domain,
clipWidth
}, transitionProps, child.props);
const animationWhitelist = props.animationWhitelist || [];
const whitelist = animationWhitelist.concat(["clipWidth"]);
const propsToAnimate = whitelist.length ? pick(combinedProps, whitelist) : combinedProps;
return /*#__PURE__*/React.createElement(VictoryAnimation, _extends({}, combinedProps.animate, {
data: propsToAnimate
}), newProps => {
if (child.props.groupComponent) {
const groupComponent = this.continuous ? /*#__PURE__*/React.cloneElement(child.props.groupComponent, {
clipWidth: newProps.clipWidth || 0
}) : child.props.groupComponent;
return /*#__PURE__*/React.cloneElement(child, defaults({
animate: null,
animating: true,
groupComponent
}, newProps, combinedProps));
}
return /*#__PURE__*/React.cloneElement(child, defaults({
animate: null,
animating: true
}, newProps, combinedProps));
});
}
}