diff --git a/src/components/axes/Axis.js b/src/components/axes/Axis.js
index 3969b2c15..7a5806e9d 100644
--- a/src/components/axes/Axis.js
+++ b/src/components/axes/Axis.js
@@ -9,7 +9,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { TransitionMotion, spring } from 'react-motion'
-import { max } from 'd3'
import Nivo from '../../Nivo'
import AxisTick from './AxisTick'
diff --git a/src/components/charts/bars/Bar.js b/src/components/charts/bars/Bar.js
index c0c0e92db..45f494240 100644
--- a/src/components/charts/bars/Bar.js
+++ b/src/components/charts/bars/Bar.js
@@ -1,15 +1,19 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import _ from 'lodash'
+import { merge } from 'lodash'
+import { TransitionMotion, spring } from 'react-motion'
import Nivo, { defaultTheme } from '../../../Nivo'
import { margin as marginPropType } from '../../../PropTypes'
import { getColorRange } from '../../../ColorUtils'
+import {
+ generateGroupedBars,
+ generateStackedBars,
+} from '../../../lib/charts/bar'
import SvgWrapper from '../SvgWrapper'
import Axis from '../../axes/Axis'
import Grid from '../../axes/Grid'
import BarItem from './BarItem'
import BarItemLabel from './BarItemLabel'
-import { scaleBand, scaleLinear, stack } from 'd3'
const axisPropType = PropTypes.shape({
tickSize: PropTypes.number,
@@ -17,37 +21,6 @@ const axisPropType = PropTypes.shape({
format: PropTypes.func,
})
-const getAxis = (
- axes,
- scale,
- position,
- width,
- height,
- theme,
- { animate, motionStiffness, motionDamping }
-) => {
- if (!axes[position]) return null
-
- const axis = axes[position]
-
- return (
-
- )
-}
-
export default class Bar extends Component {
static propTypes = {
// data
@@ -142,125 +115,68 @@ export default class Bar extends Component {
const width = _width - margin.left - margin.right
const height = _height - margin.top - margin.bottom
- const theme = _.merge({}, defaultTheme, _theme)
+ const theme = merge({}, defaultTheme, _theme)
const color = getColorRange(colors)
- // determining x scale
- const xLengths = _.uniq(data.map(({ data }) => data.length))
- if (xLengths.length > 1) {
- throw new Error(
- [
- `Found inconsitent data for x,`,
- `expecting all series to have same length`,
- `but found: ${xLengths.join(', ')}`,
- ].join(' ')
- )
- }
- const xScale = scaleBand()
- .rangeRound([0, width])
- .domain(data[0].data.map(({ x }) => x))
- .padding(xPadding)
-
- // determining y scale, depending on `groupMode`
- let maxY
- if (groupMode === 'stacked') {
- maxY = _.max(
- _.range(xLengths).map(i =>
- _.sumBy(data, serie => serie.data[i].y)
- )
- )
- } else if (groupMode === 'grouped') {
- maxY = _.maxBy(
- data.reduce((acc, serie) => [...acc, ...serie.data], []),
- 'y'
- ).y
- } else {
- throw new TypeError(
- [
- `'${groupMode}' is not a valid group mode,`,
- `must be one of: 'grouped', 'stacked'`,
- ].join(' ')
- )
+ const motionProps = {
+ animate,
+ motionDamping,
+ motionStiffness,
}
- const yScale = scaleLinear().rangeRound([height, 0]).domain([0, maxY])
- const rects = []
+ let result
if (groupMode === 'grouped') {
- data.forEach(({ id, data: serie }, serieIndex) => {
- serie.forEach(d => {
- const barWidth = xScale.bandwidth() / data.length
- const x = xScale(d.x) + barWidth * serieIndex
- const y = yScale(d.y)
- const barHeight = height - y
-
- const value = d.y
-
- if (barWidth > 0 && barHeight > 0) {
- rects.push({
- key: `${id}.${d.x}`,
- value,
- x,
- y,
- width: barWidth,
- height: barHeight,
- color: color(id),
- })
- }
- })
+ result = generateGroupedBars(data, width, height, color, {
+ xPadding,
})
} else if (groupMode === 'stacked') {
- const stackedData = data.map(({ id }) => ({
- id,
- data: [],
- }))
- _.range(xLengths).forEach(index => {
- data.forEach(({ data: serie }, serieIndex) => {
- const d = serie[index]
-
- let y0 = 0
- let y1 = d.y
- if (serieIndex > 0) {
- y0 = stackedData[serieIndex - 1].data[index].y1
- y1 = d.y + y0
- }
-
- stackedData[serieIndex].data[index] = Object.assign({}, d, {
- y0,
- y1,
- })
- })
- })
-
- console.log(stackedData)
-
- stackedData.forEach(({ id, data: serie }) => {
- serie.forEach(d => {
- const x = xScale(d.x)
- const barWidth = xScale.bandwidth()
- const y = yScale(d.y1)
- const barHeight = yScale(d.y0) - y
-
- const value = d.y
-
- if (barWidth > 0 && barHeight > 0) {
- rects.push({
- key: `${id}.${d.x}`,
- value,
- x,
- y,
- width: barWidth,
- height: barHeight,
- color: color(id),
- })
- }
- })
+ result = generateStackedBars(data, width, height, color, {
+ xPadding,
})
}
- const motionProps = {
- animate,
- motionDamping,
- motionStiffness,
+ let bars
+ if (animate === true) {
+ bars = (
+ {
+ return {
+ key: bar.key,
+ data: {
+ color: bar.color,
+ value: bar.value,
+ },
+ style: {
+ x: spring(bar.x, motionProps),
+ y: spring(bar.y, motionProps),
+ width: spring(bar.width, motionProps),
+ height: spring(bar.height, motionProps),
+ },
+ }
+ })}
+ >
+ {interpolatedStyles =>
+
+ {interpolatedStyles.map(
+ ({ key, style, data: { value, color } }) =>
+
+ )}
+ }
+
+ )
+ } else {
+ bars = result.bars.map(d => )
}
return (
@@ -269,18 +185,33 @@ export default class Bar extends Component {
theme={theme}
width={width}
height={height}
- xScale={enableGridX ? xScale : null}
- yScale={enableGridY ? yScale : null}
+ xScale={enableGridX ? result.xScale : null}
+ yScale={enableGridY ? result.yScale : null}
/>
- {['left', 'right'].map(position =>
- getAxis(axes, yScale, position, width, height, theme, motionProps)
- )}
- {['top', 'bottom'].map(position =>
- getAxis(axes, xScale, position, width, height, theme, motionProps)
- )}
- {rects.map(d => )}
+ {['top', 'right', 'bottom', 'left'].map(position => {
+ if (!axes[position]) return null
+
+ const axis = axes[position]
+ const scale = ['top', 'bottom'].includes(position)
+ ? result.xScale
+ : result.yScale
+
+ return (
+
+ )
+ })}
+ {bars}
{enableLabels &&
- rects.map(d => )}
+ result.bars.map(d => )}
)
}
diff --git a/src/components/charts/bars/BarsD3.js b/src/components/charts/bars/BarD3.js
similarity index 99%
rename from src/components/charts/bars/BarsD3.js
rename to src/components/charts/bars/BarD3.js
index 3a73a644d..8251e84bf 100644
--- a/src/components/charts/bars/BarsD3.js
+++ b/src/components/charts/bars/BarD3.js
@@ -16,7 +16,7 @@ import { getColorRange, getColorGenerator } from '../../../ColorUtils'
import { margin as marginPropType } from '../../../PropTypes'
import decoratorsFromReactChildren from '../../../lib/decoratorsFromReactChildren'
-class BarsD3 extends Component {
+class BarD3 extends Component {
renderD3(props) {
const {
groupMode,
diff --git a/src/components/charts/bars/BarGroup.js b/src/components/charts/bars/BarGroup.js
deleted file mode 100644
index b4a2f0c25..000000000
--- a/src/components/charts/bars/BarGroup.js
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * This file is part of the nivo project.
- *
- * (c) 2016 Raphaël Benitte
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-import React, { Component } from 'react'
-import _ from 'lodash'
-import PropTypes from 'prop-types'
-import ResponsiveWrapper from '../ResponsiveWrapper'
-import SvgWrapper from '../SvgWrapper'
-import Nivo, { defaultTheme } from '../../../Nivo'
-import { margin as marginPropType } from '../../../PropTypes'
-import { getColorRange } from '../../../ColorUtils'
-import Bar from './Bars'
-import { scalesPropType, scalesFromObject } from '../../../lib/scale'
-
-const MODE_GROUPED = 'group'
-const MODE_STACKED = 'stack'
-
-export default class BarGroup extends Component {
- static propTypes = {
- scales: scalesPropType,
- data: PropTypes.arrayOf(PropTypes.object),
- keys: PropTypes.arrayOf(
- PropTypes.oneOfType([PropTypes.string, PropTypes.number])
- ).isRequired,
- mode: PropTypes.oneOf([MODE_GROUPED, MODE_STACKED]).isRequired,
- colors: PropTypes.any.isRequired,
- children: PropTypes.func.isRequired,
- margin: marginPropType,
- theme: PropTypes.object.isRequired,
- }
-
- static defaultProps = {
- mode: 'stack',
- colors: Nivo.defaults.colorRange,
- theme: {},
- children: () => null,
- }
-
- render() {
- return (
-
- {({ width: _width, height: _height }) => {
- const {
- data,
- margin: _margin,
- keys,
- xScale,
- x,
- yScale,
- scales: _scales,
- colors,
- children,
- theme: _theme,
- } = this.props
-
- const margin = Object.assign(
- {},
- Nivo.defaults.margin,
- _margin
- )
- const width = _width - margin.left - margin.right
- const height = _height - margin.top - margin.bottom
-
- const theme = _.merge({}, defaultTheme, _theme)
- const scales = scalesFromObject(
- _scales,
- width,
- height,
- data
- )
- const getColor = getColorRange(colors)
-
- const barData = data.map(d =>
- keys.reduce((acc, key, index) => {
- let y0 = 0
- let y1 = d[key]
- if (index > 0) {
- y0 = acc[keys[index - 1]][1]
- y1 += y0
- }
-
- return Object.assign(acc, {
- [key]: [y0, y1],
- })
- }, d)
- )
-
- return (
-
- {children({
- data,
- barData,
- scales,
- width,
- height,
- theme,
- })}
-
- {keys.map(key =>
-
- )}
-
-
- )
- }}
-
- )
- }
-}
diff --git a/src/components/charts/bars/Bars.js b/src/components/charts/bars/Bars.js
deleted file mode 100644
index 4d5bcd46c..000000000
--- a/src/components/charts/bars/Bars.js
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * This file is part of the nivo project.
- *
- * (c) 2016 Raphaël Benitte
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-import React, { Component } from 'react'
-import PropTypes from 'prop-types'
-import _ from 'lodash'
-import Nivo from '../../../Nivo'
-import { getColorRange } from '../../../ColorUtils'
-import { getAccessorFor } from '../../../lib/propertiesConverters'
-import BarItem from './BarItem'
-import BarItemLabel from './BarItemLabel'
-
-export default class Bars extends Component {
- static propTypes = {
- data: PropTypes.arrayOf(PropTypes.object),
- colors: PropTypes.any.isRequired,
- scales: PropTypes.object,
- width: PropTypes.number.isRequired,
- height: PropTypes.number.isRequired,
- // labels
- enableLabels: PropTypes.bool.isRequired,
- // motion
- animate: PropTypes.bool.isRequired,
- motionStiffness: PropTypes.number.isRequired,
- motionDamping: PropTypes.number.isRequired,
- }
-
- static defaultProps = {
- colors: Nivo.defaults.colorRange,
- // labels
- enableLabels: true,
- // motion
- animate: true,
- motionStiffness: Nivo.defaults.motionStiffness,
- motionDamping: Nivo.defaults.motionDamping,
- }
-
- render() {
- const {
- data,
- scales,
- xScale: _xScale,
- yScale: _yScale,
- height,
- colors,
- x: _x,
- y: _y,
- } = this.props
-
- const xScale = scales[_xScale]
- const yScale = scales[_yScale]
-
- const getXValue = getAccessorFor(_x)
- const getYValue = getAccessorFor(_y)
-
- const getColor = getColorRange(colors)
-
- const rects = []
- data.forEach((d, i) => {
- let x
- let y
- let barWidth
- let barHeight
-
- const xValue = getXValue(d)
- const yValue = getYValue(d)
-
- if (xScale.bandwidth) {
- barWidth = xScale.bandwidth()
- x = xScale(xValue)
- } else {
- x = 0
- barWidth = xScale(xValue)
- }
-
- if (yScale.bandwidth) {
- barHeight = yScale.bandwidth()
- y = yScale(getYValue(d))
- } else {
- if (Array.isArray(yValue)) {
- y = yScale(yValue[1])
- barHeight = yScale(yValue[0]) - y
- } else {
- y = yScale(yValue)
- barHeight = height - y
- }
- }
-
- if (barWidth > 0 && barHeight > 0) {
- rects.push({
- key: `bar.${i}`,
- x,
- y,
- width: barWidth,
- height: barHeight,
- color: getColor(d),
- })
- }
- })
-
- return (
-
- {rects.map(d => )}
-
- )
- }
-}
diff --git a/src/components/charts/bars/ResponsiveBarsD3.js b/src/components/charts/bars/ResponsiveBarsD3.js
index 51a8f41e9..c09a9b07d 100644
--- a/src/components/charts/bars/ResponsiveBarsD3.js
+++ b/src/components/charts/bars/ResponsiveBarsD3.js
@@ -1,28 +1,22 @@
/*
* This file is part of the nivo project.
*
- * (c) Raphaël Benitte
+ * (c) 2016 Raphaël Benitte
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import React, { Component } from 'react'
-import PropTypes from 'prop-types'
-import Dimensions from 'react-dimensions'
-import BarsD3 from './BarsD3'
+import ResponsiveWrapper from '../ResponsiveWrapper'
+import BarD3 from './BarD3'
-class ResponsiveBarsD3 extends Component {
+export default class ResponsiveBarD3 extends Component {
render() {
- const { containerWidth, containerHeight } = this.props
-
return (
-
+
+ {({ width, height }) =>
+ }
+
)
}
}
-
-export default Dimensions()(ResponsiveBarsD3)
diff --git a/src/components/charts/bars/barsDataSchema.js b/src/components/charts/bars/barsDataSchema.js
deleted file mode 100644
index 621f589a3..000000000
--- a/src/components/charts/bars/barsDataSchema.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const barsDataSchema = {
- type: 'array',
-}
-
-export default barsDataSchema
diff --git a/src/components/charts/bars/index.js b/src/components/charts/bars/index.js
index 0b25ab7a5..fbc4de5bc 100644
--- a/src/components/charts/bars/index.js
+++ b/src/components/charts/bars/index.js
@@ -7,6 +7,4 @@
* file that was distributed with this source code.
*/
export Bar from './Bar'
-export Bars from './Bars'
export ResponsiveBar from './ResponsiveBar'
-export BarGroup from './BarGroup'
diff --git a/src/lib/charts/bar/index.js b/src/lib/charts/bar/index.js
new file mode 100644
index 000000000..4bc2f6f00
--- /dev/null
+++ b/src/lib/charts/bar/index.js
@@ -0,0 +1,178 @@
+import { range, max, maxBy, sumBy, uniq } from 'lodash'
+import { scaleBand, scaleLinear } from 'd3'
+
+/**
+ * Generates X scale.
+ *
+ * @param {Array.