From 447f479b35908d1860d2e9041b94a5d61b796ea7 Mon Sep 17 00:00:00 2001 From: Harry Shoff Date: Mon, 22 May 2017 16:34:12 -0700 Subject: [PATCH] [shape] add BarStack --- packages/vx-demo/components/tiles/bargroup.js | 2 +- packages/vx-demo/components/tiles/barstack.js | 95 ++++++++++++++++ packages/vx-demo/pages/barstack.js | 105 ++++++++++++++++++ packages/vx-demo/pages/gallery.js | 23 ++++ packages/vx-shape/build/index.js | 9 ++ packages/vx-shape/src/index.js | 1 + packages/vx-shape/src/shapes/BarGroup.js | 19 ++-- packages/vx-shape/src/shapes/BarStack.js | 65 +++++++++++ packages/vx-shape/test/BarStack.test.js | 9 ++ 9 files changed, 319 insertions(+), 9 deletions(-) create mode 100644 packages/vx-demo/components/tiles/barstack.js create mode 100644 packages/vx-demo/pages/barstack.js create mode 100644 packages/vx-shape/src/shapes/BarStack.js create mode 100644 packages/vx-shape/test/BarStack.test.js diff --git a/packages/vx-demo/components/tiles/bargroup.js b/packages/vx-demo/components/tiles/bargroup.js index 8dea5001b..5ccf3c91b 100644 --- a/packages/vx-demo/components/tiles/bargroup.js +++ b/packages/vx-demo/components/tiles/bargroup.js @@ -69,11 +69,11 @@ export default ({ keys={keys} height={yMax} x0={x0} - y={y} x0Scale={x0Scale} x1Scale={x1Scale} yScale={yScale} zScale={zScale} + rx={4} /> d !== 'date'); +const parseDate = timeParse("%Y%m%d"); +const format = timeFormat("%b %d"); +const formatDate = (date) => format(parseDate(date)); + +// accessors +const x = d => d.date; +const y = d => d.value; + +const totals = data.reduce((ret, cur) => { + const t = keys.reduce((dailyTotal, k) => { + dailyTotal += +cur[k] + return dailyTotal; + }, 0) + ret.push(t) + return ret; +}, []) + +export default ({ + width, + height, + margin = { + top: 40 + } +}) => { + if (width < 10) return null; + + // bounds + const xMax = width; + const yMax = height - margin.top - 100; + + // // scales + const xScale = scaleBand({ + rangeRound: [0, xMax], + domain: data.map(x), + padding: 0.2, + tickFormat: () => (val) => formatDate(val) + }); + const yScale = scaleLinear({ + rangeRound: [yMax, 0], + nice: true, + domain: [0, max(totals)], + }); + const zScale = scaleOrdinal({ + domain: keys, + range: ['#6c5efb', '#c998ff', '#a44afe'] + }) + + return ( + + + + + )} + /> + + ); +} diff --git a/packages/vx-demo/pages/barstack.js b/packages/vx-demo/pages/barstack.js new file mode 100644 index 000000000..b27ead461 --- /dev/null +++ b/packages/vx-demo/pages/barstack.js @@ -0,0 +1,105 @@ +import React from 'react'; +import Show from '../components/show'; +import BarStack from '../components/tiles/barstack'; + +export default () => { + return ( + +{`import React from 'react'; +import { BarStack } from '@vx/shape'; +import { Group } from '@vx/group'; +import { AxisBottom } from '@vx/axis'; +import { cityTemperature } from '@vx/mock-data'; +import { scaleBand, scaleLinear, scaleOrdinal } from '@vx/scale'; +import { timeParse, timeFormat } from 'd3-time-format'; +import { extent, max } from 'd3-array'; + +const data = cityTemperature.slice(0, 12); +const keys = Object.keys(data[0]).filter(d => d !== 'date'); +const parseDate = timeParse("%Y%m%d"); +const format = timeFormat("%b %d"); +const formatDate = (date) => format(parseDate(date)); + +// accessors +const x = d => d.date; +const y = d => d.value; + +const totals = data.reduce((ret, cur) => { + const t = keys.reduce((dailyTotal, k) => { + dailyTotal += +cur[k] + return dailyTotal; + }, 0) + ret.push(t) + return ret; +}, []) + +export default ({ + width, + height, + margin = { + top: 40 + } +}) => { + if (width < 10) return null; + + // bounds + const xMax = width; + const yMax = height - margin.top - 100; + + // // scales + const xScale = scaleBand({ + rangeRound: [0, xMax], + domain: data.map(x), + padding: 0.2, + tickFormat: () => (val) => formatDate(val) + }); + const yScale = scaleLinear({ + rangeRound: [yMax, 0], + nice: true, + domain: [0, max(totals)], + }); + const zScale = scaleOrdinal({ + domain: keys, + range: ['#6c5efb', '#c998ff', '#a44afe'] + }) + + return ( + + + + + )} + /> + + ); +}`} + + ); +} diff --git a/packages/vx-demo/pages/gallery.js b/packages/vx-demo/pages/gallery.js index 3d097e309..f4ced70e5 100644 --- a/packages/vx-demo/pages/gallery.js +++ b/packages/vx-demo/pages/gallery.js @@ -16,6 +16,7 @@ import Stacked from '../components/tiles/stacked'; import MultiLine from '../components/tiles/multiline'; import Axis from '../components/tiles/axis'; import BarGroup from '../components/tiles/bargroup'; +import BarStack from '../components/tiles/barstack'; const items = [ "#242424", @@ -71,6 +72,7 @@ export default class Gallery extends React.Component { const t8 = this.state.dimensions[7] || [8, 300]; const t9 = this.state.dimensions[8] || [8, 300]; const t10 = this.state.dimensions[9] || [8, 300]; + const t11 = this.state.dimensions[10] || [8, 300]; return ( @@ -333,6 +335,27 @@ export default class Gallery extends React.Component { + + +
this.nodes.add(d)}> +
+ +
+
+
Bar Stack
+
+
{``}
+
+
+
+ +
diff --git a/packages/vx-shape/build/index.js b/packages/vx-shape/build/index.js index 3eef7c303..d8fe3d23e 100644 --- a/packages/vx-shape/build/index.js +++ b/packages/vx-shape/build/index.js @@ -58,6 +58,15 @@ Object.defineProperty(exports, 'BarGroup', { } }); +var _BarStack = require('./shapes/BarStack'); + +Object.defineProperty(exports, 'BarStack', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_BarStack).default; + } +}); + var _callOrValue = require('./util/callOrValue'); Object.defineProperty(exports, 'callOrValue', { diff --git a/packages/vx-shape/src/index.js b/packages/vx-shape/src/index.js index 6c64b663a..f8a30dc56 100644 --- a/packages/vx-shape/src/index.js +++ b/packages/vx-shape/src/index.js @@ -4,4 +4,5 @@ export { default as AreaClosed } from './shapes/AreaClosed'; export { default as AreaStack } from './shapes/AreaStack'; export { default as Bar } from './shapes/Bar'; export { default as BarGroup } from './shapes/BarGroup'; +export { default as BarStack } from './shapes/BarStack'; export { default as callOrValue } from './util/callOrValue'; diff --git a/packages/vx-shape/src/shapes/BarGroup.js b/packages/vx-shape/src/shapes/BarGroup.js index c4b847af8..9c48d3d5f 100644 --- a/packages/vx-shape/src/shapes/BarGroup.js +++ b/packages/vx-shape/src/shapes/BarGroup.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import { Group } from '@vx/group'; import Bar from './Bar'; +import callOrValue from '../util/callOrValue'; export default function BarGroup({ data, @@ -10,14 +11,13 @@ export default function BarGroup({ top, left, x0, - y, - z, x0Scale, x1Scale, yScale, zScale, keys, height, + ...restProps }) { return ( { + ret[cur] = callOrValue(restProps[cur], data); + return ret; + }, {})} /> ); })} @@ -53,15 +57,14 @@ export default function BarGroup({ BarGroup.propTypes = { data: PropTypes.array.isRequired, - className: PropTypes.string, - top: PropTypes.number, - left: PropTypes.number, x0: PropTypes.func.isRequired, - y: PropTypes.func.isRequired, x0Scale: PropTypes.func.isRequired, x1Scale: PropTypes.func.isRequired, yScale: PropTypes.func.isRequired, - z: PropTypes.func, - zScale: PropTypes.func, + zScale: PropTypes.func.isRequired, keys: PropTypes.array.isRequired, + height: PropTypes.number.isRequired, + className: PropTypes.string, + top: PropTypes.number, + left: PropTypes.number, }; diff --git a/packages/vx-shape/src/shapes/BarStack.js b/packages/vx-shape/src/shapes/BarStack.js new file mode 100644 index 000000000..ab9400326 --- /dev/null +++ b/packages/vx-shape/src/shapes/BarStack.js @@ -0,0 +1,65 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import cx from 'classnames'; +import { Group } from '@vx/group'; +import Bar from './Bar'; +import { stack as d3stack } from 'd3-shape'; +import callOrValue from '../util/callOrValue'; + +export default function BarStack({ + data, + className, + top, + left, + x, + xScale, + yScale, + zScale, + keys, + height, + ...restProps +}) { + const series = d3stack().keys(keys)(data); + return ( + + {series && series.map((s, i) => { + return ( + + {s.map((d, ii) => { + return ( + { + ret[cur] = callOrValue(restProps[cur], data); + return ret; + }, {})} + /> + ); + })} + + ); + })} + + ); +} + +BarStack.propTypes = { + data: PropTypes.array.isRequired, + x: PropTypes.func.isRequired, + xScale: PropTypes.func.isRequired, + yScale: PropTypes.func.isRequired, + zScale: PropTypes.func.isRequired, + keys: PropTypes.array.isRequired, + className: PropTypes.string, + top: PropTypes.number, + left: PropTypes.number, +}; diff --git a/packages/vx-shape/test/BarStack.test.js b/packages/vx-shape/test/BarStack.test.js new file mode 100644 index 000000000..a0ce00f28 --- /dev/null +++ b/packages/vx-shape/test/BarStack.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import { BarStack } from '../src'; +import { shallow } from 'enzyme'; + +describe('', () => { + test('it should be defined', () => { + expect(BarStack).toBeDefined() + }) +}) \ No newline at end of file