react-native-svg-charts
Version:
Customizable charts (Line, Bar, Area, Pie, Circle, Progress) for React Native
242 lines (221 loc) • 6.22 kB
JavaScript
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import * as array from 'd3-array';
import * as scale from 'd3-scale';
import * as shape from 'd3-shape';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import { View } from 'react-native';
import Svg from 'react-native-svg';
import Path from '../animated-path';
class BarChart extends PureComponent {
constructor(...args) {
super(...args);
_defineProperty(this, "state", {
width: 0,
height: 0
});
}
_onLayout(event) {
const {
nativeEvent: {
layout: {
height,
width
}
}
} = event;
this.setState({
height,
width
});
}
calcXScale(domain) {
const {
horizontal,
contentInset: {
left = 0,
right = 0
},
spacingInner,
spacingOuter,
clamp
} = this.props;
const {
width
} = this.state;
if (horizontal) {
return scale.scaleLinear().domain(domain).range([left, width - right]).clamp(clamp);
}
return scale.scaleBand().domain(domain).range([left, width - right]).paddingInner([spacingInner]).paddingOuter([spacingOuter]);
}
calcYScale(domain) {
const {
horizontal,
contentInset: {
top = 0,
bottom = 0
},
spacingInner,
spacingOuter,
clamp
} = this.props;
const {
height
} = this.state;
if (horizontal) {
return scale.scaleBand().domain(domain).range([top, height - bottom]).paddingInner([spacingInner]).paddingOuter([spacingOuter]);
}
return scale.scaleLinear().domain(domain).range([height - bottom, top]).clamp(clamp);
}
calcAreas(x, y) {
const {
horizontal,
data,
yAccessor
} = this.props;
const values = data.map(item => yAccessor({
item
}));
if (horizontal) {
return data.map((bar, index) => ({
bar,
path: shape.area().y((value, _index) => _index === 0 ? y(index) : y(index) + y.bandwidth()).x0(x(0)).x1(value => x(value)).defined(value => typeof value === 'number')([values[index], values[index]])
}));
}
return data.map((bar, index) => ({
bar,
path: shape.area().y0(y(0)).y1(value => y(value)).x((value, _index) => _index === 0 ? x(index) : x(index) + x.bandwidth()).defined(value => typeof value === 'number')([values[index], values[index]])
}));
}
calcExtent() {
const {
data,
gridMin,
gridMax,
yAccessor
} = this.props;
const values = data.map(obj => yAccessor({
item: obj
}));
const extent = array.extent([...values, gridMax, gridMin]);
const {
yMin = extent[0],
yMax = extent[1]
} = this.props;
return [yMin, yMax];
}
calcIndexes() {
const {
data
} = this.props;
return data.map((_, index) => index);
}
render() {
const {
data,
animate,
animationDuration,
style,
numberOfTicks,
svg,
horizontal,
children
} = this.props;
const {
height,
width
} = this.state;
if (data.length === 0) {
return /*#__PURE__*/React.createElement(View, {
style: style
});
}
const extent = this.calcExtent();
const indexes = this.calcIndexes();
const ticks = array.ticks(extent[0], extent[1], numberOfTicks);
const xDomain = horizontal ? extent : indexes;
const yDomain = horizontal ? indexes : extent;
const x = this.calcXScale(xDomain);
const y = this.calcYScale(yDomain);
const bandwidth = horizontal ? y.bandwidth() : x.bandwidth();
const areas = this.calcAreas(x, y).filter(area => area.bar !== null && area.bar !== undefined && area.path !== null);
const extraProps = {
x,
y,
width,
height,
bandwidth,
ticks,
data
};
return /*#__PURE__*/React.createElement(View, {
style: style
}, /*#__PURE__*/React.createElement(View, {
style: {
flex: 1
},
onLayout: event => this._onLayout(event)
}, height > 0 && width > 0 && /*#__PURE__*/React.createElement(Svg, {
style: {
height,
width
}
}, React.Children.map(children, child => {
if (child && child.props.belowChart) {
return React.cloneElement(child, extraProps);
}
}), areas.map((area, index) => {
const {
bar: {
svg: barSvg = {}
},
path
} = area;
return /*#__PURE__*/React.createElement(Path, _extends({
key: index
}, svg, barSvg, {
d: path,
animate: animate,
animationDuration: animationDuration
}));
}), React.Children.map(children, child => {
if (child && !child.props.belowChart) {
return React.cloneElement(child, extraProps);
}
}))));
}
}
BarChart.propTypes = {
data: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.object])).isRequired,
style: PropTypes.any,
spacingInner: PropTypes.number,
spacingOuter: PropTypes.number,
animate: PropTypes.bool,
animationDuration: PropTypes.number,
contentInset: PropTypes.shape({
top: PropTypes.number,
left: PropTypes.number,
right: PropTypes.number,
bottom: PropTypes.number
}),
numberOfTicks: PropTypes.number,
gridMin: PropTypes.number,
gridMax: PropTypes.number,
svg: PropTypes.object,
yMin: PropTypes.any,
yMax: PropTypes.any,
clamp: PropTypes.bool
};
BarChart.defaultProps = {
spacingInner: 0.05,
spacingOuter: 0.05,
contentInset: {},
numberOfTicks: 10,
svg: {},
yAccessor: ({
item
}) => item
};
export default BarChart;
//# sourceMappingURL=bar-chart.js.map