UNPKG

@hackoregon/component-library

Version:

Official repo for Hack Oregon React component library

224 lines (209 loc) 6.01 kB
import PropTypes from "prop-types"; import React from "react"; import { groupBy } from "lodash"; import { VictoryAxis, VictoryChart, VictoryLabel, VictoryPortal, VictoryScatter, VictoryTooltip, VictoryStack, VictoryArea } from "victory"; import shortid from "shortid"; import ChartContainer from "../ChartContainer"; import SimpleLegend from "../SimpleLegend"; import civicFormat from "../utils/civicFormat"; import DataChecker from "../utils/DataChecker"; import { chartEvents, getDefaultStackedDomain, getDefaultDataSeriesLabels, getDefaultAreaStyle } from "../utils/chartHelpers"; import CivicVictoryTheme from "../VictoryTheme/VictoryThemeIndex"; const StackedAreaChart = ({ data, dataKey, dataKeyLabel, dataValue, dataValueLabel, dataSeries, dataSeriesLabel, domain, size, style, subtitle, title, xLabel, yLabel, xNumberFormatter, yNumberFormatter, legendComponent }) => { const chartDomain = domain || getDefaultStackedDomain(data, dataKey, dataValue); const dataSeriesLabels = dataSeries ? dataSeriesLabel || getDefaultDataSeriesLabels(data, dataSeries) : null; const scatterPlotStyle = style || { ...CivicVictoryTheme.civic.areaScatter.style }; const legendData = dataSeriesLabels && dataSeriesLabels.length ? dataSeriesLabels.map(series => ({ name: series.label })) : null; const lineData = dataSeries ? groupBy(data, dataSeries) : { category: data }; const areas = lineData ? Object.keys(lineData).map((category, index) => ( <VictoryArea key={shortid.generate()} data={lineData[category].map(d => ({ dataKey: d[dataKey], dataValue: d[dataValue], series: d[dataSeries] }))} x="dataKey" y="dataValue" style={getDefaultAreaStyle(index)} standalone={false} animate /> )) : null; const dots = lineData ? Object.keys(lineData).map(category => ( <VictoryScatter key={shortid.generate()} data={lineData[category].map(d => ({ dataKey: d[dataKey], dataValue: d[dataValue], series: d[dataSeries], label: `${dataKeyLabel || xLabel}: ${xNumberFormatter( d[dataKey] )} • ${dataValueLabel || yLabel}: ${yNumberFormatter( d[dataValue] )}`, size: size ? d[size.key] || size.value : 3 }))} x="dataKey" y="dataValue" standalone={false} size={d => d.size} style={scatterPlotStyle} title="Scatter Plot" events={chartEvents} labelComponent={ <VictoryTooltip x={325} y={0} orientation="bottom" pointerLength={0} cornerRadius={0} theme={CivicVictoryTheme.civic} /> } animate /> )) : null; return ( <ChartContainer title={title} subtitle={subtitle}> <DataChecker dataAccessors={{ dataKey, dataValue }} data={data}> {legendData && (legendComponent ? ( legendComponent(legendData) ) : ( <SimpleLegend className="legend" legendData={legendData} /> ))} <VictoryChart domain={chartDomain} padding={{ left: 75, right: 50, bottom: 50, top: 50 }} theme={CivicVictoryTheme.civic} > <VictoryAxis style={{ grid: { stroke: "none" } }} tickFormat={x => xNumberFormatter(x)} title="X Axis" /> <VictoryAxis dependentAxis tickFormat={y => yNumberFormatter(y)} title="Y Axis" /> <VictoryPortal> <VictoryLabel style={{ ...CivicVictoryTheme.civic.axisLabel.style }} text={yLabel} textAnchor="middle" title="Y Axis Label" verticalAnchor="end" x={75} y={45} /> </VictoryPortal> <VictoryPortal> <VictoryLabel style={{ ...CivicVictoryTheme.civic.axisLabel.style }} text={xLabel} textAnchor="end" title="X Axis Label" verticalAnchor="end" x={600} y={295} /> </VictoryPortal> <VictoryStack>{areas}</VictoryStack> <VictoryStack>{dots}</VictoryStack> </VictoryChart> </DataChecker> </ChartContainer> ); }; StackedAreaChart.propTypes = { data: PropTypes.arrayOf( PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }) ), dataKey: PropTypes.string, dataKeyLabel: PropTypes.arrayOf(PropTypes.string), dataValue: PropTypes.string, dataValueLabel: PropTypes.arrayOf(PropTypes.string), dataSeries: PropTypes.string, dataSeriesLabel: PropTypes.arrayOf( PropTypes.shape({ category: PropTypes.string, label: PropTypes.string }) ), domain: PropTypes.shape({ x: PropTypes.arrayOf(PropTypes.number), y: PropTypes.arrayOf(PropTypes.number) }), size: PropTypes.shape({ key: PropTypes.string, value: PropTypes.string }), style: PropTypes.arrayOf(PropTypes.shape({})), subtitle: PropTypes.string, title: PropTypes.string, xLabel: PropTypes.string, yLabel: PropTypes.string, xNumberFormatter: PropTypes.func, yNumberFormatter: PropTypes.func, legendComponent: PropTypes.func }; StackedAreaChart.defaultProps = { data: null, dataKey: "x", dataKeyLabel: null, dataValue: "y", dataValueLabel: null, dataSeries: null, dataSeriesLabel: null, domain: null, size: null, style: null, subtitle: null, title: null, xLabel: "X", yLabel: "Y", xNumberFormatter: civicFormat.numeric, yNumberFormatter: civicFormat.numeric, legendComponent: null }; export default StackedAreaChart;