UNPKG

react-native-svg-charts

Version:

Customizable charts (Line, Bar, Area, Pie, Circle, Progress) for React Native

159 lines (138 loc) 5.16 kB
import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import { Text, View } from 'react-native' import * as d3Scale from 'd3-scale' import * as array from 'd3-array' import Svg, { G, Text as SVGText } from 'react-native-svg' class XAxis extends PureComponent { state = { width: 0, height: 0, } _onLayout(event) { const { nativeEvent: { layout: { width, height }, }, } = event if (width !== this.state.width) { this.setState({ width, height }) } } _getX(domain) { const { scale, spacingInner, spacingOuter, contentInset: { left = 0, right = 0 }, } = this.props const { width } = this.state const x = scale() .domain(domain) .range([left, width - right]) if (scale === d3Scale.scaleBand) { x.paddingInner([spacingInner]).paddingOuter([spacingOuter]) //add half a bar to center label return (value) => x(value) + x.bandwidth() / 2 } return x } render() { const { style, scale, data, xAccessor, formatLabel, numberOfTicks, svg, children, min, max } = this.props const { height, width } = this.state if (data.length === 0) { return <View style={style} /> } const values = data.map((item, index) => xAccessor({ item, index })) const extent = array.extent(values) const domain = scale === d3Scale.scaleBand ? values : [min || extent[0], max || extent[1]] const x = this._getX(domain) const ticks = numberOfTicks ? x.ticks(numberOfTicks) : values const extraProps = { x, ticks, width, height, formatLabel, } return ( <View style={style}> <View style={{ flexGrow: 1 }} onLayout={(event) => this._onLayout(event)}> {/*invisible text to allow for parent resizing*/} <Text style={{ opacity: 0, fontSize: svg.fontSize, fontFamily: svg.fontFamily, fontWeight: svg.fontWeight, }} > {formatLabel(ticks[0], 0)} </Text> {height > 0 && width > 0 && ( <Svg style={{ position: 'absolute', top: 0, left: 0, height, width, }} > <G> {React.Children.map(children, (child) => { return React.cloneElement(child, extraProps) })} {// don't render labels if width isn't measured yet, // causes rendering issues width > 0 && ticks.map((value, index) => { const { svg: valueSvg = {} } = data[index] || {} return ( <SVGText textAnchor={'middle'} originX={x(value)} alignmentBaseline={'hanging'} {...svg} {...valueSvg} key={index} x={x(value)} > {formatLabel(value, index)} </SVGText> ) })} </G> </Svg> )} </View> </View> ) } } XAxis.propTypes = { data: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.object])).isRequired, spacingInner: PropTypes.number, spacingOuter: PropTypes.number, formatLabel: PropTypes.func, contentInset: PropTypes.shape({ left: PropTypes.number, right: PropTypes.number, }), scale: PropTypes.func, numberOfTicks: PropTypes.number, xAccessor: PropTypes.func, svg: PropTypes.object, min: PropTypes.any, max: PropTypes.any, } XAxis.defaultProps = { spacingInner: 0.05, spacingOuter: 0.05, contentInset: {}, svg: {}, xAccessor: ({ index }) => index, scale: d3Scale.scaleLinear, formatLabel: (value) => value, } export default XAxis