recharts
Version:
React charts
383 lines (309 loc) • 13.5 kB
JavaScript
var _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; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _class, _temp2; /**
* @fileOverview Radar Bar Chart
*/
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _d3Scale = require('d3-scale');
var _d3Scale2 = _interopRequireDefault(_d3Scale);
var _Surface = require('../container/Surface');
var _Surface2 = _interopRequireDefault(_Surface);
var _RadialBar = require('../polar/RadialBar');
var _RadialBar2 = _interopRequireDefault(_RadialBar);
var _LodashUtils = require('../util/LodashUtils');
var _LodashUtils2 = _interopRequireDefault(_LodashUtils);
var _Legend = require('../component/Legend');
var _Legend2 = _interopRequireDefault(_Legend);
var _Tooltip = require('../component/Tooltip');
var _Tooltip2 = _interopRequireDefault(_Tooltip);
var _ReactUtils = require('../util/ReactUtils');
var _ReactUtils2 = _interopRequireDefault(_ReactUtils);
var _PolarUtils = require('../util/PolarUtils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var RadialBarChart = (_temp2 = _class = function (_Component) {
_inherits(RadialBarChart, _Component);
function RadialBarChart() {
var _Object$getPrototypeO;
var _temp, _this, _ret;
_classCallCheck(this, RadialBarChart);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(RadialBarChart)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.state = {
activeTooltipLabel: '',
activeTooltipPosition: 'left-bottom',
activeTooltipCoord: { x: 0, y: 0 },
isTooltipActive: false
}, _temp), _possibleConstructorReturn(_this, _ret);
}
_createClass(RadialBarChart, [{
key: 'getComposedData',
/**
* Compose the data of each group
* @param {Array} barPosition The offset and size of each bar
* @param {Object} radiusScale The scale function of radius of bars
* @param {Object} center The coordinate of center
* @param {String} dataKey The unique key of a group
* @return {Array} Composed data
*/
value: function getComposedData(barPosition, radiusScale, center, dataKey) {
var data = this.props.data;
var pos = barPosition[dataKey];
return data.map(function (entry, index) {
var value = entry[dataKey];
var radius = radiusScale(index);
return _extends({}, entry, center, {
value: value,
innerRadius: radius - pos.offset,
outerRadius: radius - pos.offset + pos.radius
});
});
}
/**
* Calculate the size of all groups
* @param {Array} items All the instance of RadialBar
* @return {Object} The size of all groups
*/
}, {
key: 'getRadiusList',
value: function getRadiusList(items) {
var barSize = this.props.barSize;
return items.map(function (child) {
return _extends({}, child.props, {
barSize: child.props.barSize || barSize
});
});
}
/**
* Calculate the scale function of radius
* @param {Number} innerRadius The outer radius
* @param {Number} outerRadius The inner radius
* @return {Object} A scale function
*/
}, {
key: 'getRadiusScale',
value: function getRadiusScale(innerRadius, outerRadius) {
var data = this.props.data;
var bandCount = Math.max(data.length, 1);
var range = [outerRadius, innerRadius];
var scale = _d3Scale2.default.band().domain(_LodashUtils2.default.range(0, bandCount)).range(range);
return scale;
}
/**
* Calculate the size of each bar and the gap between two bars
* @param {Number} bandRadius The radius of each category
* @param {Array} radiusList The radius of all groups
* @return {Number} The size of each bar and the gap between two bars
*/
}, {
key: 'getBarPosition',
value: function getBarPosition(bandRadius, radiusList) {
var _props = this.props;
var barGap = _props.barGap;
var barCategoryGap = _props.barCategoryGap;
var len = radiusList.length;
var result = undefined;
// whether or not is barSize setted by user
if (len && radiusList[0].barSize === +radiusList[0].barSize) {
(function () {
var sum = radiusList.reduce(function (res, entry) {
return res + entry.barSize;
}, 0);
sum += (len - 1) * barGap;
var offset = -sum / 2 >> 0;
var prev = { offset: offset - barGap, radius: 0 };
result = radiusList.reduce(function (res, entry) {
res[entry.dataKey] = {
offset: prev.offset + prev.radius + barGap,
radius: entry.barSize
};
prev = res[entry.dataKey];
return res;
}, {});
})();
} else {
(function () {
var offset = _LodashUtils2.default.getPercentValue(barCategoryGap, bandRadius);
var radius = (bandRadius - 2 * offset - (len - 1) * barGap) / len >> 0;
offset = -Math.max((radius * len + (len - 1) * barGap) / 2 >> 0, 0);
result = radiusList.reduce(function (res, entry, i) {
res[entry.dataKey] = {
offset: offset + (radius + barGap) * i,
radius: radius
};
return res;
}, {});
})();
}
return result;
}
}, {
key: 'handleMouseEnter',
value: function handleMouseEnter(el, e) {
var _this2 = this;
this.setState({
isTooltipActive: true
}, function () {
if (_this2.props.onMouseEnter) {
_this2.props.onMouseEnter(el, e);
}
});
}
}, {
key: 'handleMouseLeave',
value: function handleMouseLeave(e) {
var _this3 = this;
this.setState({
isTooltipActive: false
}, function () {
if (_this3.props.onMouseEnter) {
_this3.props.onMouseLeave(e);
}
});
}
/**
* Draw legend
* @param {ReactElement} legendItem The instance of Legend
* @return {ReactElement} The instance of Legend
*/
}, {
key: 'renderLegend',
value: function renderLegend() {
var children = this.props.children;
var legendItem = _ReactUtils2.default.findChildByType(children, _Legend2.default);
if (!legendItem) {
return null;
}
var _props2 = this.props;
var data = _props2.data;
var width = _props2.width;
var height = _props2.height;
var legendData = data.map(function (entry) {
return {
type: 'square',
color: entry.fill || '#000',
value: entry.name
};
});
return _react2.default.cloneElement(legendItem, _extends({}, _Legend2.default.getWithHeight(legendItem, width, height), {
payload: legendData
}));
}
}, {
key: 'renderTooltip',
value: function renderTooltip() {
var children = this.props.children;
var tooltipItem = _ReactUtils2.default.findChildByType(children, _Tooltip2.default);
if (!tooltipItem) {
return;
}
}
/**
* Draw the main part of bar chart
* @param {Array} items All the instance of RadialBar
* @param {Object} radiusScale The scale function of radius of bars
* @param {Object} center The coordinate of center
* @return {ReactComponent} All the instances of RadialBar
*/
}, {
key: 'renderItems',
value: function renderItems(items, radiusScale, center) {
var _this4 = this;
if (!items || !items.length) {
return null;
}
var radiusList = this.getRadiusList(items);
var bandRadius = radiusScale.bandwidth();
var barPosition = this.getBarPosition(bandRadius, radiusList);
return items.map(function (child, i) {
var dataKey = child.props.dataKey;
return _react2.default.cloneElement(child, _extends({}, center, {
key: 'radial-bar-' + i,
onMouseLeave: _this4.handleMouseLeave.bind(_this4),
onMouseEnter: _this4.handleMouseEnter.bind(_this4, dataKey),
data: _this4.getComposedData(barPosition, radiusScale, center, dataKey)
}));
}, this);
}
}, {
key: 'render',
value: function render() {
if (!_ReactUtils2.default.validateWidthHeight(this)) {
return null;
}
var _props3 = this.props;
var style = _props3.style;
var children = _props3.children;
var className = _props3.className;
var width = _props3.width;
var height = _props3.height;
var margin = _props3.margin;
var items = _ReactUtils2.default.findAllByType(children, _RadialBar2.default);
var cx = _LodashUtils2.default.getPercentValue(this.props.cx, width, width / 2);
var cy = _LodashUtils2.default.getPercentValue(this.props.cy, height, height / 2);
var maxRadius = (0, _PolarUtils.getMaxRadius)(width, height, cx, cy, margin);
var innerRadius = _LodashUtils2.default.getPercentValue(this.props.innerRadius, maxRadius, 0);
var outerRadius = _LodashUtils2.default.getPercentValue(this.props.outerRadius, maxRadius, maxRadius * 0.8);
var radiusScale = this.getRadiusScale(innerRadius, outerRadius);
return _react2.default.createElement(
'div',
{ className: (0, _classnames2.default)('recharts-wrapper', className),
style: _extends({ cursor: 'default' }, style, { position: 'relative' })
},
_react2.default.createElement(
_Surface2.default,
{ width: width, height: height },
this.renderItems(items, radiusScale, { cx: cx, cy: cy })
),
this.renderLegend(),
this.renderTooltip(items)
);
}
}]);
return RadialBarChart;
}(_react.Component), _class.displayName = 'RadialBarChart', _class.propTypes = {
width: _react.PropTypes.number,
height: _react.PropTypes.number,
margin: _react.PropTypes.shape({
top: _react.PropTypes.number,
right: _react.PropTypes.number,
bottom: _react.PropTypes.number,
left: _react.PropTypes.number
}),
cy: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
cx: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
data: _react.PropTypes.array,
innerRadius: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
outerRadius: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
// The offset radius between two categorys
barCategoryGap: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
// The gap radius of two radial bar in one category
barGap: _react.PropTypes.number,
// The radius of each radial bar
barSize: _react.PropTypes.number,
title: _react.PropTypes.string,
style: _react.PropTypes.object,
onMouseEnter: _react.PropTypes.func,
onMouseLeave: _react.PropTypes.func,
onClick: _react.PropTypes.func,
children: _react.PropTypes.oneOfType([_react.PropTypes.arrayOf(_react.PropTypes.node), _react.PropTypes.node]),
className: _react.PropTypes.string
}, _class.defaultProps = {
innerRadius: '30%',
outerRadius: '100%',
barGap: 2,
barCategoryGap: '10%',
style: {},
margin: { top: 0, right: 0, bottom: 0, left: 0 }
}, _temp2);
exports.default = RadialBarChart;
;