From b7e8bea42ffc4470549e33da2c4713367634d3dc Mon Sep 17 00:00:00 2001 From: Alexander Antonov Date: Thu, 12 Oct 2017 23:12:20 +0300 Subject: [PATCH] feat(tooltip): prop to format values in tooltip was added --- src/components/charts/bar/Bar.js | 2 + src/components/charts/bar/BarItem.js | 3 ++ src/components/charts/bar/props.js | 1 + src/components/charts/bubble/Bubble.js | 2 + src/components/charts/bubble/interactivity.js | 12 ++++- src/components/charts/bubble/props.js | 1 + src/components/charts/chord/Chord.js | 3 ++ .../charts/chord/ChordArcTooltip.js | 11 +++- src/components/charts/chord/ChordArcs.js | 3 +- src/components/charts/chord/ChordRibbons.js | 20 ++++++-- src/components/charts/chord/props.js | 1 + src/components/charts/heatmap/HeatMap.js | 4 +- .../charts/heatmap/HeatMapCellTooltip.js | 3 +- src/components/charts/heatmap/props.js | 1 + src/components/charts/line/Line.js | 2 + src/components/charts/line/LineSlices.js | 3 +- src/components/charts/line/LineSlicesItem.js | 27 +++++++--- src/components/charts/line/props.js | 1 + src/components/charts/pie/Pie.js | 2 + src/components/charts/pie/props.js | 1 + src/components/charts/radar/Radar.js | 3 ++ src/components/charts/radar/RadarTooltip.js | 2 + .../charts/radar/RadarTooltipItem.js | 39 ++++++++++----- src/components/charts/sankey/Sankey.js | 3 ++ src/components/charts/sankey/SankeyLinks.js | 3 ++ .../charts/sankey/SankeyLinksItem.js | 8 +-- src/components/charts/sankey/props.js | 1 + src/components/charts/stream/Stream.js | 2 + src/components/charts/stream/StreamSlices.js | 3 +- .../charts/stream/StreamSlicesItem.js | 27 +++++++--- src/components/charts/stream/props.js | 1 + src/components/tooltip/BasicTooltip.js | 50 +++++++++++++------ stories/charts/bar.stories.js | 16 ++++++ stories/charts/bubble.stories.js | 9 ++++ stories/charts/chord.stories.js | 11 ++++ stories/charts/heatmap.stories.js | 10 ++++ stories/charts/line.stories.js | 17 +++++++ stories/charts/pie.stories.js | 10 ++++ stories/charts/radar.stories.js | 10 ++++ stories/charts/sankey.stories.js | 9 ++++ stories/charts/stream.stories.js | 10 ++++ 41 files changed, 287 insertions(+), 60 deletions(-) diff --git a/src/components/charts/bar/Bar.js b/src/components/charts/bar/Bar.js index bbde78593..edd1f9c58 100644 --- a/src/components/charts/bar/Bar.js +++ b/src/components/charts/bar/Bar.js @@ -102,6 +102,7 @@ const Bar = ({ // interactivity isInteractive, + tooltipFormat, onClick, }) => { const options = { @@ -163,6 +164,7 @@ const Bar = ({ hideTooltip, onClick, theme, + tooltipFormat, } let bars diff --git a/src/components/charts/bar/BarItem.js b/src/components/charts/bar/BarItem.js index 14bd79f34..90934cb64 100644 --- a/src/components/charts/bar/BarItem.js +++ b/src/components/charts/bar/BarItem.js @@ -32,6 +32,7 @@ const BarItem = ({ showTooltip, hideTooltip, onClick, + tooltipFormat, theme, }) => { @@ -43,6 +44,7 @@ const BarItem = ({ enableChip={true} color={color} theme={theme} + format={tooltipFormat} />, e ) @@ -100,6 +102,7 @@ BarItem.propTypes = { shouldRenderLabel: PropTypes.bool.isRequired, labelColor: PropTypes.string.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), showTooltip: PropTypes.func.isRequired, hideTooltip: PropTypes.func.isRequired, diff --git a/src/components/charts/bar/props.js b/src/components/charts/bar/props.js index 97a508a1d..273474d60 100644 --- a/src/components/charts/bar/props.js +++ b/src/components/charts/bar/props.js @@ -61,6 +61,7 @@ export const BarPropTypes = { // interactivity isInteractive: PropTypes.bool, onClick: PropTypes.func.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), // canvas specific pixelRatio: PropTypes.number.isRequired, diff --git a/src/components/charts/bubble/Bubble.js b/src/components/charts/bubble/Bubble.js index 51c9eefea..dbd75aed0 100644 --- a/src/components/charts/bubble/Bubble.js +++ b/src/components/charts/bubble/Bubble.js @@ -42,6 +42,7 @@ const Bubble = ({ // interactivity isInteractive, onClick, + tooltipFormat, isZoomable, zoomToNode, }) => { @@ -59,6 +60,7 @@ const Bubble = ({ isZoomable, zoomToNode, theme, + tooltipFormat, }) return ( diff --git a/src/components/charts/bubble/interactivity.js b/src/components/charts/bubble/interactivity.js index 7214f1653..f58a9cb63 100644 --- a/src/components/charts/bubble/interactivity.js +++ b/src/components/charts/bubble/interactivity.js @@ -11,7 +11,16 @@ import BasicTooltip from '../../tooltip/BasicTooltip' export const getNodeHandlers = ( node, - { isInteractive, onClick, showTooltip, hideTooltip, isZoomable, zoomToNode, theme } + { + isInteractive, + onClick, + showTooltip, + hideTooltip, + isZoomable, + zoomToNode, + theme, + tooltipFormat, + } ) => { if (!isInteractive) return {} @@ -23,6 +32,7 @@ export const getNodeHandlers = ( enableChip={true} color={node.color} theme={theme} + format={tooltipFormat} />, e ) diff --git a/src/components/charts/bubble/props.js b/src/components/charts/bubble/props.js index 34ec9b6a6..f750f3808 100644 --- a/src/components/charts/bubble/props.js +++ b/src/components/charts/bubble/props.js @@ -47,6 +47,7 @@ const commonPropTypes = { isInteractive: PropTypes.bool.isRequired, onClick: PropTypes.func.isRequired, isZoomable: PropTypes.bool.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), } export const BubblePropTypes = { diff --git a/src/components/charts/chord/Chord.js b/src/components/charts/chord/Chord.js index 6b70f465d..2e0783e9d 100644 --- a/src/components/charts/chord/Chord.js +++ b/src/components/charts/chord/Chord.js @@ -46,6 +46,7 @@ const Chord = ({ // interactivity isInteractive, + tooltipFormat, // motion animate, @@ -83,6 +84,7 @@ const Chord = ({ getOpacity={getRibbonOpacity} setCurrent={setCurrentRibbon} theme={theme} + tooltipFormat={tooltipFormat} showTooltip={showTooltip} hideTooltip={hideTooltip} {...motionProps} @@ -95,6 +97,7 @@ const Chord = ({ getOpacity={getArcOpacity} setCurrent={setCurrentArc} theme={theme} + tooltipFormat={tooltipFormat} showTooltip={showTooltip} hideTooltip={hideTooltip} {...motionProps} diff --git a/src/components/charts/chord/ChordArcTooltip.js b/src/components/charts/chord/ChordArcTooltip.js index 395e778d1..207e1d706 100644 --- a/src/components/charts/chord/ChordArcTooltip.js +++ b/src/components/charts/chord/ChordArcTooltip.js @@ -11,8 +11,15 @@ import PropTypes from 'prop-types' import pure from 'recompose/pure' import BasicTooltip from '../../tooltip/BasicTooltip' -const ChordArcTooltip = ({ arc, theme }) => ( - +const ChordArcTooltip = ({ arc, theme, format }) => ( + ) ChordArcTooltip.propTypes = { diff --git a/src/components/charts/chord/ChordArcs.js b/src/components/charts/chord/ChordArcs.js index a10f9b4e8..ebb6fa797 100644 --- a/src/components/charts/chord/ChordArcs.js +++ b/src/components/charts/chord/ChordArcs.js @@ -20,6 +20,7 @@ const ChordArcs = ({ getOpacity, shapeGenerator, theme, + tooltipFormat, setCurrent, showTooltip, hideTooltip, @@ -30,7 +31,7 @@ const ChordArcs = ({ motionStiffness, }) => { const commonProps = arc => { - const arcTooltip = + const arcTooltip = return { strokeWidth: borderWidth, diff --git a/src/components/charts/chord/ChordRibbons.js b/src/components/charts/chord/ChordRibbons.js index d07873d19..c8d51b2e1 100644 --- a/src/components/charts/chord/ChordRibbons.js +++ b/src/components/charts/chord/ChordRibbons.js @@ -8,8 +8,11 @@ */ import React from 'react' import PropTypes from 'prop-types' -import { mapValues } from 'lodash' +import { isFunction, mapValues } from 'lodash' import { TransitionMotion, spring } from 'react-motion' +import { format as d3Format } from 'd3-format' +import compose from 'recompose/compose' +import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' import { colorMotionSpring, getInterpolatedColor } from '../../../lib/colors' import { midAngle } from '../../../lib/polar' @@ -83,6 +86,7 @@ const ChordRibbons = ({ getBorderColor, getOpacity, theme, + tooltipFormat, setCurrent, showTooltip, hideTooltip, @@ -100,12 +104,12 @@ const ChordRibbons = ({ [ , {ribbon.source.id}, - ribbon.source.value, + tooltipFormat ? tooltipFormat(ribbon.source.value) : ribbon.source.value, ], [ , {ribbon.target.id}, - ribbon.target.value, + tooltipFormat ? tooltipFormat(ribbon.target.value) : ribbon.target.value, ], ]} /> @@ -221,4 +225,12 @@ ChordRibbons.propTypes = { hideTooltip: PropTypes.func.isRequired, } -export default pure(ChordRibbons) +const enhance = compose( + withPropsOnChange(['tooltipFormat'], ({ tooltipFormat }) => { + if (!tooltipFormat || isFunction(tooltipFormat)) return { tooltipFormat } + return { tooltipFormat: d3Format(tooltipFormat) } + }), + pure +) + +export default enhance(ChordRibbons) diff --git a/src/components/charts/chord/props.js b/src/components/charts/chord/props.js index 3a204e801..f5fa3f2b8 100644 --- a/src/components/charts/chord/props.js +++ b/src/components/charts/chord/props.js @@ -46,6 +46,7 @@ export const ChordPropTypes = { arcHoverOthersOpacity: PropTypes.number.isRequired, ribbonHoverOpacity: PropTypes.number.isRequired, ribbonHoverOthersOpacity: PropTypes.number.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), // canvas specific pixelRatio: PropTypes.number.isRequired, diff --git a/src/components/charts/heatmap/HeatMap.js b/src/components/charts/heatmap/HeatMap.js index 74bcbac12..7182981d0 100644 --- a/src/components/charts/heatmap/HeatMap.js +++ b/src/components/charts/heatmap/HeatMap.js @@ -25,9 +25,9 @@ class HeatMap extends Component { static propTypes = HeatMapPropTypes handleNodeHover = (showTooltip, node, event) => { - const { setCurrentNode, theme } = this.props + const { setCurrentNode, theme, tooltipFormat } = this.props setCurrentNode(node) - showTooltip(, event) + showTooltip(, event) } handleNodeLeave = hideTooltip => { diff --git a/src/components/charts/heatmap/HeatMapCellTooltip.js b/src/components/charts/heatmap/HeatMapCellTooltip.js index 36062e6d2..ff96eefa6 100644 --- a/src/components/charts/heatmap/HeatMapCellTooltip.js +++ b/src/components/charts/heatmap/HeatMapCellTooltip.js @@ -10,13 +10,14 @@ import React from 'react' import pure from 'recompose/pure' import BasicTooltip from '../../tooltip/BasicTooltip' -const HeatMapCellTooltip = ({ node, theme }) => ( +const HeatMapCellTooltip = ({ node, theme, format }) => ( ) diff --git a/src/components/charts/heatmap/props.js b/src/components/charts/heatmap/props.js index 4a47247b6..2d4782f05 100644 --- a/src/components/charts/heatmap/props.js +++ b/src/components/charts/heatmap/props.js @@ -53,6 +53,7 @@ export const HeatMapPropTypes = { hoverTarget: PropTypes.oneOf(['cell', 'row', 'column', 'rowColumn']).isRequired, cellHoverOpacity: PropTypes.number.isRequired, cellHoverOthersOpacity: PropTypes.number.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), // canvas specific pixelRatio: PropTypes.number.isRequired, diff --git a/src/components/charts/line/Line.js b/src/components/charts/line/Line.js index c3e448bd2..67f6c87a6 100644 --- a/src/components/charts/line/Line.js +++ b/src/components/charts/line/Line.js @@ -81,6 +81,7 @@ const Line = ({ // interactivity isInteractive, + tooltipFormat, // stackTooltip enableStackTooltip, @@ -137,6 +138,7 @@ const Line = ({ showTooltip={showTooltip} hideTooltip={hideTooltip} theme={theme} + tooltipFormat={tooltipFormat} /> )} {enableDots && ( diff --git a/src/components/charts/line/LineSlices.js b/src/components/charts/line/LineSlices.js index 4fb3d37ec..8c180dbef 100644 --- a/src/components/charts/line/LineSlices.js +++ b/src/components/charts/line/LineSlices.js @@ -11,7 +11,7 @@ import PropTypes from 'prop-types' import pure from 'recompose/pure' import LineSlicesItem from './LineSlicesItem' -const LineSlices = ({ slices, height, showTooltip, hideTooltip, theme }) => ( +const LineSlices = ({ slices, height, showTooltip, hideTooltip, theme, tooltipFormat }) => ( {slices.map(slice => ( ( showTooltip={showTooltip} hideTooltip={hideTooltip} theme={theme} + tooltipFormat={tooltipFormat} /> ))} diff --git a/src/components/charts/line/LineSlicesItem.js b/src/components/charts/line/LineSlicesItem.js index b7f54f36b..5a0e044f4 100644 --- a/src/components/charts/line/LineSlicesItem.js +++ b/src/components/charts/line/LineSlicesItem.js @@ -8,6 +8,8 @@ */ import React from 'react' import PropTypes from 'prop-types' +import { isFunction } from 'lodash' +import { format as d3Format } from 'd3-format' import compose from 'recompose/compose' import pure from 'recompose/pure' import withState from 'recompose/withState' @@ -56,14 +58,23 @@ LineSlicesItem.propTypes = { const enhance = compose( withState('isHover', 'setIsHover', false), - withPropsOnChange(['slice', 'theme'], ({ slice, theme }) => ({ - tooltip: ( - [, p.id, p.value])} - /> - ), - })), + withPropsOnChange(['slice', 'theme', 'tooltipFormat'], ({ slice, theme, tooltipFormat }) => { + const format = + !tooltipFormat || isFunction(tooltipFormat) ? tooltipFormat : d3Format(tooltipFormat) + + return { + tooltip: ( + [ + , + p.id, + format ? format(p.value) : p.value, + ])} + /> + ), + } + }), withHandlers({ showTooltip: ({ showTooltip, setIsHover, tooltip }) => e => { setIsHover(true) diff --git a/src/components/charts/line/props.js b/src/components/charts/line/props.js index fd0b20355..81618aad5 100644 --- a/src/components/charts/line/props.js +++ b/src/components/charts/line/props.js @@ -75,6 +75,7 @@ export const LinePropTypes = { // interactivity isInteractive: PropTypes.bool.isRequired, enableStackTooltip: PropTypes.bool.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), } export const LineDefaultProps = { diff --git a/src/components/charts/pie/Pie.js b/src/components/charts/pie/Pie.js index 815e9c20c..d4752a431 100644 --- a/src/components/charts/pie/Pie.js +++ b/src/components/charts/pie/Pie.js @@ -71,6 +71,7 @@ const Pie = ({ // interactivity isInteractive, + tooltipFormat, }) => { const centerX = width / 2 const centerY = height / 2 @@ -168,6 +169,7 @@ const Pie = ({ enableChip={true} color={d.data.color} theme={theme} + format={tooltipFormat} />, e ) diff --git a/src/components/charts/pie/props.js b/src/components/charts/pie/props.js index 6eda512ed..866f4ae1a 100644 --- a/src/components/charts/pie/props.js +++ b/src/components/charts/pie/props.js @@ -59,6 +59,7 @@ export const PiePropTypes = { // interactivity isInteractive: PropTypes.bool, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), } export const PieDefaultProps = { diff --git a/src/components/charts/radar/Radar.js b/src/components/charts/radar/Radar.js index e96a28673..096e2cc83 100644 --- a/src/components/charts/radar/Radar.js +++ b/src/components/charts/radar/Radar.js @@ -76,6 +76,7 @@ const Radar = ({ // interactivity isInteractive, + tooltipFormat, }) => { const motionProps = { animate, @@ -119,6 +120,7 @@ const Radar = ({ radius={radius} angleStep={angleStep} theme={theme} + tooltipFormat={tooltipFormat} showTooltip={showTooltip} hideTooltip={hideTooltip} /> @@ -191,6 +193,7 @@ Radar.propTypes = { // interactivity isInteractive: PropTypes.bool.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), } export const RadarDefaultProps = { diff --git a/src/components/charts/radar/RadarTooltip.js b/src/components/charts/radar/RadarTooltip.js index 7af07e8c6..ce1e5e087 100644 --- a/src/components/charts/radar/RadarTooltip.js +++ b/src/components/charts/radar/RadarTooltip.js @@ -20,6 +20,7 @@ const RadarTooltip = ({ radius, angleStep, theme, + tooltipFormat, showTooltip, hideTooltip, }) => { @@ -51,6 +52,7 @@ const RadarTooltip = ({ radius={radius} arcGenerator={arc} theme={theme} + tooltipFormat={tooltipFormat} showTooltip={showTooltip} hideTooltip={hideTooltip} /> diff --git a/src/components/charts/radar/RadarTooltipItem.js b/src/components/charts/radar/RadarTooltipItem.js index f3d481860..830829758 100644 --- a/src/components/charts/radar/RadarTooltipItem.js +++ b/src/components/charts/radar/RadarTooltipItem.js @@ -8,6 +8,8 @@ */ import React from 'react' import PropTypes from 'prop-types' +import { isFunction } from 'lodash' +import { format as d3Format } from 'd3-format' import compose from 'recompose/compose' import withState from 'recompose/withState' import withPropsOnChange from 'recompose/withPropsOnChange' @@ -58,19 +60,30 @@ RadarTooltipItem.propTypes = { const enhance = compose( withState('isHover', 'setIsHover', false), withPropsOnChange( - ['datum', 'keys', 'index', 'colorByKey', 'theme'], - ({ datum, keys, index, colorByKey, theme }) => ({ - tooltip: ( - {index}} - rows={sortBy( - keys.map(key => [, key, datum[key]]), - '2' - ).reverse()} - theme={theme} - /> - ), - }) + ['datum', 'keys', 'index', 'colorByKey', 'theme', 'tooltipFormat'], + ({ datum, keys, index, colorByKey, theme, tooltipFormat }) => { + const format = + !tooltipFormat || isFunction(tooltipFormat) + ? tooltipFormat + : d3Format(tooltipFormat) + + return { + tooltip: ( + {index}} + rows={sortBy( + keys.map(key => [ + , + key, + format ? format(datum[key]) : datum[key], + ]), + '2' + ).reverse()} + theme={theme} + /> + ), + } + } ), withPropsOnChange( ['startAngle', 'endAngle', 'radius', 'arcGenerator'], diff --git a/src/components/charts/sankey/Sankey.js b/src/components/charts/sankey/Sankey.js index 2d84be420..66334ff0f 100644 --- a/src/components/charts/sankey/Sankey.js +++ b/src/components/charts/sankey/Sankey.js @@ -77,6 +77,7 @@ const Sankey = ({ // interactivity isInteractive, onClick, + tooltipFormat, }) => { const sankey = d3Sankey() .nodeAlign(sankeyAlignmentFromProp(align)) @@ -153,6 +154,7 @@ const Sankey = ({ onClick={onClick} tooltip={linkTooltip} theme={theme} + tooltipFormat={tooltipFormat} {...motionProps} /> {enableLabels && ( diff --git a/src/components/charts/sankey/SankeyLinks.js b/src/components/charts/sankey/SankeyLinks.js index b53aecc16..cce87108d 100644 --- a/src/components/charts/sankey/SankeyLinks.js +++ b/src/components/charts/sankey/SankeyLinks.js @@ -38,6 +38,7 @@ const SankeyLinks = ({ currentLink, isCurrentLink, onClick, + tooltipFormat, tooltip, theme, @@ -66,6 +67,7 @@ const SankeyLinks = ({ onClick={onClick} tooltip={tooltip} theme={theme} + tooltipFormat={tooltipFormat} /> ))} @@ -100,6 +102,7 @@ const SankeyLinks = ({ onClick={onClick} tooltip={tooltip} theme={theme} + tooltipFormat={tooltipFormat} /> )} diff --git a/src/components/charts/sankey/SankeyLinksItem.js b/src/components/charts/sankey/SankeyLinksItem.js index 7a399f56d..c99828a5a 100644 --- a/src/components/charts/sankey/SankeyLinksItem.js +++ b/src/components/charts/sankey/SankeyLinksItem.js @@ -30,14 +30,14 @@ const tooltipStyles = { }, } -const TooltipContent = ({ link }) => ( +const TooltipContent = ({ link, format }) => ( {link.source.label}  >  {link.target.label} - {link.value} + {format ? format(link.value) : link.value} ) @@ -99,14 +99,14 @@ SankeyLinksItem.propTypes = { } const enhance = compose( - withPropsOnChange(['link', 'theme', 'tooltip'], ({ link, theme, tooltip }) => { + withPropsOnChange(['link', 'theme', 'tooltip', 'tooltipFormat'], ({ link, theme, tooltip, tooltipFormat }) => { if (tooltip) { return { tooltip: , } } return { - tooltip: } theme={theme} />, + tooltip: } theme={theme} />, } }), withPropsOnChange(['onClick', 'link'], ({ onClick, link }) => ({ diff --git a/src/components/charts/sankey/props.js b/src/components/charts/sankey/props.js index ed77c74cb..1add05021 100644 --- a/src/components/charts/sankey/props.js +++ b/src/components/charts/sankey/props.js @@ -61,6 +61,7 @@ export const SankeyPropTypes = { // interactivity isInteractive: PropTypes.bool.isRequired, onClick: PropTypes.func.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), } export const SankeyDefaultProps = { diff --git a/src/components/charts/stream/Stream.js b/src/components/charts/stream/Stream.js index 09ce40e6c..04d6b5211 100644 --- a/src/components/charts/stream/Stream.js +++ b/src/components/charts/stream/Stream.js @@ -57,6 +57,7 @@ const Stream = ({ // interactivity isInteractive, + tooltipFormat, // stack tooltip enableStackTooltip, @@ -146,6 +147,7 @@ const Stream = ({ showTooltip={showTooltip} hideTooltip={hideTooltip} theme={theme} + tooltipFormat={tooltipFormat} /> )} diff --git a/src/components/charts/stream/StreamSlices.js b/src/components/charts/stream/StreamSlices.js index e374e4c20..5477038e0 100644 --- a/src/components/charts/stream/StreamSlices.js +++ b/src/components/charts/stream/StreamSlices.js @@ -11,7 +11,7 @@ import PropTypes from 'prop-types' import pure from 'recompose/pure' import StreamSlicesItem from './StreamSlicesItem' -const StreamSlices = ({ slices, height, showTooltip, hideTooltip, theme }) => ( +const StreamSlices = ({ slices, height, showTooltip, hideTooltip, theme, tooltipFormat }) => ( {slices.map(slice => ( ( showTooltip={showTooltip} hideTooltip={hideTooltip} theme={theme} + tooltipFormat={tooltipFormat} /> ))} diff --git a/src/components/charts/stream/StreamSlicesItem.js b/src/components/charts/stream/StreamSlicesItem.js index 6ab557162..84f13cdfd 100644 --- a/src/components/charts/stream/StreamSlicesItem.js +++ b/src/components/charts/stream/StreamSlicesItem.js @@ -8,6 +8,8 @@ */ import React from 'react' import PropTypes from 'prop-types' +import { isFunction } from 'lodash' +import { format as d3Format } from 'd3-format' import compose from 'recompose/compose' import pure from 'recompose/pure' import withState from 'recompose/withState' @@ -53,14 +55,23 @@ StreamSlicesItem.propTypes = { const enhance = compose( withState('isHover', 'setIsHover', false), - withPropsOnChange(['slice', 'theme'], ({ slice, theme }) => ({ - tooltip: ( - [, p.id, p.value])} - /> - ), - })), + withPropsOnChange(['slice', 'theme', 'tooltipFormat'], ({ slice, theme, tooltipFormat }) => { + const format = + !tooltipFormat || isFunction(tooltipFormat) ? tooltipFormat : d3Format(tooltipFormat) + + return { + tooltip: ( + [ + , + p.id, + format ? format(p.value) : p.value, + ])} + /> + ), + } + }), withHandlers({ showTooltip: ({ showTooltip, setIsHover, tooltip }) => e => { setIsHover(true) diff --git a/src/components/charts/stream/props.js b/src/components/charts/stream/props.js index 9a568b933..de99dee49 100644 --- a/src/components/charts/stream/props.js +++ b/src/components/charts/stream/props.js @@ -54,6 +54,7 @@ export const StreamPropTypes = { // interactivity isInteractive: PropTypes.bool, enableStackTooltip: PropTypes.bool.isRequired, + tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), } export const StreamDefaultProps = { diff --git a/src/components/tooltip/BasicTooltip.js b/src/components/tooltip/BasicTooltip.js index 985586d28..9929aeca5 100644 --- a/src/components/tooltip/BasicTooltip.js +++ b/src/components/tooltip/BasicTooltip.js @@ -8,31 +8,45 @@ */ import React from 'react' import PropTypes from 'prop-types' +import { isFunction } from 'lodash' +import { format as d3Format } from 'd3-format' +import compose from 'recompose/compose' +import withPropsOnChange from 'recompose/withPropsOnChange' import pure from 'recompose/pure' import Chip from './Chip' const chipStyle = { marginRight: 7 } -const BasicTooltip = ({ id, value, enableChip, color, theme }) => ( -
-
- {enableChip && } - {value !== undefined ? ( - - {id}: {value} - - ) : ( - id - )} +const BasicTooltip = props => { + const { id, value: _value, format, enableChip, color, theme } = props + + let value = _value + if (format !== undefined && value !== undefined) { + value = format(value) + } + + return ( +
+
+ {enableChip && } + {value !== undefined ? ( + + {id}: {value} + + ) : ( + id + )} +
-
-) + ) +} BasicTooltip.propTypes = { id: PropTypes.node.isRequired, value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), enableChip: PropTypes.bool.isRequired, color: PropTypes.string, + format: PropTypes.func, theme: PropTypes.shape({ tooltip: PropTypes.shape({ @@ -46,4 +60,12 @@ BasicTooltip.defaultProps = { enableChip: false, } -export default pure(BasicTooltip) +const enhance = compose( + withPropsOnChange(['format'], ({ format }) => { + if (!format || isFunction(format)) return { format } + return { format: d3Format(format) } + }), + pure +) + +export default enhance(BasicTooltip) diff --git a/stories/charts/bar.stories.js b/stories/charts/bar.stories.js index 07b8ae060..dd2b5a3d1 100644 --- a/stories/charts/bar.stories.js +++ b/stories/charts/bar.stories.js @@ -162,3 +162,19 @@ stories.add('custom bar item', () => ( labelTextColor="inherit:darker(1)" /> )) + +stories.add('with formatted values', () => ( + + Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + }), + }} + tooltipFormat={value => + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +)) diff --git a/stories/charts/bubble.stories.js b/stories/charts/bubble.stories.js index 4807bfbb0..6d886506f 100644 --- a/stories/charts/bubble.stories.js +++ b/stories/charts/bubble.stories.js @@ -19,3 +19,12 @@ storiesOf('Bubble', module) .addDecorator(story =>
{story()}
) .add('default', () => ) .add('rendering leaves only', () => ) + .add('with formatted values', () => ( + + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> + )) diff --git a/stories/charts/chord.stories.js b/stories/charts/chord.stories.js index cd18753a1..7a7bb9351 100644 --- a/stories/charts/chord.stories.js +++ b/stories/charts/chord.stories.js @@ -55,3 +55,14 @@ stories.add('putting labels inside arcs', () => ( labelTextColor="inherit:darker(1.2)" /> )) + +stories.add('with formatted values', () => ( + + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +)) diff --git a/stories/charts/heatmap.stories.js b/stories/charts/heatmap.stories.js index 69e2270a2..8906644e5 100644 --- a/stories/charts/heatmap.stories.js +++ b/stories/charts/heatmap.stories.js @@ -113,3 +113,13 @@ stories.add('Custom cell component', () => ( labelTextColor="inherit:darker(1.6)" /> )) + +stories.add('with formatted values', () => ( + + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +)) diff --git a/stories/charts/line.stories.js b/stories/charts/line.stories.js index c285c6889..8e0743e07 100644 --- a/stories/charts/line.stories.js +++ b/stories/charts/line.stories.js @@ -204,3 +204,20 @@ stories.add('with custom min/max Y', () => ( maxY={1} /> )) + +stories.add('with formatted values', () => ( + + Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + }), + }} + curve="monotoneX" + tooltipFormat={value => + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +)) diff --git a/stories/charts/pie.stories.js b/stories/charts/pie.stories.js index 82ca6cd9a..edfc5723a 100644 --- a/stories/charts/pie.stories.js +++ b/stories/charts/pie.stories.js @@ -49,3 +49,13 @@ stories.add('custom radial label', () => ( enableSlicesLabels={false} /> )) + +stories.add('with formatted values', () => ( + + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +)) diff --git a/stories/charts/radar.stories.js b/stories/charts/radar.stories.js index 2b7a4d5b4..735548518 100644 --- a/stories/charts/radar.stories.js +++ b/stories/charts/radar.stories.js @@ -81,3 +81,13 @@ stories.add('custom dot symbol', () => ( gridLabelOffset={36} /> )) + +stories.add('with formatted values', () => ( + + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +)) diff --git a/stories/charts/sankey.stories.js b/stories/charts/sankey.stories.js index 1859259bd..9d0484ff4 100644 --- a/stories/charts/sankey.stories.js +++ b/stories/charts/sankey.stories.js @@ -51,3 +51,12 @@ stories.add('custom tooltip', () => ( )} /> )) + +stories.add('with formatted values', () => ( + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +)) diff --git a/stories/charts/stream.stories.js b/stories/charts/stream.stories.js index 5e34ab20c..a478f04d3 100644 --- a/stories/charts/stream.stories.js +++ b/stories/charts/stream.stories.js @@ -45,3 +45,13 @@ stories.add('regular stacked chart', () => ( )) stories.add('custom curve', () => ) + +stories.add('with formatted values', () => ( + + `${Number(value).toLocaleString('ru-RU', { + minimumFractionDigits: 2, + })} ₽`} + /> +))