UNPKG

@gravityforms/components

Version:

UI components for use in Gravity Forms development. Both React and vanilla js flavors.

242 lines (223 loc) 8.57 kB
import { classnames, PropTypes, React } from '@gravityforms/libraries'; import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; import Box from '../../../elements/Box'; import Checkbox from '../../../elements/Checkbox'; import DataDot from '../common/DataDot'; import CustomTooltip from '../common/Tooltip'; const { forwardRef, useState, useEffect } = React; /** * @module GravityAreaChart * @description The AreaChart component. Loaded by the Chart renderer and displayed by passing type "area". * * @since 4.4.5 * * @param {number} animationDuration The duration of the reveal animation in milliseconds. * @param {object} areaProps The props to pass to each Area (can also override the presets we use). Check Recharts docs for all available. * @param {object} cartesianGridProps The props to pass to the CartesianGrid (can also override the presets we use). Check Recharts docs for all available. * @param {object} checkboxProps The props to pass to each Checkbox. Check our docs for all available. * @param {node} children Any additional content to display below the chart. * @param {string} cursorColor The color of the cursor line in the chart that appears when the tooltip is hovered. * @param {object} customAttributes Custom attributes to apply to the chart wrapper. * @param {string|array|object} customClasses Custom classes to apply to the chart wrapper. * @param {array} data The data to display in the chart. Check Recharts docs for formats. * @param {string} gridColor The color of the grid lines and the x and y axis. * @param {number|string} height The height of the chart. * @param {object} legendProps The props to pass to the Legend (can also override the presets we use). Check Recharts docs for all available. * @param {array} options The options to display as checkboxes to toggle the visibility of each data set. * @param {boolean} showCheckboxes Whether to show the checkboxes to toggle the visibility of each data set. * @param {boolean} showLegend Whether to show the legend. * @param {object} tooltipProps The props to pass to the Tooltip (can also override the presets we use). Check Recharts docs for all available. * @param {number|string} width The width of the chart. * @param {object} xAxisProps The props to pass to the XAxis (can also override the presets we use). Check Recharts docs for all available. * @param {object} yAxisProps The props to pass to the YAxis (can also override the presets we use). Check Recharts docs for all available. * @param {object} ref The reference to the chart component. * * @return {JSX.Element|null} The AreaChart component. */ const GravityAreaChart = forwardRef( ( { animationDuration = 1000, areaProps = {}, cartesianGridProps = {}, checkboxProps = {}, children = null, cursorColor = '#9092b2', customAttributes = {}, customClasses = {}, customInterval = null, data = [], gridColor = '#ecedf8', height = 400, legendProps = {}, options = [], showCheckboxes = true, showLegend = false, tooltipProps = {}, width = '100%', xAxisProps = {}, yAxisProps = {}, }, ref ) => { const componentProps = { className: classnames( { 'gform-chart--area': true, 'gform-chart__wrapper': true, }, customClasses ), ...customAttributes, ref, }; const initialCheckboxState = options.reduce( ( acc, option ) => { acc[ option.dataKey ] = option.defaultChecked || true; // Set default visibility, default to true return acc; }, {} ); const [ checkboxState, setCheckboxState ] = useState( initialCheckboxState ); const [ animationActive, setAnimationActive ] = useState( true ); const [ interval, setInterval ] = useState( Math.floor( data.length / 10 ) ); const updateInterval = () => { const screenWidth = window.innerWidth; setInterval( Math.floor( data.length / ( screenWidth / 180 ) ) ); }; useEffect( () => { // Disable animation after the first render const timer = setTimeout( () => { setAnimationActive( false ); }, animationDuration ); return () => clearTimeout( timer ); }, [] ); useEffect( () => { if ( customInterval ) { customInterval( setInterval, data.length ); } else { updateInterval(); window.addEventListener( 'resize', updateInterval ); return () => { window.removeEventListener( 'resize', updateInterval ); }; } }, [ data.length, customInterval ] ); const handleCheckboxChange = ( dataKey ) => { setCheckboxState( ( prevState ) => ( { ...prevState, [ dataKey ]: ! prevState[ dataKey ], } ) ); }; const cartesianGridAttributes = { stroke: gridColor, strokeDasharray: '0', vertical: false, ...cartesianGridProps, }; const yAxisAttributes = { axisLine: { stroke: gridColor }, padding: { top: 10 }, tickLine: { stroke: gridColor }, ...yAxisProps, }; const xAxisAttributes = { axisLine: { stroke: gridColor }, tickLine: { stroke: gridColor }, interval, ...xAxisProps, }; const tooltipAttributes = { content: <CustomTooltip />, cursor: { stroke: cursorColor }, ...tooltipProps, }; const legendAttributes = { ...legendProps, }; return ( <div { ...componentProps }> { showCheckboxes && ( <div className="gform-chart__checkboxes"> <Box display="flex" spacing={ [ 0, 5, 0, 0 ] }> { options.map( ( option ) => { const checkboxAttributes = { externalChecked: checkboxState[ option.dataKey ], externalControl: true, labelAttributes: { label: option.label, weight: 'normal', }, onChange: () => handleCheckboxChange( option.dataKey ), spacing: [ 0, 0, 4, 3 ], ...checkboxProps, }; return ( <Checkbox key={ option.dataKey } { ...checkboxAttributes } /> ); } ) } </Box> </div> ) } <ResponsiveContainer width={ width } height={ height }> <AreaChart data={ data } margin={ { top: 0, right: 20, left: 0, bottom: 0 } }> <defs> { options.map( ( option ) => ( <linearGradient key={ option.dataKey } id={ `color${ option.dataKey }` } x1="0" y1="0" x2="0" y2="1"> <stop offset="5%" stopColor={ option.color } stopOpacity={ 0.1 } /> <stop offset="95%" stopColor={ option.color } stopOpacity={ 0 } /> </linearGradient> ) ) } </defs> <CartesianGrid { ...cartesianGridAttributes } /> <XAxis { ...xAxisAttributes } /> <YAxis { ...yAxisAttributes } /> <Tooltip { ...tooltipAttributes } /> { showLegend && <Legend { ...legendAttributes } /> } { options.map( ( option ) => { const areaAttributes = { type: 'monotone', dataKey: option.dataKey, stroke: option.color, fillOpacity: 1, fill: `url(#color${ option.dataKey })`, strokeWidth: 2, dot: false, activeDot: <DataDot stroke={ option.color } />, isAnimationActive: animationActive, animationBegin: 0, animationDuration, ...areaProps, }; return checkboxState[ option.dataKey ] ? ( <Area key={ option.dataKey } { ...areaAttributes } /> ) : null; } ) } </AreaChart> </ResponsiveContainer> { children } </div> ); } ); GravityAreaChart.propTypes = { animationDuration: PropTypes.number, areaProps: PropTypes.object, cartesianGridProps: PropTypes.object, checkboxProps: PropTypes.object, children: PropTypes.oneOfType( [ PropTypes.arrayOf( PropTypes.node ), PropTypes.node, ] ), cursorColor: PropTypes.string, customAttributes: PropTypes.object, customClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), data: PropTypes.array, gridColor: PropTypes.string, height: PropTypes.oneOfType( [ PropTypes.string, PropTypes.number ] ), legendProps: PropTypes.object, options: PropTypes.array, showCheckboxes: PropTypes.bool, showLegend: PropTypes.bool, tooltipProps: PropTypes.object, width: PropTypes.oneOfType( [ PropTypes.string, PropTypes.number ] ), xAxisProps: PropTypes.object, yAxisProps: PropTypes.object, }; GravityAreaChart.displayName = 'AreaChart'; export default GravityAreaChart;