diff --git a/src/components/charts/Container.js b/src/components/charts/Container.js new file mode 100644 index 000000000..fcacfa181 --- /dev/null +++ b/src/components/charts/Container.js @@ -0,0 +1,74 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +const containerStyle = { + position: 'relative', +} + +const tooltipStyle = { + position: 'absolute', + background: '#FFF', + zIndex: 10, + top: 0, + left: 0, + borderRadius: '3px', + boxShadow: '0 1px 2px rgba(0, 0, 0, 0.25)', + padding: '7px 12px', +} + +const Tooltip = ({ x, y, children }) => +
+ {children} +
+ +export default class Container extends Component { + static propTypes = { + children: PropTypes.func.isRequired, + } + + state = { + isTooltipVisible: true, + tooltipContent: 'crap', + tooltipX: 0, + tooltipY: 0, + } + + showTooltip = (content, event) => { + const { pageX, pageY } = event + const bounds = this.container.getBoundingClientRect() + + this.setState({ + isTooltipVisible: true, + tooltipContent: content, + tooltipX: pageX - bounds.left + 20, + tooltipY: pageY - bounds.top, + }) + } + + hideTooltip = () => { + this.setState({ isTooltipVisible: false, tooltipContent: null }) + } + + render() { + const { children } = this.props + const { isTooltipVisible, tooltipContent, tooltipX, tooltipY } = this.state + + return ( +
{ + this.container = container + }} + > + {children({ + showTooltip: this.showTooltip, + hideTooltip: this.hideTooltip, + })} + {isTooltipVisible && + + {tooltipContent} + } +
+ ) + } +} diff --git a/src/components/charts/stream/Stream.js b/src/components/charts/stream/Stream.js index ec2fe53a7..6e169bd55 100644 --- a/src/components/charts/stream/Stream.js +++ b/src/components/charts/stream/Stream.js @@ -26,8 +26,9 @@ import { stackOffsetPropType, stackOffsetFromProp, } from '../../../props' -import { getColorsGenerator } from '../../../lib/colorUtils' +import { getColorRange } from '../../../lib/colorUtils' import SvgWrapper from '../SvgWrapper' +import Container from '../Container' import Axes from '../../axes/Axes' import Grid from '../../axes/Grid' import StreamLayers from './StreamLayers' @@ -37,6 +38,8 @@ const stackMax = layers => max(layers.reduce((acc, layer) => [...acc, ...layer.m const Stream = ({ data, + keys, + order, offsetType, curve, @@ -59,14 +62,13 @@ const Stream = ({ // theming theme, color, + fillOpacity, // motion animate, motionStiffness, motionDamping, }) => { - const keys = range(5) - const stack = d3Stack() .keys(keys) .offset(stackOffsetFromProp(offsetType)) @@ -74,12 +76,6 @@ const Stream = ({ const layers = stack(data) - /* - console.log('DATA', data) - console.log('KEYS', keys) - console.log('LAYERS', layers) - */ - const minValue = stackMin(layers) const maxValue = stackMax(layers) @@ -92,6 +88,13 @@ const Stream = ({ .y1(d => yScale(d[1])) .curve(curveFromProp(curve)) + const enhancedLayers = layers.map((layer, i) => ({ + id: keys[i], + layer, + path: area(layer), + color: color(i), + })) + const motionProps = { animate, motionDamping, @@ -99,43 +102,46 @@ const Stream = ({ } return ( - - - ({ - layer, - path: area(layer), - color: color(i), - }))} - area={area} - {...motionProps} - /> - - + + {({ showTooltip, hideTooltip }) => + + + + + } + ) } Stream.propTypes = { // data data: PropTypes.arrayOf(PropTypes.object).isRequired, + keys: PropTypes.array.isRequired, order: stackOrderPropType.isRequired, offsetType: stackOffsetPropType.isRequired, @@ -157,7 +163,7 @@ Stream.propTypes = { // theming theme: PropTypes.object.isRequired, colors: PropTypes.any.isRequired, - colorBy: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), + fillOpacity: PropTypes.number.isRequired, color: PropTypes.func.isRequired, // motion @@ -167,7 +173,7 @@ Stream.propTypes = { export const StreamDefaultProps = { order: 'none', offsetType: 'wiggle', - curve: 'monotoneX', + curve: 'catmullRom', // dimensions margin: Nivo.defaults.margin, @@ -180,7 +186,7 @@ export const StreamDefaultProps = { // theming theme: {}, colors: 'nivo', - colorBy: 'id', + fillOpacity: 1, // motion animate: true, @@ -191,8 +197,8 @@ export const StreamDefaultProps = { const enhance = compose( defaultProps(StreamDefaultProps), withPropsOnChange(['theme'], ({ theme }) => ({ theme: merge({}, defaultTheme, theme) })), - withPropsOnChange(['colors', 'colorBy'], ({ colors, colorBy }) => ({ - color: getColorsGenerator(colors, d => Nivo.defaults.colorRange(d)), + withPropsOnChange(['colors'], ({ colors, colorBy }) => ({ + color: getColorRange(colors), })), withPropsOnChange( (props, nextProps) => diff --git a/src/components/charts/stream/StreamLayers.js b/src/components/charts/stream/StreamLayers.js index e4c3cfe3e..412616c0d 100644 --- a/src/components/charts/stream/StreamLayers.js +++ b/src/components/charts/stream/StreamLayers.js @@ -13,6 +13,10 @@ import SmartMotion from '../../SmartMotion' const StreamLayers = ({ layers, + fillOpacity, + + showTooltip, + hideTooltip, // motion animate, @@ -22,7 +26,21 @@ const StreamLayers = ({ if (animate !== true) { return ( - {layers.map(({ path, color }, i) => )} + {layers.map(({ id, path, color }, i) => + { + showTooltip(id, e) + }} + onMouseEnter={e => { + showTooltip(id, e) + }} + onMouseLeave={hideTooltip} + d={path} + fill={color} + fillOpacity={fillOpacity} + /> + )} ) } @@ -34,15 +52,26 @@ const StreamLayers = ({ return ( - {layers.map(({ path, color }, i) => + {layers.map(({ id, path, color }, i) => ({ d: spring(path, springConfig), fill: spring(color, springConfig), + fillOpacity: spring(fillOpacity, springConfig), })} > - {style => } + {style => + { + showTooltip(id, e) + }} + onMouseEnter={e => { + showTooltip(id, e) + }} + onMouseLeave={hideTooltip} + {...style} + />} )} @@ -51,6 +80,7 @@ const StreamLayers = ({ StreamLayers.propTypes = { area: PropTypes.func.isRequired, + fillOpacity: PropTypes.number.isRequired, // motion ...motionPropTypes,