UNPKG

victory-chart

Version:
321 lines (284 loc) 12.4 kB
import { assign, defaults, flatten, isFunction, partialRight, uniq } from "lodash"; import React from "react"; import Axis from "./axis"; import { Style, Transitions, Collection, Data, Domain } from "victory-core"; export default { getData(props, childComponents) { if (props.data) { return Data.getData(props); } childComponents = childComponents || React.Children.toArray(props.children); return this.getDataFromChildren(childComponents); }, getDomain(props, axis, childComponents) { childComponents = childComponents || React.Children.toArray(props.children); const propsDomain = Domain.getDomainFromProps(props, axis); if (propsDomain) { return propsDomain; } const dataset = (props.data || props.y) && Data.getData(props); const dataDomain = dataset ? Domain.getDomainFromData(props, axis, dataset) : []; const childDomain = this.getDomainFromChildren(props, axis, childComponents); const min = Collection.getMinValue([...dataDomain, ...childDomain]); const max = Collection.getMaxValue([...dataDomain, ...childDomain]); return Domain.cleanDomain([min, max], props, axis); }, setAnimationState(props, nextProps) { if (!props.animate) { return; } if (props.animate.parentState) { const nodesWillExit = props.animate.parentState.nodesWillExit; const nodesDoneClipPathExit = props.animate.parentState.nodesDoneClipPathExit; const oldProps = nodesWillExit && !nodesDoneClipPathExit ? props : null; this.setState(defaults({oldProps}, props.animate.parentState)); } else { const oldChildren = React.Children.toArray(props.children); const nextChildren = React.Children.toArray(nextProps.children); const { nodesWillExit, nodesWillEnter, childrenTransitions, nodesShouldEnter, nodesShouldLoad, nodesDoneLoad, nodesDoneClipPathLoad, nodesDoneClipPathEnter, nodesDoneClipPathExit } = Transitions.getInitialTransitionState(oldChildren, nextChildren); this.setState({ nodesWillExit, nodesWillEnter, nodesShouldEnter, nodesDoneClipPathEnter, nodesDoneClipPathExit, childrenTransitions: Collection.isArrayOfArrays(childrenTransitions) ? childrenTransitions[0] : childrenTransitions, nodesShouldLoad: nodesShouldLoad || this.state.nodesShouldLoad, nodesDoneLoad: nodesDoneLoad || this.state.nodesDoneLoad, nodesDoneClipPathLoad: nodesDoneClipPathLoad || this.state.nodesDoneClipPathLoad, oldProps: nodesWillExit && !nodesDoneClipPathExit ? props : null }); } }, getAnimationProps(props, child, index) { if (!props.animate) { return child.props.animate; } const getFilteredState = () => { let childrenTransitions = this.state && this.state.childrenTransitions; childrenTransitions = Collection.isArrayOfArrays(childrenTransitions) ? childrenTransitions[index] : childrenTransitions; return defaults({childrenTransitions}, this.state); }; let getTransitions = props.animate && props.animate.getTransitions; const state = getFilteredState(); const parentState = props.animate && props.animate.parentState || state; if (!getTransitions) { const getTransitionProps = Transitions.getTransitionPropsFactory( props, state, (newState) => this.setState(newState) ); getTransitions = partialRight(getTransitionProps, index); } return defaults({getTransitions, parentState}, props.animate, child.props.animate); }, getDomainFromChildren(props, axis, childComponents) { // eslint-disable-line max-statements, complexity, max-len const childDomains = []; let childDomainsLength = 0; const children = childComponents ? childComponents.slice(0) : React.Children.toArray(props.children); let childrenLength = children.length; const horizontalChildren = childComponents.some((child) => child.props.horizontal); const horizontal = props && props.horizontal || horizontalChildren.length > 0; const currentAxis = Axis.getCurrentAxis(axis, horizontal); while (childrenLength > 0) { const child = children[--childrenLength]; if (child.type && isFunction(child.type.getDomain)) { const parentData = props.data ? Data.getData(props, axis) : undefined; const sharedProps = parentData ? assign({}, child.props, {data: parentData}) : child.props; const childDomain = child.props && child.type.getDomain(sharedProps, currentAxis); if (childDomain) { const childDomainLength = childDomain.length; for (let index = 0; index < childDomainLength; index++) { childDomains[childDomainsLength++] = childDomain[index]; } } } else if (child.props && child.props.children) { const newChildren = React.Children.toArray(child.props.children); const newChildrenLength = newChildren.length; for (let index = 0; index < newChildrenLength; index++) { children[childrenLength++] = newChildren[index]; } } } const min = Collection.getMinValue(childDomains); const max = Collection.getMaxValue(childDomains); return childDomains.length === 0 ? [0, 1] : [min, max]; }, getDataFromChildren(props, childComponents) { const getData = (childProps) => { const data = Data.getData(childProps); return Array.isArray(data) && data.length > 0 ? data : undefined; }; // Reverse the child array to maintain correct order when looping over // children starting from the end of the array. const children = childComponents ? childComponents.slice(0).reverse() : React.Children.toArray(props.children).reverse(); let childrenLength = children.length; const dataArr = []; let dataArrLength = 0; while (childrenLength > 0) { const child = children[--childrenLength]; if (child.type && isFunction(child.type.getData)) { dataArr[dataArrLength++] = child.props && child.type.getData(child.props); } else if (child.props && child.props.children) { const newChildren = React.Children.toArray(child.props.children); const newChildrenLength = newChildren.length; for (let index = 0; index < newChildrenLength; index++) { children[childrenLength++] = newChildren[index]; } } else { dataArr[dataArrLength++] = getData(child.props); } } return dataArr; }, getStackedDomain(props, axis) { const propsDomain = Domain.getDomainFromProps(props, axis); if (propsDomain) { return propsDomain; } const { horizontal } = props; const ensureZero = (domain) => { const isDependent = (axis === "y" && !horizontal) || (axis === "x" && horizontal); return isDependent ? [Collection.getMinValue(domain, 0), Collection.getMaxValue(domain, 0)] : domain; }; const datasets = this.getDataFromChildren(props); return ensureZero(Domain.getDomainFromGroupedData(props, axis, datasets)); }, getColor(calculatedProps, child, index) { // check for styles first const { style } = calculatedProps; let { colorScale, color } = calculatedProps; if (style && style.data && style.data.fill) { return style.data.fill; } colorScale = child.props && child.props.colorScale ? child.props.colorScale : colorScale; color = child.props && child.props.color ? child.props.color : color; if (!colorScale && !color) { return undefined; } const colors = Array.isArray(colorScale) ? colorScale : Style.getColorScale(colorScale); return color || colors[index % colors.length]; }, getChildStyle(child, index, calculatedProps) { const { style } = calculatedProps; const role = child.type && child.type.role; const defaultFill = role === "stack" ? undefined : this.getColor(calculatedProps, child, index); const defaultColor = role === "line" ? {fill: "none", stroke: defaultFill} : {fill: defaultFill}; const childStyle = child.props.style || {}; const dataStyle = defaults({}, childStyle.data, assign({}, style.data, defaultColor)); const labelsStyle = defaults({}, childStyle.labels, style.labels); return { parent: style.parent, data: dataStyle, labels: labelsStyle }; }, getStringsFromCategories(childComponents, axis) { // eslint-disable-line max-statements const strings = []; let stringsLength = 0; const children = childComponents.slice(0).reverse(); let childrenLength = children.length; while (childrenLength > 0) { const child = children[--childrenLength]; if (child.props && child.props.categories) { const newStrings = Data.getStringsFromCategories(child.props, axis); const newStringsLength = newStrings.length; for (let index = 0; index < newStringsLength; index++) { strings[stringsLength++] = newStrings[index]; } } else if (child.props && child.props.children) { const newChildren = React.Children.toArray(child.props.children); const newChildrenLength = newChildren.length; for (let index = 0; index < newChildrenLength; index++) { children[childrenLength++] = newChildren[index]; } } } return strings; }, getStringsFromData(childComponents, axis) { // eslint-disable-line max-statements const strings = []; let stringsLength = 0; const children = childComponents.slice(0).reverse(); let childrenLength = children.length; while (childrenLength > 0) { const child = children[--childrenLength]; if (child.props && child.props.data) { const newStrings = Data.getStringsFromData(child.props, axis); const newStringsLength = newStrings.length; for (let index = 0; index < newStringsLength; index++) { strings[stringsLength++] = newStrings[index]; } } else if (child.type && isFunction(child.type.getData)) { const data = flatten(child.type.getData(child.props)); const attr = axis === "x" ? "xName" : "yName"; for (let index = 0; index < data.length; index++) { const datum = data[index]; if (datum[attr]) { strings[stringsLength++] = datum[attr]; } } } else if (child.props && child.props.children) { const newChildren = React.Children.toArray(child.props.children); const newChildrenLength = newChildren.length; for (let index = 0; index < newChildrenLength; index++) { children[childrenLength++] = newChildren[index]; } } } return strings; }, getStringsFromChildren(props, axis, childComponents) { childComponents = childComponents || React.Children.toArray(props.children); const axisComponent = Axis.getAxisComponent(childComponents, axis); const axisStrings = axisComponent ? Data.getStringsFromAxes(axisComponent.props, axis) : []; const categoryStrings = this.getStringsFromCategories(childComponents, axis); const dataStrings = this.getStringsFromData(childComponents, axis); return uniq(flatten([...categoryStrings, ...dataStrings, ...axisStrings])); }, getCategories(props, axis) { const categories = Data.getCategories(props, axis) || this.getStringsFromChildren(props, axis); return categories.length > 0 ? categories : undefined; }, getY0(datum, index, calculatedProps) { const { datasets } = calculatedProps; const y = datum.y; const previousDataSets = datasets.slice(0, index); const previousPoints = previousDataSets.reduce((prev, dataset) => { return prev.concat(dataset .filter((previousDatum) => datum.x instanceof Date ? previousDatum.x.getTime() === datum.x.getTime() : previousDatum.x === datum.x) .map((previousDatum) => previousDatum.y || 0) ); }, []); const y0 = previousPoints.length && previousPoints.reduce((memo, value) => { const sameSign = (y < 0 && value < 0) || (y >= 0 && value >= 0); return sameSign ? +value + memo : memo; }, 0); return previousPoints.some((point) => point instanceof Date) ? new Date(y0) : y0; } };