Skip to content
This repository has been archived by the owner on Feb 19, 2022. It is now read-only.

Commit

Permalink
Merge pull request #390 from FormidableLabs/improvement/reduce-children
Browse files Browse the repository at this point in the history
Improvement/reduce children
  • Loading branch information
boygirl authored Jun 20, 2018
2 parents ab3437a + 16e135e commit de1a791
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 137 deletions.
17 changes: 8 additions & 9 deletions src/victory-shared-events/victory-shared-events.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,15 @@ export default class VictorySharedEvents extends React.Component {

getNewChildren(props, baseProps) {
const { events, eventKey } = props;
const childNames = Object.keys(baseProps);
const alterChildren = (children) => {
const alterChildren = (children, childNames) => {
return children.reduce((memo, child, index) => {
if (child.props.children) {
return memo.concat(React.cloneElement(
child,
child.props,
alterChildren(React.Children.toArray(child.props.children))
));
const newChildren = React.Children.toArray(child.props.children);
const names = childNames.slice(index, index + newChildren.length);
const results = React.cloneElement(child, child.props, alterChildren(newChildren, names));
return memo.concat(results);
} else if (child.type && isFunction(child.type.getBaseProps)) {
const name = child.props.name || childNames.shift() || index;
const name = child.props.name || childNames[index];
const childEvents = Array.isArray(events) &&
events.filter((event) => {
if (event.target === "parent") {
Expand All @@ -193,8 +191,9 @@ export default class VictorySharedEvents extends React.Component {
}
}, []);
};
const childNames = Object.keys(baseProps);
const childComponents = React.Children.toArray(props.children);
return alterChildren(childComponents);
return alterChildren(childComponents, childNames);
}

getContainer(props, baseProps, events) {
Expand Down
107 changes: 13 additions & 94 deletions src/victory-util/domain.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable func-style */
/* eslint-disable no-use-before-define */
import { flatten, includes, isPlainObject, sortedUniq, isFunction } from "lodash";
import { flatten, isPlainObject, sortedUniq, isFunction } from "lodash";
import Data from "./data";
import Scale from "./scale";
import Helpers from "./helpers";
Expand All @@ -26,37 +26,6 @@ function cleanDomain(domain, props, axis) {
return rules(domain);
}

function getCumulativeData(props, axis, datasets) {
const currentAxis = Helpers.getCurrentAxis(axis, props.horizontal);
const otherAxis = currentAxis === "x" ? "y" : "x";
const categories = [];
const axisValues = [];
datasets.forEach((dataset) => {
dataset.forEach((data) => {
if (data.category !== undefined && !includes(categories, data.category)) {
categories.push(data.category);
} else if (!includes(axisValues, data[`_${otherAxis}`])) {
axisValues.push(data[`_${otherAxis}`]);
}
});
});

const _dataByCategory = () => {
return categories.map((value) => {
return datasets.reduce((prev, data) => {
return data.category === value ? prev.concat(data[`_${axis}`]) : prev;
}, []);
});
};

const _dataByIndex = () => {
return axisValues.map((value, index) => {
return datasets.map((data) => data[index] && data[index][`_${currentAxis}`]);
});
};
return categories.length === 0 ? _dataByIndex() : _dataByCategory();
}

function getDomainPadding(props, axis) {
const formatPadding = (padding) => {
return Array.isArray(padding) ?
Expand All @@ -74,26 +43,18 @@ function getFlatData(dataset, axis) {
});
}

function getMaxFromData(dataset, axis) {
function getExtremeFromData(dataset, axis, type = "min") {
const getExtreme = (arr) => type === "max" ? Math.max(...arr) : Math.min(...arr);
const initialValue = type === "max" ? -Infinity : Infinity;
let containsDate = false;
const minValue = flatten(dataset).reduce((memo, datum) => {
const current = datum[`_${axis}`] && datum[`_${axis}1`] !== undefined ?
datum[`_${axis}1`] : datum[`_${axis}`];
const result = flatten(dataset).reduce((memo, datum) => {
const current0 = datum[`_${axis}0`] !== undefined ? datum[`_${axis}0`] : datum[`_${axis}`];
const current1 = datum[`_${axis}1`] !== undefined ? datum[`_${axis}1`] : datum[`_${axis}`];
const current = getExtreme([current0, current1]);
containsDate = containsDate || current instanceof Date;
return memo > current ? memo : current;
}, -Infinity);
return containsDate ? new Date(minValue) : minValue;
}

function getMinFromData(dataset, axis) {
let containsDate = false;
const minValue = flatten(dataset).reduce((memo, datum) => {
const current = datum[`_${axis}`] && datum[`_${axis}0`] !== undefined ?
datum[`_${axis}0`] : datum[`_${axis}`];
containsDate = containsDate || current instanceof Date;
return memo < current ? memo : current;
}, Infinity);
return containsDate ? new Date(minValue) : minValue;
return getExtreme([memo, current]);
}, initialValue);
return containsDate ? new Date(result) : result;
}

//eslint-disable-next-line max-statements
Expand Down Expand Up @@ -259,55 +220,14 @@ function getDomainFromData(props, axis, dataset) {
return getDomainFromMinMax(min, max);
}
const currentAxis = Helpers.getCurrentAxis(axis, horizontal);
const min = minDomain !== undefined ? minDomain : getMinFromData(dataset, currentAxis);
const max = maxDomain !== undefined ? maxDomain : getMaxFromData(dataset, currentAxis);
const min = minDomain !== undefined ? minDomain : getExtremeFromData(dataset, currentAxis, "min");
const max = maxDomain !== undefined ? maxDomain : getExtremeFromData(dataset, currentAxis, "max");
const domain = getDomainFromMinMax(min, max);

return polar && axis === "x" && Math.abs(startAngle - endAngle) === 360 ?
getSymmetricDomain(domain, getFlatData(dataset, currentAxis)) : domain;
}

/**
* Returns a cumulative domain for a set of grouped datasets (i.e. stacked charts)
* @param {Object} props: the props object
* @param {String} axis: the current axis
* @param {Array} datasets: an array of data arrays
* @returns {Array} the cumulative domain
*/
function getDomainFromGroupedData(props, axis, datasets) {
const { horizontal } = props;
const dependent = (axis === "x" && !horizontal) || (axis === "y" && horizontal);
const categories = isPlainObject(props.categories) ? props.categories[axis] : props.categories;
if (dependent && categories) {
return getDomainFromCategories(props, axis, categories);
}
const globalDomain = getDomainFromData(props, axis, datasets);
if (dependent) {
return globalDomain;
}
// find the cumulative max for stacked chart types
const cumulativeData = getCumulativeData(props, axis, datasets);
const cumulativeMax = cumulativeData.reduce((memo, dataset) => {
const currentMax = dataset.reduce((m, val) => {
return val > 0 ? m + val : m;
}, 0);
return memo > currentMax ? memo : currentMax;
}, -Infinity);

const cumulativeMin = cumulativeData.reduce((memo, dataset) => {
const currentMin = dataset.reduce((m, val) => {
return val < 0 ? m + val : m;
}, 0);
return memo < currentMin ? memo : currentMin;
}, Infinity);

// use greatest min / max
return getDomainFromMinMax(
Collection.getMinValue(globalDomain, cumulativeMin),
Collection.getMaxValue(globalDomain, cumulativeMax)
);
}

/**
* Returns a domain in the form of a two element array given a min and max value.
* @param {Number|Date} min: the props object
Expand Down Expand Up @@ -422,7 +342,6 @@ export default {
getDomain,
getDomainFromCategories,
getDomainFromData,
getDomainFromGroupedData,
getDomainFromMinMax,
getDomainFromProps,
getDomainWithZero,
Expand Down
34 changes: 21 additions & 13 deletions src/victory-util/helpers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable func-style */
/* eslint-disable no-use-before-define */
import React from "react";
import { defaults, isFunction, property, includes } from "lodash";
import { defaults, isFunction, property, pick, assign } from "lodash";

// Private Functions

Expand Down Expand Up @@ -189,20 +189,27 @@ function getCurrentAxis(axis, horizontal) {
/**
* @param {Array} children: an array of child components
* @param {Function} iteratee: a function with arguments "child", "childName", and "parent"
* @param {Array} [rolesToSkip=[]]: children of these roles will be skipped while the role,
* itself, will be processed
* @param {Object} parentProps: props from the parent that are applied to children
* @returns {Array} returns an array of results from calling the iteratee on all nested children
*/
function reduceChildren(children, iteratee, rolesToSkip = []) {
let childIndex = 0;
const traverseChildren = (childArray, parent) => {
return childArray.reduce((memo, child) => {
function reduceChildren(children, iteratee, parentProps = {}) {
const sharedProps = [
"data", "domain", "categories", "polar", "startAngle", "endAngle", "minDomain", "maxDomain"
];
const traverseChildren = (childArray, names, parent) => {
return childArray.reduce((memo, child, index) => {
const childRole = child.type && child.type.role;
const childName = child.props.name || childIndex;
childIndex++;
if (!includes(rolesToSkip, childRole) && child.props && child.props.children) {
const nestedChildren = React.Children.toArray(child.props.children);
const nestedResults = traverseChildren(nestedChildren, child);
const childName = child.props.name || `${childRole}-${names[index]}`;
if (child.props && child.props.children) {
const childProps = assign({}, child.props, pick(parentProps, sharedProps));
const nestedChildren = child.type && isFunction(child.type.getChildren) ?
child.type.getChildren(childProps) :
React.Children.toArray(child.props.children).map((c) => {
const nestedChildProps = assign({}, c.props, pick(childProps, sharedProps));
return React.cloneElement(c, nestedChildProps);
});
const childNames = nestedChildren.map((c, i) => `${childName}-${i}`);
const nestedResults = traverseChildren(nestedChildren, childNames, child);
memo = memo.concat(nestedResults);
} else {
const result = iteratee(child, childName, parent);
Expand All @@ -211,7 +218,8 @@ function reduceChildren(children, iteratee, rolesToSkip = []) {
return memo;
}, []);
};
return traverseChildren(children);
const childNames = children.map((c, i) => i);
return traverseChildren(children, childNames);
}

export default {
Expand Down
21 changes: 0 additions & 21 deletions test/client/spec/victory-util/domain.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { Domain } from "src/index";
getDomain,
getDomainFromCategories,
getDomainFromData,
getDomainFromGroupedData,
getDomainFromMinMax,
getDomainFromProps,
getDomainWithZero,
Expand Down Expand Up @@ -119,26 +118,6 @@ describe("victory-util/domain", () => {
});
});

describe("getDomainFromGroupedData", () => {
const data = [
[{ _x: 1, _y: 0 }, { _x: 2, _y: 0 }, { _x: 3, _y: 0 }],
[{ _x: 1, _y: 1 }, { _x: 2, _y: 1 }, { _x: 3, _y: 1 }],
[{ _x: 1, _y: 2 }, { _x: 2, _y: 2 }, { _x: 3, _y: 2 }]
];

it("calculates a domain from categories for the independent axis", () => {
const props = { categories: [1, 2, 3], data, x: "x", y: "y" };
const domainResultX = Domain.getDomainFromGroupedData(props, "x", data);
expect(domainResultX).to.eql([1, 3]);
});

it("calculates a stacked domain for the dependent axis", () => {
const props = { categories: [1, 2, 3], data, x: "x", y: "y" };
const domainResultY = Domain.getDomainFromGroupedData(props, "y", data);
expect(domainResultY).to.eql([0, 3]);
});
});

describe("getDomainFromProps", () => {
it("gets the domain from a domain array", () => {
const props = { domain: [1, 2] };
Expand Down

0 comments on commit de1a791

Please sign in to comment.