UNPKG

victory-chart

Version:
204 lines (184 loc) 6.46 kB
import React, { PropTypes } from "react"; import BarHelpers from "./helper-methods"; import { partialRight } from "lodash"; import { PropTypes as CustomPropTypes, Helpers, VictoryTransition, VictoryLabel, VictoryContainer, VictoryTheme, Bar, addEvents, Data, Domain } from "victory-core"; const fallbackProps = { width: 450, height: 300, padding: 50 }; const defaultData = [ {x: 1, y: 1}, {x: 2, y: 2}, {x: 3, y: 3}, {x: 4, y: 4} ]; class VictoryBar extends React.Component { static displayName = "VictoryBar"; static role = "bar"; static defaultTransitions = { onLoad: { duration: 2000, before: () => ({ y: 0, y1: 0, y0: 0 }), after: (datum) => ({ y: datum.y, y1: datum.y1, y0: datum.y0 }) }, onExit: { duration: 500, before: () => ({ y: 0, yOffset: 0 }) }, onEnter: { duration: 500, before: () => ({ y: 0, y1: 0, y0: 0 }), after: (datum) => ({ y: datum.y, y1: datum.y1, y0: datum.y0 }) } }; static propTypes = { animate: PropTypes.object, categories: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.string), PropTypes.shape({ x: PropTypes.arrayOf(PropTypes.string), y: PropTypes.arrayOf(PropTypes.string) }) ]), containerComponent: PropTypes.element, data: PropTypes.array, domainPadding: PropTypes.oneOfType([ PropTypes.shape({ x: PropTypes.oneOfType([ PropTypes.number, CustomPropTypes.domain ]), y: PropTypes.oneOfType([ PropTypes.number, CustomPropTypes.domain ]) }), PropTypes.number ]), dataComponent: PropTypes.element, domain: PropTypes.oneOfType([ CustomPropTypes.domain, PropTypes.shape({ x: CustomPropTypes.domain, y: CustomPropTypes.domain }) ]), events: PropTypes.arrayOf(PropTypes.shape({ target: PropTypes.oneOf(["data", "labels", "parent"]), eventKey: PropTypes.oneOfType([ PropTypes.array, CustomPropTypes.allOfType([CustomPropTypes.integer, CustomPropTypes.nonNegative]), PropTypes.string ]), eventHandlers: PropTypes.object })), eventKey: PropTypes.oneOfType([ PropTypes.func, CustomPropTypes.allOfType([CustomPropTypes.integer, CustomPropTypes.nonNegative]), PropTypes.string ]), groupComponent: PropTypes.element, height: CustomPropTypes.nonNegative, horizontal: PropTypes.bool, labels: PropTypes.oneOfType([ PropTypes.func, PropTypes.array ]), labelComponent: PropTypes.element, name: PropTypes.string, padding: PropTypes.oneOfType([ PropTypes.number, PropTypes.shape({ top: PropTypes.number, bottom: PropTypes.number, left: PropTypes.number, right: PropTypes.number }) ]), samples: CustomPropTypes.nonNegative, scale: PropTypes.oneOfType([ CustomPropTypes.scale, PropTypes.shape({ x: CustomPropTypes.scale, y: CustomPropTypes.scale }) ]), sharedEvents: PropTypes.shape({ events: PropTypes.array, getEventState: PropTypes.func }), standalone: PropTypes.bool, style: PropTypes.shape({ parent: PropTypes.object, data: PropTypes.object, labels: PropTypes.object }), theme: PropTypes.object, width: CustomPropTypes.nonNegative, x: PropTypes.oneOfType([ PropTypes.func, CustomPropTypes.allOfType([CustomPropTypes.integer, CustomPropTypes.nonNegative]), PropTypes.string, PropTypes.arrayOf(PropTypes.string) ]), y: PropTypes.oneOfType([ PropTypes.func, CustomPropTypes.allOfType([CustomPropTypes.integer, CustomPropTypes.nonNegative]), PropTypes.string, PropTypes.arrayOf(PropTypes.string) ]) }; static defaultProps = { data: defaultData, dataComponent: <Bar/>, labelComponent: <VictoryLabel/>, scale: "linear", standalone: true, containerComponent: <VictoryContainer/>, groupComponent: <g/>, theme: VictoryTheme.grayscale }; static getDomain = Domain.getDomainWithZero.bind(Domain); static getData = Data.getData.bind(Data); static getBaseProps = partialRight(BarHelpers.getBaseProps.bind(BarHelpers), fallbackProps); static expectedComponents = [ "dataComponent", "labelComponent", "groupComponent", "containerComponent" ]; renderContainer(props, group) { const { containerComponent } = props; const parentProps = this.getComponentProps(containerComponent, "parent", "parent"); return React.cloneElement(containerComponent, parentProps, group); } renderGroup(children, style) { return React.cloneElement( this.props.groupComponent, { role: "presentation", style}, children ); } shouldAnimate() { return !!this.props.animate; } renderData(props) { const { dataComponent, labelComponent, groupComponent } = props; const dataComponents = []; const labelComponents = []; for (let index = 0, len = this.dataKeys.length; index < len; index++) { const dataProps = this.getComponentProps(dataComponent, "data", index); dataComponents[index] = React.cloneElement(dataComponent, dataProps); const labelProps = this.getComponentProps(labelComponent, "labels", index); if (labelProps && labelProps.text !== undefined && labelProps.text !== null) { labelComponents[index] = React.cloneElement(labelComponent, labelProps); } } return labelComponents.length > 0 ? React.cloneElement(groupComponent, {}, ...dataComponents, ...labelComponents) : dataComponents; } render() { const { role } = this.constructor; const props = Helpers.modifyProps((this.props), fallbackProps, role); const { animate, style, standalone, theme } = props; if (this.shouldAnimate()) { const animationWhitelist = [ "data", "domain", "height", "padding", "style", "width" ]; return ( <VictoryTransition animate={animate} animationWhitelist={animationWhitelist}> {React.createElement(this.constructor, props)} </VictoryTransition> ); } const styleObject = theme && theme[role] && theme[role].style ? theme[role].style : {}; const baseStyles = Helpers.getStyles(style, styleObject, "auto", "100%"); const group = this.renderGroup( this.renderData(props), props, baseStyles ); return standalone ? this.renderContainer(props, group) : group; } } export default addEvents(VictoryBar);