Skip to content

Commit

Permalink
feat(defs): init support for svg gradients/patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphaël Benitte committed Sep 10, 2017
1 parent 8cb8847 commit cd4c166
Show file tree
Hide file tree
Showing 22 changed files with 593 additions and 105 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ Several libraries already exist for React d3 integration, but just a few provide
- supports [d3 v4](https://github.com/d3/d3/blob/master/CHANGES.md)
- [responsive charts](http://nivo.rocks/#/components?term=responsive) (`<Responsive* />` components)
- highly customizable
- motion/transitions, even the non-d3 based components (DOM managed by React) support transitions within the help of [react-motion](https://github.com/chenglou/react-motion)
- motion/transitions, powered by [react-motion](https://github.com/chenglou/react-motion)
- [component playground](http://nivo.rocks)
- [exhaustive documentation](http://nivo.rocks)
- isomorphic rendering
- support for SVG and [HTML](http://nivo.rocks/#/components?term=html) and [canvas](http://nivo.rocks/#/components?term=canvas) (for a subset of components)
- [SVG charts](http://nivo.rocks/#/components?filter=svg)
- [HTML charts](http://nivo.rocks/#/components?filter=html) (for a restricted subset of components)
- [Canvas charts](http://nivo.rocks/#/components?filter=canvas) (for a restricted subset of components)
- [placeholder components](http://nivo.rocks/#/components?term=placeholder) for advanced customization (`<*Placeholders />` components)
- [server side rendering API](https://github.com/plouc/nivo-api)
- [SVG patterns](http://nivo.rocks/#/guides/patterns)
- [Gradients](http://nivo.rocks/#/guides/gradients)

## Components

Expand Down
15 changes: 14 additions & 1 deletion src/components/charts/SvgWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@
* file that was distributed with this source code.
*/
import React from 'react'
import PropTypes from 'prop-types'
import { Defs } from '../defs'

const SvgWrapper = ({ width, height, margin, children }) => (
const SvgWrapper = ({ width, height, margin, defs, children }) => (
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={height}>
<Defs defs={defs} />
<g transform={`translate(${margin.left},${margin.top})`}>{children}</g>
</svg>
)

SvgWrapper.propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
margin: PropTypes.shape({
top: PropTypes.number.isRequired,
left: PropTypes.number.isRequired,
}).isRequired,
defs: PropTypes.array,
}

export default SvgWrapper
16 changes: 15 additions & 1 deletion src/components/charts/bar/Bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
import React from 'react'
import { TransitionMotion, spring } from 'react-motion'
import { bindDefs } from '../../../lib/defs'
import { generateGroupedBars, generateStackedBars } from '../../../lib/charts/bar'
import enhance from './enhance'
import { BarPropTypes } from './props'
Expand Down Expand Up @@ -88,6 +89,8 @@ const Bar = ({
// theming
theme,
getColor,
defs,
fill,
borderRadius,

// motion
Expand Down Expand Up @@ -140,6 +143,12 @@ const Bar = ({
return true
}

const boundDefs = bindDefs(defs, result.bars, fill, {
idKey: 'key',
dataKey: 'data',
targetKey: 'data.fill',
})

return (
<Container isInteractive={isInteractive} theme={theme}>
{({ showTooltip, hideTooltip }) => {
Expand Down Expand Up @@ -205,7 +214,12 @@ const Bar = ({
}

return (
<SvgWrapper width={outerWidth} height={outerHeight} margin={margin}>
<SvgWrapper
width={outerWidth}
height={outerHeight}
margin={margin}
defs={boundDefs}
>
<Grid
theme={theme}
width={width}
Expand Down
3 changes: 2 additions & 1 deletion src/components/charts/bar/BarItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import BasicTooltip from '../../tooltip/BasicTooltip'

const BarItem = ({
data,

x,
y,
width,
Expand Down Expand Up @@ -51,7 +52,7 @@ const BarItem = ({
height={height}
rx={borderRadius}
ry={borderRadius}
fill={color}
fill={data.fill ? data.fill : color}
onMouseEnter={handleTooltip}
onMouseMove={handleTooltip}
onMouseLeave={hideTooltip}
Expand Down
17 changes: 16 additions & 1 deletion src/components/charts/bar/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,21 @@ export const BarPropTypes = {
labelLinkColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
getLabelLinkColor: PropTypes.func.isRequired, // computed

// theming
// styling
borderRadius: PropTypes.number.isRequired,
getColor: PropTypes.func.isRequired, // computed
defs: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
})
).isRequired,
fill: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
match: PropTypes.oneOfType([PropTypes.oneOf(['*']), PropTypes.object, PropTypes.func])
.isRequired,
})
).isRequired,

// interactivity
isInteractive: PropTypes.bool,
Expand Down Expand Up @@ -93,6 +105,9 @@ export const BarDefaultProps = {
labelLinkColor: 'theme',
labelTextColor: 'theme',

defs: [],
fill: [],

// interactivity
isInteractive: true,
onClick: noop,
Expand Down
10 changes: 8 additions & 2 deletions src/components/charts/line/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,14 @@ export const LinePropTypes = {
})
),

// theming
// styling
getColor: PropTypes.func.isRequired,
lineWidth: PropTypes.number.isRequired,
defs: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
})
).isRequired,

// interactivity
isInteractive: PropTypes.bool.isRequired,
Expand Down Expand Up @@ -97,10 +102,11 @@ export const LineDefaultProps = {
dotBorderColor: 'inherit',
enableDotLabel: false,

// theming
// styling
colors: 'nivo',
colorBy: 'id',
lineWidth: 2,
defs: [],

// interactivity
isInteractive: true,
Expand Down
106 changes: 23 additions & 83 deletions src/components/charts/pie/Pie.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,19 @@
* file that was distributed with this source code.
*/
import React from 'react'
import PropTypes from 'prop-types'
import { merge } from 'lodash'
import { Motion, TransitionMotion, spring } from 'react-motion'
import compose from 'recompose/compose'
import defaultProps from 'recompose/defaultProps'
import pure from 'recompose/pure'
import { getInheritedColorGenerator } from '../../../lib/colors'
import { getLabelGenerator } from '../../../lib/propertiesConverters'
import { degreesToRadians, radiansToDegrees } from '../../../lib/polar'
import { withTheme, withDimensions, withColors } from '../../../hocs'
import { bindDefs } from '../../../lib/defs'
import Container from '../Container'
import SvgWrapper from '../SvgWrapper'
import { pie as d3Pie, arc as d3Arc } from 'd3-shape'
import PieRadialLabels from './PieRadialLabels'
import PieSlicesLabels from './PieSlicesLabels'
import BasicTooltip from '../../tooltip/BasicTooltip'
import { PiePropTypes } from './props'
import enhance from './enhance'

const Pie = ({
data,
Expand Down Expand Up @@ -60,9 +57,11 @@ const Pie = ({
slicesLabelsSkipAngle,
slicesLabelsTextColor,

// theming
// styling
theme,
getColor,
defs,
fill,

// motion
animate,
Expand Down Expand Up @@ -112,10 +111,22 @@ const Pie = ({
const arc = d3Arc()
arc.outerRadius(radius)

const enhancedData = data.map(d => {
const color = getColor(d)
return { ...d, color }
})

const boundDefs = bindDefs(defs, enhancedData, fill)

return (
<Container isInteractive={isInteractive} theme={theme}>
{({ showTooltip, hideTooltip }) => (
<SvgWrapper width={outerWidth} height={outerHeight} margin={margin}>
<SvgWrapper
width={outerWidth}
height={outerHeight}
margin={margin}
defs={boundDefs}
>
<Motion
style={{
centerX: spring(centerX, motionProps),
Expand All @@ -131,17 +142,14 @@ const Pie = ({
.cornerRadius(interpolatingStyle.cornerRadius)
.innerRadius(interpolatingStyle.innerRadius)

const arcsData = interpolatedPie(data).map(d => {
const arcsData = interpolatedPie(enhancedData).map(d => {
const angle = d.endAngle - d.startAngle

return {
...d,
angle,
angleDegrees: radiansToDegrees(angle),
data: {
...d.data,
color: getColor(d.data),
},
data: d.data,
}
})

Expand All @@ -166,7 +174,7 @@ const Pie = ({
<path
key={d.data.id}
d={interpolatedArc(d)}
fill={d.data.color}
fill={d.data.fill ? d.data.fill : d.data.color}
strokeWidth={borderWidth}
stroke={borderColor(d.data)}
onMouseEnter={handleTooltip}
Expand Down Expand Up @@ -202,75 +210,7 @@ const Pie = ({
)
}

Pie.propTypes = {
data: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
value: PropTypes.number.isRequired,
})
).isRequired,

innerRadius: PropTypes.number.isRequired,
padAngle: PropTypes.number.isRequired,
cornerRadius: PropTypes.number.isRequired,

// border
borderWidth: PropTypes.number.isRequired,
borderColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

// radial labels
enableRadialLabels: PropTypes.bool.isRequired,
radialLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
radialLabelsSkipAngle: PropTypes.number,
radialLabelsTextXOffset: PropTypes.number,
radialLabelsTextColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
radialLabelsLinkOffset: PropTypes.number,
radialLabelsLinkDiagonalLength: PropTypes.number,
radialLabelsLinkHorizontalLength: PropTypes.number,
radialLabelsLinkStrokeWidth: PropTypes.number,
radialLabelsLinkColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

// slices labels
enableSlicesLabels: PropTypes.bool.isRequired,
sliceLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
slicesLabelsSkipAngle: PropTypes.number,
slicesLabelsTextColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

// interactivity
isInteractive: PropTypes.bool,
}

export const PieDefaultProps = {
innerRadius: 0,
padAngle: 0,
cornerRadius: 0,

// border
borderWidth: 0,
borderColor: 'inherit:darker(1)',

// radial labels
enableRadialLabels: true,
radialLabel: 'id',
radialLabelsTextColor: 'theme',
radialLabelsLinkColor: 'theme',

// slices labels
enableSlicesLabels: true,
sliceLabel: 'value',
slicesLabelsTextColor: 'theme',

// interactivity
isInteractive: true,
}

const enhance = compose(
defaultProps(PieDefaultProps),
withTheme(),
withDimensions(),
withColors(),
pure
)
Pie.propTypes = PiePropTypes

const enhancedPie = enhance(Pie)
enhancedPie.displayName = 'enhance(Pie)'
Expand Down
18 changes: 18 additions & 0 deletions src/components/charts/pie/enhance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* This file is part of the nivo project.
*
* Copyright 2016-present, Raphaël Benitte.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import compose from 'recompose/compose'
import defaultProps from 'recompose/defaultProps'
import pure from 'recompose/pure'
import { withTheme, withDimensions, withColors } from '../../../hocs'
import { PieDefaultProps } from './props'

export default Component =>
compose(defaultProps(PieDefaultProps), withTheme(), withDimensions(), withColors(), pure)(
Component
)
2 changes: 1 addition & 1 deletion src/components/charts/pie/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
* file that was distributed with this source code.
*/
export { default as Pie } from './Pie'
export * from './Pie'
export { default as ResponsivePie } from './ResponsivePie'
export * from './props'
Loading

0 comments on commit cd4c166

Please sign in to comment.