From 755cfbb71704c29b1b17f051ced0e85f7d24de3f Mon Sep 17 00:00:00 2001 From: boygirl Date: Tue, 17 Oct 2017 16:29:06 -0700 Subject: [PATCH 1/5] safety commit --- demo/components/debug-demo.js | 87 +++---------- src/components/victory-axis/helper-methods.js | 8 +- src/components/victory-chart/victory-chart.js | 21 ++-- src/helpers/axis.js | 116 +++++++++++++++--- 4 files changed, 125 insertions(+), 107 deletions(-) diff --git a/demo/components/debug-demo.js b/demo/components/debug-demo.js index 8e3e80ba..6a7fa7be 100644 --- a/demo/components/debug-demo.js +++ b/demo/components/debug-demo.js @@ -22,86 +22,27 @@ class App extends React.Component {

VictoryChart

- - - - 0.5 * d.x + 0.5} style={{ data: { stroke: "red" } }}/> - d.x * d.x} style={{ data: { stroke: "red" } }}/> - - - - - - 0.5 * d.x + 0.5} style={{ data: { stroke: "red" } }}/> - d.x * d.x} style={{ data: { stroke: "red" } }}/> - - - - - - 0.5 * d.x + 0.5} style={{ data: { stroke: "red" } }}/> - d.x * d.x} style={{ data: { stroke: "red" } }}/> - - - - - - 0.5 * d.x + 0.5} style={{ data: { stroke: "red" } }}/> - d.x * d.x} style={{ data: { stroke: "red" } }}/> - - - - - - - - - - - - 0.5 * d.x + 0.5} style={{ data: { stroke: "red" } }}/> - - - - - 0.5 * d.x + 0.5} style={{ data: { stroke: "red" } }}/> - - - - + - `y: ${t}`} - /> - `x: ${t}`} + alignment="start" + data={[ + { x: 2, y: "Echo" }, + { x: 6, y: "Foxtrot" }, + { x: 3, y: "Golf" }, + { x: 4, y: "Hotel" } + ]} /> - - `x: ${t}`} +
diff --git a/src/components/victory-axis/helper-methods.js b/src/components/victory-axis/helper-methods.js index 68768607..d9f3300a 100644 --- a/src/components/victory-axis/helper-methods.js +++ b/src/components/victory-axis/helper-methods.js @@ -245,7 +245,7 @@ export default { const scale = this.getScale(props); const domain = this.getDomain(props); const ticks = this.getTicks(props, scale); - const tickFormat = Axis.getTickFormat(props, scale); + const tickFormat = Axis.getTickFormat(props, scale, props.stringMap); const anchors = this.getAnchors(orientation, isVertical); return { @@ -281,11 +281,9 @@ export default { getTicks(props, scale) { const { tickCount, crossAxis } = props; - const tickValues = Axis.getTickArray(props.tickValues, props.tickFormat); + const tickValues = Axis.getTickArray(props); if (tickValues) { - return Helpers.stringTicks(props) ? - Axis.downsampleTicks(range(1, props.tickValues.length + 1), tickCount) : - Axis.downsampleTicks(tickValues, tickCount); + return Axis.downsampleTicks(tickValues, tickCount); } else if (scale.ticks && isFunction(scale.ticks)) { // eslint-disable-next-line no-magic-numbers const defaultTickCount = tickCount || 5; diff --git a/src/components/victory-chart/victory-chart.js b/src/components/victory-chart/victory-chart.js index 890144db..be7877de 100644 --- a/src/components/victory-chart/victory-chart.js +++ b/src/components/victory-chart/victory-chart.js @@ -98,28 +98,27 @@ export default class VictoryChart extends React.Component { } getAxisProps(child, props, calculatedProps) { - const { domain, scale, originSign, stringMap } = calculatedProps; - const axis = child.type.getAxis(child.props); + const { domain, scale, originSign, stringMap, categories, horizontal } = calculatedProps; + const childProps = child.props || {}; + const axis = child.type.getAxis(childProps); + const currentAxis = Axis.getCurrentAxis(axis, horizontal); const otherAxis = axis === "x" ? "y" : "x"; const axisOffset = ChartHelpers.getAxisOffset(props, calculatedProps); - const tickValues = ChartHelpers.getTicks(calculatedProps, axis, child); - const tickFormat = child.props.tickFormat ? - Axis.getTickFormat(child.props, scale, stringMap) : - ChartHelpers.getTickFormat(child, axis, calculatedProps); + // const tickValues = childProps.tickValues || ChartHelpers.getTicks(calculatedProps, axis, child); const offsetY = axis === "y" ? undefined : axisOffset.y; const offsetX = axis === "x" ? undefined : axisOffset.x; - const crossAxis = child.props.crossAxis === false ? false : true; + const crossAxis = childProps.crossAxis === false ? false : true; const orientation = Axis.getOrientation(child, axis, originSign[otherAxis]); return { + stringMap: stringMap[currentAxis], + categories: categories[currentAxis], startAngle: props.startAngle, endAngle: props.endAngle, innerRadius: props.innerRadius, domain, scale, - tickValues, - tickFormat, - offsetY: child.props.offsetY !== undefined ? child.props.offsetY : offsetY, - offsetX: child.props.offsetX !== undefined ? child.props.offsetX : offsetX, + offsetY: childProps.offsetY !== undefined ? childProps.offsetY : offsetY, + offsetX: childProps.offsetX !== undefined ? childProps.offsetX : offsetX, crossAxis, orientation }; diff --git a/src/helpers/axis.js b/src/helpers/axis.js index 6d5fe11c..94cfcb9d 100644 --- a/src/helpers/axis.js +++ b/src/helpers/axis.js @@ -1,5 +1,5 @@ import { Collection } from "victory-core"; -import { identity, isFunction, invert, uniq } from "lodash"; +import { identity, isFunction, invert, uniq, range, sortBy, values } from "lodash"; import React from "react"; export default { @@ -157,29 +157,109 @@ export default { return props.tickValues !== undefined && Collection.containsStrings(props.tickValues); }, + getTicksFromData(props) { + const { stringMap, categories, tickCount } = props; + // if tickValues are defined for an axis component use them + const ticksFromCategories = categories && Collection.containsOnlyStrings(categories) ? + categories.map((tick) => stringMap[tick]) : categories; + const ticksFromStringMap = stringMap && values(stringMap); + // when ticks is undefined, axis will determine its own ticks + const ticks = ticksFromCategories && ticksFromCategories.length !== 0 ? + ticksFromCategories : ticksFromStringMap; + return this.downsampleTicks(ticks, tickCount); + }, + + getTicksFromAxis(props) { + const { tickValues, tickFormat, stringMap, tickCount } = props; + const tickArray = tickValues || tickFormat; + if (!Array.isArray(tickArray)) { + return undefined; + } + + const ticks = Collection.containsOnlyStrings(tickArray) && stringMap ? + tickArray.map((tick) => stringMap[tick]) : tickArray; + return this.downsampleTicks(ticks, tickCount); + }, + + getTicks(...args) { + return this.getTicksFromAxis(...args) || this.getTicksFromData(...args); + }, + + getDefaultTickFormat(props) { + const { tickValues, stringMap } = props; + const useIdentity = tickValues && !Collection.containsDates(tickValues); + if (useIdentity && !stringMap) { + return (x) => x; + } else if (stringMap) { + const tickValueArray = sortBy(values(stringMap), (n) => n); + const invertedStringMap = invert(stringMap); + 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]; + } else { + return undefined; + } + }, + + + // getTickFormat(props, scale, stringMap) { + // const stringTicks = this.stringTicks(props); + // if (stringTicks) { + // return (x, index) => props.tickValues[index]; + // } + + // let tickFormat; + // if (props.tickFormat) { + // tickFormat = Array.isArray(props.tickFormat) ? + // (x, index) => props.tickFormat[index] : props.tickFormat; + // } else if (scale.tickFormat && isFunction(scale.tickFormat)) { + // tickFormat = scale.tickFormat(); + // } else { + // tickFormat = (x) => x; + // } + + // if (!stringMap) { + // return tickFormat; + // } + // const applyStringTicks = (tick, index, ticks) => { + // const invertedStringMap = invert(stringMap); + // const stringTickArray = ticks.map((t) => invertedStringMap[t]); + // return tickFormat(invertedStringMap[tick], index, stringTickArray); + // }; + // return applyStringTicks; + // }, + getTickFormat(props, scale, stringMap) { - const stringTicks = this.stringTicks(props); - const axis = this.getAxis(props); - const applyStringTicks = (tick, index, ticks) => { - const invertedStringMap = invert(stringMap[axis]); - const stringTickArray = ticks.map((t) => invertedStringMap[t]); - return props.tickFormat(invertedStringMap[tick], index, stringTickArray); - }; - if (props.tickFormat && isFunction(props.tickFormat)) { - return stringMap && stringMap[axis] ? applyStringTicks : props.tickFormat; - } else if (props.tickFormat && Array.isArray(props.tickFormat)) { - return (x, index) => props.tickFormat[index]; - } else if (stringTicks) { - return (x, index) => props.tickValues[index]; - } else if (scale.tickFormat && isFunction(scale.tickFormat)) { - return scale.tickFormat(); + const { tickFormat } = props; + if (!tickFormat) { + const defaultTickFormat = this.getDefaultTickFormat(props); + const scaleTickFormat = scale.tickFormat && isFunction(scale.tickFormat) ? + scale.tickFormat() : (x) => x; + return defaultTickFormat || scaleTickFormat; + } else if (tickFormat && Array.isArray(tickFormat)) { + return (x, index) => tickFormat[index]; + } else if (tickFormat && isFunction(tickFormat)) { + const applyStringTicks = (tick, index, ticks) => { + const invertedStringMap = invert(stringMap); + const stringTickArray = ticks.map((t) => invertedStringMap[t]); + return props.tickFormat(invertedStringMap[tick], index, stringTickArray); + }; + return stringMap ? applyStringTicks : tickFormat; } else { return (x) => x; } }, - getTickArray(tickValues, tickFormat) { - const tickArray = tickValues ? uniq(tickValues) : tickFormat; + getTickArray(props) { + const { tickValues, tickFormat, stringMap } = props; + let ticks = tickValues; + if (tickValues && Collection.containsStrings(tickValues)) { + ticks = stringMap ? + tickValues.map((tick) => stringMap[tick]) : + range(1, tickValues.length + 1); + } + const tickArray = ticks ? uniq(ticks) : tickFormat; return Array.isArray(tickArray) && tickArray.length ? tickArray : undefined; }, From 4b652ad6a228f7b0d85cee7799154f44a7e38dde Mon Sep 17 00:00:00 2001 From: boygirl Date: Wed, 18 Oct 2017 16:01:25 -0700 Subject: [PATCH 2/5] working axis controlled tickFormats --- demo/components/debug-demo.js | 13 ++- src/components/victory-axis/helper-methods.js | 19 ++-- .../victory-polar-axis/helper-methods.js | 6 +- src/helpers/axis.js | 95 ++++++------------- 4 files changed, 51 insertions(+), 82 deletions(-) diff --git a/demo/components/debug-demo.js b/demo/components/debug-demo.js index 6a7fa7be..3339a452 100644 --- a/demo/components/debug-demo.js +++ b/demo/components/debug-demo.js @@ -20,8 +20,19 @@ class App extends React.Component { const chartStyle = { parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" } }; return (
-

VictoryChart

+

Debug

+ + `${t}s ${i} ${ts[0]}`}/> + + { - const tick = stringTicks ? tickValues[indexedTick - 1] : indexedTick; - + return ticks.reduce((childProps, tick, index) => { const styles = this.getEvaluatedStyles(style, tick, index); const tickLayout = { position: this.getTickPosition(styles, orientation, isVertical), - transform: this.getTickTransform(scale(indexedTick), globalTransform, isVertical) + transform: this.getTickTransform(scale(tick), globalTransform, isVertical) }; const gridLayout = { edge: gridEdge, transform: { x: isVertical ? - -gridOffset.x + globalTransform.x : scale(indexedTick) + globalTransform.x, + -gridOffset.x + globalTransform.x : scale(tick) + globalTransform.x, y: isVertical ? - scale(indexedTick) + globalTransform.y : gridOffset.y + globalTransform.y + scale(tick) + globalTransform.y : gridOffset.y + globalTransform.y } }; - childProps[index] = { axis: axisProps, axisLabel: axisLabelProps, @@ -245,7 +242,7 @@ export default { const scale = this.getScale(props); const domain = this.getDomain(props); const ticks = this.getTicks(props, scale); - const tickFormat = Axis.getTickFormat(props, scale, props.stringMap); + const tickFormat = Axis.getTickFormat(props, scale); const anchors = this.getAnchors(orientation, isVertical); return { diff --git a/src/components/victory-polar-axis/helper-methods.js b/src/components/victory-polar-axis/helper-methods.js index 9c30d132..75566cb3 100644 --- a/src/components/victory-polar-axis/helper-methods.js +++ b/src/components/victory-polar-axis/helper-methods.js @@ -327,11 +327,9 @@ export default { getTicks(props, scale) { const { tickCount } = props; - const tickValues = Axis.getTickArray(props.tickValues, props.tickFormat); + const tickValues = Axis.getTickArray(props); if (tickValues) { - return Helpers.stringTicks(props) ? - Axis.downsampleTicks(lodashRange(1, tickValues.length + 1), tickCount) : - Axis.downsampleTicks(tickValues, tickCount); + return Axis.downsampleTicks(tickValues, tickCount); } else if (scale.ticks && isFunction(scale.ticks)) { // eslint-disable-next-line no-magic-numbers const defaultTickCount = tickCount || 5; diff --git a/src/helpers/axis.js b/src/helpers/axis.js index 94cfcb9d..f38e1217 100644 --- a/src/helpers/axis.js +++ b/src/helpers/axis.js @@ -157,81 +157,24 @@ export default { return props.tickValues !== undefined && Collection.containsStrings(props.tickValues); }, - getTicksFromData(props) { - const { stringMap, categories, tickCount } = props; - // if tickValues are defined for an axis component use them - const ticksFromCategories = categories && Collection.containsOnlyStrings(categories) ? - categories.map((tick) => stringMap[tick]) : categories; - const ticksFromStringMap = stringMap && values(stringMap); - // when ticks is undefined, axis will determine its own ticks - const ticks = ticksFromCategories && ticksFromCategories.length !== 0 ? - ticksFromCategories : ticksFromStringMap; - return this.downsampleTicks(ticks, tickCount); - }, - - getTicksFromAxis(props) { - const { tickValues, tickFormat, stringMap, tickCount } = props; - const tickArray = tickValues || tickFormat; - if (!Array.isArray(tickArray)) { - return undefined; - } - - const ticks = Collection.containsOnlyStrings(tickArray) && stringMap ? - tickArray.map((tick) => stringMap[tick]) : tickArray; - return this.downsampleTicks(ticks, tickCount); - }, - - getTicks(...args) { - return this.getTicksFromAxis(...args) || this.getTicksFromData(...args); - }, - getDefaultTickFormat(props) { const { tickValues, stringMap } = props; - const useIdentity = tickValues && !Collection.containsDates(tickValues); - if (useIdentity && !stringMap) { - return (x) => x; - } else if (stringMap) { + const fallbackFormat = tickValues && !Collection.containsDates(tickValues) ? + (x) => x : undefined; + if (!stringMap) { + return this.stringTicks(props) ? (x, index) => tickValues[index] : fallbackFormat; + } else { + const invertedStringMap = stringMap && invert(stringMap); const tickValueArray = sortBy(values(stringMap), (n) => n); - const invertedStringMap = invert(stringMap); 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]; - } else { - return undefined; } }, - - // getTickFormat(props, scale, stringMap) { - // const stringTicks = this.stringTicks(props); - // if (stringTicks) { - // return (x, index) => props.tickValues[index]; - // } - - // let tickFormat; - // if (props.tickFormat) { - // tickFormat = Array.isArray(props.tickFormat) ? - // (x, index) => props.tickFormat[index] : props.tickFormat; - // } else if (scale.tickFormat && isFunction(scale.tickFormat)) { - // tickFormat = scale.tickFormat(); - // } else { - // tickFormat = (x) => x; - // } - - // if (!stringMap) { - // return tickFormat; - // } - // const applyStringTicks = (tick, index, ticks) => { - // const invertedStringMap = invert(stringMap); - // const stringTickArray = ticks.map((t) => invertedStringMap[t]); - // return tickFormat(invertedStringMap[tick], index, stringTickArray); - // }; - // return applyStringTicks; - // }, - - getTickFormat(props, scale, stringMap) { - const { tickFormat } = props; + getTickFormat(props, scale) { + const { tickFormat, stringMap } = props; if (!tickFormat) { const defaultTickFormat = this.getDefaultTickFormat(props); const scaleTickFormat = scale.tickFormat && isFunction(scale.tickFormat) ? @@ -251,15 +194,35 @@ export default { } }, + getStringTicks(props) { + const { stringMap, categories } = props; + const ticksFromCategories = categories && Collection.containsOnlyStrings(categories) ? + categories.map((tick) => stringMap[tick]) : undefined; + const ticksFromStringMap = stringMap && values(stringMap); + return ticksFromCategories && ticksFromCategories.length !== 0 ? + ticksFromCategories : ticksFromStringMap; + }, + + getTickArray(props) { const { tickValues, tickFormat, stringMap } = props; + 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 = this.getStringTicks(props); + } if (tickValues && Collection.containsStrings(tickValues)) { ticks = stringMap ? tickValues.map((tick) => stringMap[tick]) : range(1, tickValues.length + 1); } - const tickArray = ticks ? uniq(ticks) : tickFormat; + const tickArray = ticks ? uniq(ticks) : getTicksFromFormat(props); return Array.isArray(tickArray) && tickArray.length ? tickArray : undefined; }, From 2ce1bdd3129469ad7dc5154384d3e555cf1e1aac Mon Sep 17 00:00:00 2001 From: boygirl Date: Wed, 18 Oct 2017 17:25:00 -0700 Subject: [PATCH 3/5] axes are fully responsible for calculating tickValues and tickFormat --- demo/components/debug-demo.js | 4 +- demo/components/victory-chart-demo.js | 2 + src/components/victory-axis/helper-methods.js | 25 +---- .../victory-chart/helper-methods.js | 56 +--------- src/components/victory-chart/victory-chart.js | 1 - .../victory-polar-axis/helper-methods.js | 44 +------- src/helpers/axis.js | 25 ++++- .../victory-axis/helper-methods.spec.js | 41 ------- .../victory-chart/helper-methods.spec.js | 103 ------------------ test/client/spec/helpers/axis.spec.js | 38 +++++++ 10 files changed, 73 insertions(+), 266 deletions(-) diff --git a/demo/components/debug-demo.js b/demo/components/debug-demo.js index 3339a452..2f702f40 100644 --- a/demo/components/debug-demo.js +++ b/demo/components/debug-demo.js @@ -2,11 +2,9 @@ import React from "react"; import { - VictoryChart, VictoryAxis, VictoryLine, VictoryScatter, VictoryBar + VictoryChart, VictoryAxis, VictoryBar } from "../../src/index"; -import { range } from "lodash"; - class App extends React.Component { render() { diff --git a/demo/components/victory-chart-demo.js b/demo/components/victory-chart-demo.js index ce6d0d51..082d1bf2 100644 --- a/demo/components/victory-chart-demo.js +++ b/demo/components/victory-chart-demo.js @@ -409,6 +409,7 @@ class App extends React.Component { > + @@ -503,6 +504,7 @@ class App extends React.Component { + {this.state.barData.map((data, index) => { return ; diff --git a/src/components/victory-axis/helper-methods.js b/src/components/victory-axis/helper-methods.js index 78f08782..833e785d 100644 --- a/src/components/victory-axis/helper-methods.js +++ b/src/components/victory-axis/helper-methods.js @@ -1,4 +1,4 @@ -import { includes, defaults, defaultsDeep, isFunction, without } from "lodash"; +import { defaults, defaultsDeep, isFunction } from "lodash"; import Axis from "../../helpers/axis"; import { Helpers, Scale, Domain } from "victory-core"; @@ -241,7 +241,7 @@ export default { const stringTicks = Helpers.stringTicks(props); const scale = this.getScale(props); const domain = this.getDomain(props); - const ticks = this.getTicks(props, scale); + const ticks = Axis.getTicks(props, scale, props.crossAxis); const tickFormat = Axis.getTickFormat(props, scale); const anchors = this.getAnchors(orientation, isVertical); @@ -276,27 +276,6 @@ export default { }; }, - getTicks(props, scale) { - const { tickCount, crossAxis } = props; - const tickValues = Axis.getTickArray(props); - if (tickValues) { - return Axis.downsampleTicks(tickValues, tickCount); - } else if (scale.ticks && isFunction(scale.ticks)) { - // eslint-disable-next-line no-magic-numbers - const defaultTickCount = tickCount || 5; - const scaleTicks = scale.ticks(defaultTickCount); - const tickArray = Array.isArray(scaleTicks) && scaleTicks.length ? - scaleTicks : scale.domain(); - const ticks = Axis.downsampleTicks(tickArray, tickCount); - if (crossAxis) { - const filteredTicks = includes(ticks, 0) ? without(ticks, 0) : ticks; - return filteredTicks.length ? filteredTicks : ticks; - } - return ticks; - } - return scale.domain(); - }, - getAnchors(orientation, isVertical) { const anchorOrientation = { top: "end", left: "end", right: "start", bottom: "start" }; const anchor = anchorOrientation[orientation]; diff --git a/src/components/victory-chart/helper-methods.js b/src/components/victory-chart/helper-methods.js index 2335f898..b35355f6 100644 --- a/src/components/victory-chart/helper-methods.js +++ b/src/components/victory-chart/helper-methods.js @@ -1,10 +1,8 @@ -import { invert, sortBy, values } from "lodash"; import Axis from "../../helpers/axis"; import Wrapper from "../../helpers/wrapper"; import React from "react"; -import { Helpers, Collection, Log } from "victory-core"; +import { Collection, Log } from "victory-core"; -const identity = (x) => x; export default { getChildComponents(props, defaultAxes) { @@ -106,58 +104,6 @@ export default { }; }, - getTicksFromData(calculatedProps, axis, axisComponent) { - const currentAxis = Helpers.getCurrentAxis(axis, calculatedProps.horizontal); - const stringMap = calculatedProps.stringMap[currentAxis]; - // if tickValues are defined for an axis component use them - const categoryArray = calculatedProps.categories[currentAxis]; - const ticksFromCategories = categoryArray && Collection.containsOnlyStrings(categoryArray) ? - categoryArray.map((tick) => stringMap[tick]) : categoryArray; - const ticksFromStringMap = stringMap && values(stringMap); - // when ticks is undefined, axis will determine its own ticks - const ticks = ticksFromCategories && ticksFromCategories.length !== 0 ? - ticksFromCategories : ticksFromStringMap; - const tickCount = axisComponent && axisComponent.props && axisComponent.props.tickCount; - return Axis.downsampleTicks(ticks, tickCount); - }, - - getTicksFromAxis(calculatedProps, axis, axisComponent) { - const axisProps = axisComponent && axisComponent.props || {}; - const tickArray = axisProps.tickValues || axisProps.tickFormat; - if (!Array.isArray(tickArray)) { - return undefined; - } - const currentAxis = Helpers.getCurrentAxis(axis, calculatedProps.horizontal); - const stringMap = calculatedProps.stringMap[currentAxis]; - const ticks = Collection.containsOnlyStrings(tickArray) && stringMap ? - tickArray.map((tick) => stringMap[tick]) : tickArray; - return Axis.downsampleTicks(ticks, axisProps.tickCount); - }, - - getTicks(...args) { - return this.getTicksFromAxis(...args) || this.getTicksFromData(...args); - }, - - getTickFormat(component, axis, calculatedProps) { - const currentAxis = Helpers.getCurrentAxis(axis, calculatedProps.horizontal); - const stringMap = calculatedProps.stringMap[currentAxis]; - const tickValues = component.props.tickValues; - const useIdentity = tickValues && !Collection.containsStrings(tickValues) && - !Collection.containsDates(tickValues); - if (useIdentity) { - return identity; - } else if (stringMap !== null) { - const tickValueArray = sortBy(values(stringMap), (n) => n); - const invertedStringMap = invert(stringMap); - 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]; - } else { - return undefined; - } - }, - createStringMap(props, axis, childComponents) { const allStrings = Wrapper.getStringsFromChildren(props, axis, childComponents); return allStrings.length === 0 ? null : diff --git a/src/components/victory-chart/victory-chart.js b/src/components/victory-chart/victory-chart.js index be7877de..e471a0fb 100644 --- a/src/components/victory-chart/victory-chart.js +++ b/src/components/victory-chart/victory-chart.js @@ -104,7 +104,6 @@ export default class VictoryChart extends React.Component { const currentAxis = Axis.getCurrentAxis(axis, horizontal); const otherAxis = axis === "x" ? "y" : "x"; const axisOffset = ChartHelpers.getAxisOffset(props, calculatedProps); - // const tickValues = childProps.tickValues || ChartHelpers.getTicks(calculatedProps, axis, child); const offsetY = axis === "y" ? undefined : axisOffset.y; const offsetX = axis === "x" ? undefined : axisOffset.x; const crossAxis = childProps.crossAxis === false ? false : true; diff --git a/src/components/victory-polar-axis/helper-methods.js b/src/components/victory-polar-axis/helper-methods.js index 75566cb3..68468cb3 100644 --- a/src/components/victory-polar-axis/helper-methods.js +++ b/src/components/victory-polar-axis/helper-methods.js @@ -1,6 +1,4 @@ -import { - assign, uniqBy, includes, defaults, defaultsDeep, isFunction, range as lodashRange, without -} from "lodash"; +import { assign, uniqBy, defaults, defaultsDeep, isFunction } from "lodash"; import Axis from "../../helpers/axis"; import { Helpers, LabelHelpers, Scale, Domain, Collection } from "victory-core"; @@ -15,9 +13,9 @@ export default { const domain = this.getDomain(props, axis); const range = this.getRange(props, axis); const scale = this.getScale(props); - const initialTicks = this.getTicks(props, scale); + const initialTicks = Axis.getTicks(props, scale); const ticks = axisType === "angular" ? this.filterTicks(initialTicks, scale) : initialTicks; - const tickFormat = this.getTickFormat(props, scale, ticks); + const tickFormat = Axis.getTickFormat(props, scale); const radius = this.getRadius(props); return { axis, style, padding, stringTicks, axisType, scale, ticks, tickFormat, domain, range, radius @@ -175,7 +173,7 @@ export default { }, getTickLabelProps(props, calculatedValues, tick, index) { //eslint-disable-line max-params - const { axisType, radius, tickFormat, style, scale } = calculatedValues; + const { axisType, radius, tickFormat, style, scale, ticks } = calculatedValues; const { labelStyle } = this.getEvaluatedStyles(style, tick, index); const { tickLabelComponent } = props; const labelPlacement = tickLabelComponent.props && tickLabelComponent.props.labelPlacement ? @@ -194,7 +192,7 @@ export default { index, datum: tick, style: labelStyle, angle: textAngle, textAnchor, - text: tickFormat(tick, index), + text: tickFormat(tick, index, ticks), x: labelRadius * Math.cos(Helpers.degreesToRadians(labelAngle)), y: -labelRadius * Math.sin(Helpers.degreesToRadians(labelAngle)) }; @@ -325,40 +323,8 @@ export default { }, initialChildProps); }, - getTicks(props, scale) { - const { tickCount } = props; - const tickValues = Axis.getTickArray(props); - if (tickValues) { - return Axis.downsampleTicks(tickValues, tickCount); - } else if (scale.ticks && isFunction(scale.ticks)) { - // eslint-disable-next-line no-magic-numbers - const defaultTickCount = tickCount || 5; - const scaleTicks = scale.ticks(defaultTickCount); - const tickArray = Array.isArray(scaleTicks) && scaleTicks.length ? - scaleTicks : scale.domain(); - const ticks = Axis.downsampleTicks(tickArray, tickCount); - const filteredTicks = includes(ticks, 0) ? without(ticks, 0) : ticks; - return filteredTicks.length ? filteredTicks : ticks; - } - return scale.domain(); - }, - filterTicks(ticks, scale) { const compareTicks = (t) => scale(t) % (2 * Math.PI); return uniqBy(ticks, compareTicks); - }, - - getTickFormat(props, scale) { - if (props.tickFormat && isFunction(props.tickFormat)) { - return props.tickFormat; - } else if (props.tickFormat && Array.isArray(props.tickFormat)) { - return (x, index) => props.tickFormat[index]; - } else if (Helpers.stringTicks(props)) { - return (x, index) => props.tickValues[index]; - } else if (scale.tickFormat && isFunction(scale.tickFormat)) { - return scale.tickFormat(); - } else { - return (x) => x; - } } }; diff --git a/src/helpers/axis.js b/src/helpers/axis.js index f38e1217..6cb1fb2c 100644 --- a/src/helpers/axis.js +++ b/src/helpers/axis.js @@ -1,5 +1,7 @@ import { Collection } from "victory-core"; -import { identity, isFunction, invert, uniq, range, sortBy, values } from "lodash"; +import { + identity, isFunction, invert, uniq, range, sortBy, values, includes, without +} from "lodash"; import React from "react"; export default { @@ -232,5 +234,26 @@ export default { } const k = Math.floor(ticks.length / tickCount); return ticks.filter((d, i) => i % k === 0); + }, + + getTicks(props, scale, filterZero) { + const { tickCount } = props; + const tickValues = this.getTickArray(props); + if (tickValues) { + return this.downsampleTicks(tickValues, tickCount); + } else if (scale.ticks && isFunction(scale.ticks)) { + // eslint-disable-next-line no-magic-numbers + const defaultTickCount = tickCount || 5; + const scaleTicks = scale.ticks(defaultTickCount); + const tickArray = Array.isArray(scaleTicks) && scaleTicks.length ? + scaleTicks : scale.domain(); + const ticks = this.downsampleTicks(tickArray, tickCount); + if (filterZero) { + const filteredTicks = includes(ticks, 0) ? without(ticks, 0) : ticks; + return filteredTicks.length ? filteredTicks : ticks; + } + return ticks; + } + return scale.domain(); } }; diff --git a/test/client/spec/components/victory-axis/helper-methods.spec.js b/test/client/spec/components/victory-axis/helper-methods.spec.js index 0c2b4626..b29a1282 100644 --- a/test/client/spec/components/victory-axis/helper-methods.spec.js +++ b/test/client/spec/components/victory-axis/helper-methods.spec.js @@ -96,45 +96,4 @@ describe("victory-axis/helper-methods", () => { expect(scaleResult.range()).to.eql([0, 100]); }); }); - - describe("getTicks", () => { - let sandbox; - const scale = Scale.getBaseScale({ scale: { x: "linear" } }, "x"); - beforeEach(() => { - sandbox = sinon.sandbox.create(); - sandbox.spy(Helpers, "stringTicks"); - sandbox.spy(scale, "ticks"); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("returns tickValues from props", () => { - const props = { tickValues: [1, 2, 3] }; - const tickResult = AxisHelpers.getTicks(props); - expect(Helpers.stringTicks).calledWith(props).and.returned(false); - expect(tickResult).to.eql(props.tickValues); - }); - - it("returns converts string tickValues to numbers", () => { - const props = { tickValues: ["a", "b", "c", "d"] }; - const tickResult = AxisHelpers.getTicks(props); - expect(Helpers.stringTicks).calledWith(props).and.returned(true); - expect(tickResult).to.eql([1, 2, 3, 4]); - }); - - it("calculates tickValues from scale.ticks()", () => { - const props = { tickCount: 5 }; - AxisHelpers.getTicks(props, scale); - expect(scale.ticks).calledWith(5); - }); - - it("calculates tickValues from scale.ticks(), and removes zero if axes cross", () => { - const props = { tickCount: 5, crossAxis: true }; - const tickResult = AxisHelpers.getTicks(props, scale); - expect(scale.ticks).calledWith(5); - expect(tickResult).to.be.an("array").and.not.have.members([0]); - }); - }); }); diff --git a/test/client/spec/components/victory-chart/helper-methods.spec.js b/test/client/spec/components/victory-chart/helper-methods.spec.js index c54d0dda..9865f0fe 100644 --- a/test/client/spec/components/victory-chart/helper-methods.spec.js +++ b/test/client/spec/components/victory-chart/helper-methods.spec.js @@ -157,107 +157,4 @@ describe("victory-chart/helpers-methods", () => { expect(stringResult).to.eql({ a: 1, b: 2, c: 3, d: 4 }); }); }); - - describe("getTickFormat", () => { - const stringMap = { x: { "a": 1, "b": 2, "c": 3 } }; - const nullStringMap = { x: null }; - - it("returns the identity function when tickValues are numerical", () => { - const props = { tickValues: [1, 2, 3] }; - const victoryAxis = getVictoryAxis(props); - const formatResult = Helpers.getTickFormat(victoryAxis, "x", { stringMap: nullStringMap }); - const val = 2; - expect(formatResult).to.be.a("function"); - expect(formatResult(val)).to.equal(val); - }); - - it("returns a function from a string map", () => { - const victoryAxis = getVictoryAxis({}); - const formatResult = Helpers.getTickFormat(victoryAxis, "x", { stringMap }); - expect(formatResult).to.be.a("function"); - expect(formatResult(1)).to.equal("a"); - }); - - it("returns undefined if no tickValues or stringMaps exist", () => { - const victoryAxis = getVictoryAxis({}); - const formatResult = Helpers.getTickFormat( - victoryAxis, "x", { stringMap: nullStringMap } - ); - expect(formatResult).to.equal(undefined); - }); - }); - - describe("getTicks", () => { - let sandbox; - beforeEach(() => { - sandbox = sinon.sandbox.create(); - const fakeTicks = (bool) => bool; - sandbox.stub(Helpers, "getTicksFromAxis", fakeTicks); - sandbox.stub(Helpers, "getTicksFromData", fakeTicks); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("returns the result of getTicksFromAxis if truthy", () => { - expect(Helpers.getTicks(true)).to.eql(true); - expect(Helpers.getTicksFromAxis).calledWith(true).and.returned(true); - expect(Helpers.getTicksFromData).notCalled; - }); - - it("returns the result of getTicksFromData if getTicksFromAxis didnt return ticks", () => { - expect(Helpers.getTicks(false)).to.eql(false); - expect(Helpers.getTicksFromAxis).calledWith(false).and.returned(false); - expect(Helpers.getTicksFromData).calledWith(false).and.returned(false); - }); - }); - - describe("getTicksFromAxis", () => { - const stringMap = { x: { "a": 1, "b": 2, "c": 3 } }; - - it("returns numeric tickValues from a child component props", () => { - const props = { tickValues: [1, 2, 3] }; - const victoryAxis = getVictoryAxis(props); - const tickResult = Helpers.getTicksFromAxis({ stringMap }, "x", victoryAxis); - expect(tickResult).to.eql(props.tickValues); - }); - - it("converts string tickValues to numbers", () => { - const props = { tickValues: ["a", "b", "c"] }; - const victoryAxis = getVictoryAxis(props); - const tickResult = Helpers.getTicksFromAxis({ stringMap }, "x", victoryAxis); - expect(tickResult).to.eql([1, 2, 3]); - }); - - it("converts returns undefined if tickValues is not given", () => { - const victoryAxis = getVictoryAxis({}); - const tickResult = Helpers.getTicksFromAxis({ stringMap }, "x", victoryAxis); - expect(tickResult).to.be.undefined; - }); - }); - - describe("getTicksFromData", () => { - - it("returns a category array if there is one", () => { - const categories = { x: [1, 2, 3] }; - const stringMap = { x: { "a": 1, "b": 2, "c": 3 } }; - const tickResult = Helpers.getTicksFromData({ categories, stringMap }, "x"); - expect(tickResult).to.eql(categories.x); - }); - - it("returns the values from a string map if categories are not given", () => { - const stringMap = { x: { "a": 1, "b": 2, "c": 3 } }; - const categories = {}; - const tickResult = Helpers.getTicksFromData({ categories, stringMap }, "x"); - expect(tickResult).to.eql([1, 2, 3]); - }); - - it("returns undefined if neither a string map or categories are given", () => { - const stringMap = {}; - const categories = {}; - const tickResult = Helpers.getTicksFromData({ categories, stringMap }, "x"); - expect(tickResult).to.be.undefined; - }); - }); }); diff --git a/test/client/spec/helpers/axis.spec.js b/test/client/spec/helpers/axis.spec.js index 7f427d24..f35c0f00 100644 --- a/test/client/spec/helpers/axis.spec.js +++ b/test/client/spec/helpers/axis.spec.js @@ -84,4 +84,42 @@ describe("helpers/axis", () => { expect(formatResult).to.be.a("function"); }); }); + + describe("getTicks", () => { + let sandbox; + const scale = Scale.getBaseScale({ scale: { x: "linear" } }, "x"); + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.spy(scale, "ticks"); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it("returns tickValues from props", () => { + const props = { tickValues: [1, 2, 3] }; + const tickResult = Axis.getTicks(props); + expect(tickResult).to.eql(props.tickValues); + }); + + it("returns converts string tickValues to numbers", () => { + const props = { tickValues: ["a", "b", "c", "d"] }; + const tickResult = Axis.getTicks(props); + expect(tickResult).to.eql([1, 2, 3, 4]); + }); + + it("calculates tickValues from scale.ticks()", () => { + const props = { tickCount: 5 }; + Axis.getTicks(props, scale); + expect(scale.ticks).calledWith(5); + }); + + it("calculates tickValues from scale.ticks(), and removes zero if axes cross", () => { + const props = { tickCount: 5, crossAxis: true }; + const tickResult = Axis.getTicks(props, scale); + expect(scale.ticks).calledWith(5); + expect(tickResult).to.be.an("array").and.not.have.members([0]); + }); + }); }); From c744cfa220703d80b19c07f85986793ba99bfbb3 Mon Sep 17 00:00:00 2001 From: boygirl Date: Wed, 18 Oct 2017 17:44:17 -0700 Subject: [PATCH 4/5] styles evaluated with original tick --- src/components/victory-axis/helper-methods.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/victory-axis/helper-methods.js b/src/components/victory-axis/helper-methods.js index 833e785d..b293b143 100644 --- a/src/components/victory-axis/helper-methods.js +++ b/src/components/victory-axis/helper-methods.js @@ -188,7 +188,7 @@ export default { props = this.modifyProps(props, fallbackProps, role); const calculatedValues = this.getCalculatedValues(props); const { - style, orientation, isVertical, scale, ticks, tickFormat, anchors, domain + style, orientation, isVertical, scale, ticks, tickFormat, anchors, domain, stringTicks } = calculatedValues; const { width, height, standalone, theme, polar, padding } = props; const { @@ -202,7 +202,8 @@ export default { } }; return ticks.reduce((childProps, tick, index) => { - const styles = this.getEvaluatedStyles(style, tick, index); + const stringTick = stringTicks ? stringTicks[index] : tick; + const styles = this.getEvaluatedStyles(style, stringTick, index); const tickLayout = { position: this.getTickPosition(styles, orientation, isVertical), transform: this.getTickTransform(scale(tick), globalTransform, isVertical) @@ -238,7 +239,7 @@ export default { const orientation = props.orientation || (props.dependentAxis ? "left" : "bottom"); const isVertical = Helpers.isVertical(props); const labelPadding = this.getLabelPadding(props, style); - const stringTicks = Helpers.stringTicks(props); + const stringTicks = Helpers.stringTicks(props) ? props.tickValues : undefined; const scale = this.getScale(props); const domain = this.getDomain(props); const ticks = Axis.getTicks(props, scale, props.crossAxis); From bef01ca51b24e94c14840aee6c71200f605f82e2 Mon Sep 17 00:00:00 2001 From: boygirl Date: Wed, 18 Oct 2017 17:49:47 -0700 Subject: [PATCH 5/5] use originalTicks for axis and polar axis styles --- src/components/victory-axis/helper-methods.js | 4 ++-- .../victory-polar-axis/helper-methods.js | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/victory-axis/helper-methods.js b/src/components/victory-axis/helper-methods.js index b293b143..fc5802df 100644 --- a/src/components/victory-axis/helper-methods.js +++ b/src/components/victory-axis/helper-methods.js @@ -202,8 +202,8 @@ export default { } }; return ticks.reduce((childProps, tick, index) => { - const stringTick = stringTicks ? stringTicks[index] : tick; - const styles = this.getEvaluatedStyles(style, stringTick, index); + const originalTick = stringTicks ? stringTicks[index] : tick; + const styles = this.getEvaluatedStyles(style, originalTick, index); const tickLayout = { position: this.getTickPosition(styles, orientation, isVertical), transform: this.getTickTransform(scale(tick), globalTransform, isVertical) diff --git a/src/components/victory-polar-axis/helper-methods.js b/src/components/victory-polar-axis/helper-methods.js index 68468cb3..b0c5dea0 100644 --- a/src/components/victory-polar-axis/helper-methods.js +++ b/src/components/victory-polar-axis/helper-methods.js @@ -9,7 +9,7 @@ export default { const padding = Helpers.getPadding(props); const axis = this.getAxis(props); const axisType = this.getAxisType(props); - const stringTicks = Helpers.stringTicks(props); + const stringTicks = Helpers.stringTicks(props) ? props.tickValues : undefined; const domain = this.getDomain(props, axis); const range = this.getRange(props, axis); const scale = this.getScale(props); @@ -151,8 +151,9 @@ export default { }, getTickProps(props, calculatedValues, tick, index) { //eslint-disable-line max-params - const { axisType, radius, scale, style } = calculatedValues; - const { tickStyle } = this.getEvaluatedStyles(style, tick, index); + const { axisType, radius, scale, style, stringTicks } = calculatedValues; + const originalTick = stringTicks ? stringTicks[index] : tick; + const { tickStyle } = this.getEvaluatedStyles(style, originalTick, index); const tickPadding = tickStyle.padding || 0; const angularPadding = tickPadding; // TODO: do some geometry const axisAngle = axisType === "radial" ? this.getAxisAngle(props, scale) : undefined; @@ -173,8 +174,9 @@ export default { }, getTickLabelProps(props, calculatedValues, tick, index) { //eslint-disable-line max-params - const { axisType, radius, tickFormat, style, scale, ticks } = calculatedValues; - const { labelStyle } = this.getEvaluatedStyles(style, tick, index); + const { axisType, radius, tickFormat, style, scale, ticks, stringTicks } = calculatedValues; + const originalTick = stringTicks ? stringTicks[index] : tick; + const { labelStyle } = this.getEvaluatedStyles(style, originalTick, index); const { tickLabelComponent } = props; const labelPlacement = tickLabelComponent.props && tickLabelComponent.props.labelPlacement ? tickLabelComponent.props.labelPlacement : props.labelPlacement; @@ -199,9 +201,10 @@ export default { }, getGridProps(props, calculatedValues, tick, index) { //eslint-disable-line max-params - const { axisType, radius, style, scale } = calculatedValues; + const { axisType, radius, style, scale, stringTicks } = calculatedValues; const { startAngle, endAngle, innerRadius = 0 } = props; - const { gridStyle } = this.getEvaluatedStyles(style, tick, index); + const originalTick = stringTicks ? stringTicks[index] : tick; + const { gridStyle } = this.getEvaluatedStyles(style, originalTick, index); const angle = scale(tick); return axisType === "angular" ? {