UNPKG

@patternfly/react-charts

Version:

This library provides a set of React chart components for use with the PatternFly reference implementation.

215 lines • 14.1 kB
import * as React from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { VictoryChart } from 'victory-chart'; import { getComparativeMeasureErrorWidth, getComparativeMeasureWidth, getComparativeMeasureWarningWidth, getPrimaryDotMeasureSize, getPrimarySegmentedMeasureWidth, getQualitativeRangeBarWidth } from './utils/chart-bullet-size'; import { getBulletDomain } from './utils/chart-bullet-domain'; import { getBulletThemeWithLegendColorScale } from './utils/chart-bullet-theme'; import { ChartAxis } from '../ChartAxis'; import { ChartBulletComparativeErrorMeasure } from './ChartBulletComparativeErrorMeasure'; import { ChartBulletComparativeMeasure } from './ChartBulletComparativeMeasure'; import { ChartBulletComparativeWarningMeasure } from './ChartBulletComparativeWarningMeasure'; import { ChartBulletGroupTitle } from './ChartBulletGroupTitle'; import { ChartBulletPrimaryDotMeasure } from './ChartBulletPrimaryDotMeasure'; import { ChartBulletPrimarySegmentedMeasure } from './ChartBulletPrimarySegmentedMeasure'; import { ChartBulletQualitativeRange } from './ChartBulletQualitativeRange'; import { ChartBulletTitle } from './ChartBulletTitle'; import { ChartContainer } from '../ChartContainer'; import { ChartLegend, ChartLegendPosition } from '../ChartLegend'; import { ChartBulletStyles } from '../ChartTheme'; import { ChartTooltip } from '../ChartTooltip'; import { getComputedLegend, getPaddingForSide } from '../ChartUtils'; export const ChartBullet = ({ allowTooltip = true, ariaDesc, ariaTitle, axisComponent = React.createElement(ChartAxis, null), comparativeErrorMeasureComponent = React.createElement(ChartBulletComparativeErrorMeasure, null), comparativeErrorMeasureData, comparativeErrorMeasureDataY, comparativeErrorMeasureLegendData, comparativeWarningMeasureComponent = React.createElement(ChartBulletComparativeWarningMeasure, null), comparativeWarningMeasureData, comparativeWarningMeasureDataY, comparativeWarningMeasureLegendData, comparativeZeroMeasureComponent = React.createElement(ChartBulletComparativeMeasure, null), constrainToVisibleArea = false, groupTitleComponent = React.createElement(ChartBulletGroupTitle, null), groupSubTitle, groupTitle, horizontal = true, invert = false, labels, legendAllowWrap = false, legendComponent = React.createElement(ChartLegend, null), legendItemsPerRow, legendPosition = 'bottom', maxDomain, minDomain, name, padding, primaryDotMeasureComponent = React.createElement(ChartBulletPrimaryDotMeasure, null), primaryDotMeasureData, primaryDotMeasureDataY, primaryDotMeasureLegendData, primarySegmentedMeasureComponent = React.createElement(ChartBulletPrimarySegmentedMeasure, null), primarySegmentedMeasureData, primarySegmentedMeasureDataY, primarySegmentedMeasureLegendData, qualitativeRangeComponent = React.createElement(ChartBulletQualitativeRange, null), qualitativeRangeData, qualitativeRangeDataY, qualitativeRangeDataY0, qualitativeRangeLegendData, standalone = true, subTitle, themeColor, // eslint-disable-next-line @typescript-eslint/no-unused-vars themeVariant, title, titleComponent = React.createElement(ChartBulletTitle, null), titlePosition, // destructure last theme = getBulletThemeWithLegendColorScale({ comparativeErrorMeasureData, comparativeErrorMeasureLegendData, comparativeWarningMeasureData, comparativeWarningMeasureLegendData, invert, primaryDotMeasureData, primaryDotMeasureLegendData, primarySegmentedMeasureData, primarySegmentedMeasureLegendData, qualitativeRangeData, qualitativeRangeLegendData, themeColor }), domain = getBulletDomain({ comparativeErrorMeasureComponent, comparativeErrorMeasureData, comparativeWarningMeasureComponent, comparativeWarningMeasureData, maxDomain, minDomain, primaryDotMeasureComponent, primaryDotMeasureData, primarySegmentedMeasureComponent, primarySegmentedMeasureData, qualitativeRangeComponent, qualitativeRangeData }), legendOrientation = theme.legend.orientation, height = horizontal ? theme.chart.height : theme.chart.width, width = horizontal ? theme.chart.width : theme.chart.height, bulletSize = theme.chart.height }) => { // Note that we're using a fixed bullet height width to align components. const chartSize = { height: horizontal ? bulletSize : height, width: horizontal ? width : bulletSize }; const defaultPadding = { bottom: getPaddingForSide('bottom', padding, theme.chart.padding), left: getPaddingForSide('left', padding, theme.chart.padding), right: getPaddingForSide('right', padding, theme.chart.padding), top: getPaddingForSide('top', padding, theme.chart.padding) }; // Bullet group title const bulletGroupTitle = React.cloneElement(groupTitleComponent, Object.assign(Object.assign(Object.assign({ height }, (name && { name: `${name}-${groupTitleComponent.type.displayName}` })), { standalone: false, subTitle: groupSubTitle, title: groupTitle, width }), groupTitleComponent.props)); // Bullet title const bulletTitle = React.cloneElement(titleComponent, Object.assign(Object.assign(Object.assign({ height, horizontal, legendPosition }, (name && { name: `${name}-${titleComponent.type.displayName}` })), { padding, standalone: false, subTitle, theme, title, titlePosition, width }), titleComponent.props)); // Comparative error measure const comparativeErrorMeasure = React.cloneElement(comparativeErrorMeasureComponent, Object.assign({ allowTooltip, barWidth: getComparativeMeasureErrorWidth({ height: chartSize.height, horizontal, width: chartSize.width }), constrainToVisibleArea, data: comparativeErrorMeasureData, domain, height: chartSize.height, horizontal, labelComponent: allowTooltip ? React.createElement(ChartTooltip, { height: height, theme: theme, width: width }) : undefined, labels, padding, standalone: false, width: chartSize.width, y: comparativeErrorMeasureDataY }, comparativeErrorMeasureComponent.props)); // Comparative warning measure const comparativeWarningMeasure = React.cloneElement(comparativeWarningMeasureComponent, Object.assign({ allowTooltip, barWidth: getComparativeMeasureWarningWidth({ height: chartSize.height, horizontal, width: chartSize.width }), constrainToVisibleArea, data: comparativeWarningMeasureData, domain, height: chartSize.height, horizontal, labelComponent: allowTooltip ? React.createElement(ChartTooltip, { height: height, theme: theme, width: width }) : undefined, labels, padding, standalone: false, width: chartSize.width, y: comparativeWarningMeasureDataY }, comparativeWarningMeasureComponent.props)); // Comparative zero measure const comparativeZeroMeasure = React.cloneElement(comparativeZeroMeasureComponent, Object.assign({ barWidth: getComparativeMeasureWidth({ height: chartSize.height, horizontal, width: chartSize.width }), data: [{ y: 0 }], domain, height: chartSize.height, horizontal, padding, standalone: false, width: chartSize.width }, comparativeZeroMeasureComponent.props)); // Legend const legend = React.cloneElement(legendComponent, Object.assign(Object.assign(Object.assign({ data: [ ...(primaryDotMeasureLegendData ? primaryDotMeasureLegendData : []), ...(primarySegmentedMeasureLegendData ? primarySegmentedMeasureLegendData : []), ...(comparativeWarningMeasureLegendData ? comparativeWarningMeasureLegendData : []), ...(comparativeErrorMeasureLegendData ? comparativeErrorMeasureLegendData : []), ...(qualitativeRangeLegendData ? qualitativeRangeLegendData : []) ] }, (name && { name: `${name}-${legendComponent.type.displayName}` })), { itemsPerRow: legendItemsPerRow, orientation: legendOrientation, position: legendPosition, theme }), legendComponent.props)); // Primary dot measure const primaryDotMeasure = React.cloneElement(primaryDotMeasureComponent, Object.assign({ allowTooltip, constrainToVisibleArea, data: primaryDotMeasureData, domain, height: chartSize.height, horizontal, invert, labelComponent: allowTooltip ? React.createElement(ChartTooltip, { height: height, theme: theme, width: width }) : undefined, labels, padding, size: getPrimaryDotMeasureSize({ height: chartSize.height, horizontal, width: chartSize.width }), standalone: false, themeColor, width: chartSize.width, y: primaryDotMeasureDataY }, primaryDotMeasureComponent.props)); // Primary segmented measure const primarySegmentedMeasure = React.cloneElement(primarySegmentedMeasureComponent, Object.assign({ allowTooltip, constrainToVisibleArea, barWidth: getPrimarySegmentedMeasureWidth({ height: chartSize.height, horizontal, width: chartSize.width }), data: primarySegmentedMeasureData, domain, height: chartSize.height, horizontal, invert, labelComponent: allowTooltip ? React.createElement(ChartTooltip, { height: height, theme: theme, width: width }) : undefined, labels, padding, standalone: false, themeColor, width: chartSize.width, y: primarySegmentedMeasureDataY }, primarySegmentedMeasureComponent.props)); // Qualitative range const qualitativeRange = React.cloneElement(qualitativeRangeComponent, Object.assign({ allowTooltip, constrainToVisibleArea, barWidth: getQualitativeRangeBarWidth({ height: chartSize.height, horizontal, width: chartSize.width }), data: qualitativeRangeData, domain, height: chartSize.height, horizontal, invert, labelComponent: allowTooltip ? React.createElement(ChartTooltip, { height: height, theme: theme, width: width }) : undefined, labels, padding, standalone: false, width: chartSize.width, y: qualitativeRangeDataY, y0: qualitativeRangeDataY0 }, qualitativeRangeComponent.props)); // Returns tick values -- Victory doesn't include min/max domain const getTickValues = (minVal, maxVal) => { const tickValues = [minVal, maxVal]; let range = 0; if (minVal < 0 && maxVal < 0) { range = Math.abs(minVal - maxVal); } else if (minVal < 0) { range = Math.abs(minVal) + maxVal; } else { range = maxVal - minVal; } const tickInterval = range / (ChartBulletStyles.axisTickCount - 1); for (let i = minVal; i < maxVal;) { i += tickInterval; tickValues.push(Math.ceil(i)); } return tickValues; }; // Returns a computed legend const getLegend = () => { if (!legend.props.data) { return null; } let dx = 0; let dy = 0; // Adjust for padding if (legendPosition === ChartLegendPosition.bottom) { if (horizontal) { dy = defaultPadding.top * 0.5 + (defaultPadding.bottom * 0.5 - defaultPadding.bottom) - 25; } else if (title) { dy = -defaultPadding.bottom + 60; } else { dy = -defaultPadding.bottom; } } else if (legendPosition === ChartLegendPosition.bottomLeft) { if (horizontal) { dy = defaultPadding.top * 0.5 + (defaultPadding.bottom * 0.5 - defaultPadding.bottom) - 25; } else if (title) { dy = -defaultPadding.bottom + 60; } else { dy = -defaultPadding.bottom; } dx = -10; } return getComputedLegend({ allowWrap: legendAllowWrap, chartType: 'bullet', dx, dy, height: chartSize.height, legendComponent: legend, padding: defaultPadding, position: legendPosition, theme, width: chartSize.width }); }; // Returns comparative zero measure const getComparativeZeroMeasure = () => { const _domain = domain; let low = 0; if (Array.isArray(_domain)) { low = _domain[0]; } else if (_domain.y && Array.isArray(_domain.y)) { low = _domain.y[0]; } let high = 0; if (Array.isArray(_domain)) { high = _domain[_domain.length - 1]; } else if (_domain.y && Array.isArray(_domain.y)) { high = _domain.y[_domain.y.length - 1]; } if (low < 0 && high > 0) { return comparativeZeroMeasure; } return null; }; // Axis component for custom tick values const axis = React.cloneElement(axisComponent, Object.assign(Object.assign(Object.assign({ dependentAxis: horizontal ? false : true, domain: !horizontal ? domain : { x: domain.y, y: domain.x }, height: chartSize.height }, (name && { name: `${name}-${axisComponent.type.displayName}` })), { // Adjust for padding offsetX: !horizontal ? defaultPadding.left * 0.5 + (defaultPadding.right * 0.5 - (defaultPadding.right - 55)) : 0, offsetY: horizontal ? 80 - defaultPadding.top * 0.5 + (defaultPadding.bottom * 0.5 - 25) : 0, padding, standalone: false, tickCount: ChartBulletStyles.axisTickCount, tickValues: getTickValues(domain.y[0], domain.y[1]), width: chartSize.width }), axisComponent.props)); const bulletChart = (React.createElement(React.Fragment, null, axis, bulletGroupTitle, bulletTitle, qualitativeRange, primarySegmentedMeasure, primaryDotMeasure, comparativeErrorMeasure, comparativeWarningMeasure, getComparativeZeroMeasure(), getLegend())); return standalone ? (React.createElement(ChartContainer, { desc: ariaDesc, height: height, title: ariaTitle, theme: theme, width: width }, bulletChart)) : (React.createElement(React.Fragment, null, bulletChart)); }; ChartBullet.displayName = 'ChartBullet'; hoistNonReactStatics(ChartBullet, VictoryChart); //# sourceMappingURL=ChartBullet.js.map