react-vis
Version:
Data visualization library based on React and d3.
376 lines (306 loc) • 14.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
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 _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; }; // Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _deepEqual = require('deep-equal');
var _deepEqual2 = _interopRequireDefault(_deepEqual);
var _d3Shape = require('d3-shape');
var d3Shape = _interopRequireWildcard(_d3Shape);
var _animation = require('../animation');
var _animation2 = _interopRequireDefault(_animation);
var _scalesUtils = require('../utils/scales-utils');
var _chartUtils = require('../utils/chart-utils');
var _animationUtils = require('../utils/animation-utils');
var _theme = require('../theme');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
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 ATTRIBUTES = ['angle', 'radius', 'innerRadius', 'color', 'opacity', 'fill', 'stroke'];
var ANIMATED_PROPS = ['angleDomain', 'angleRange', 'angle', 'radiusDomain', 'radiusRange', 'radius', 'innerRadiusDomain', 'innerRadiusRange', 'innerRadius', 'colorDomain', 'colorRange', 'color', 'opacityDomain', 'opacityRange', 'opacity', 'fillDomain', 'fillRange', 'fill', 'strokeDomain', 'strokeRange', 'stroke', 'data'];
var DEFAULT_MARGINS = {
left: 10,
right: 10,
top: 10,
bottom: 10
};
/**
* Walk through the data and assign color property to the data points if it
* doesn't exist.
* @param {Array} data Array of data.
* @returns {Array} New array of data points.
*/
function assignColorsToData(data) {
return data.map(function (d, color) {
return _extends({ color: color }, d);
});
}
var RadialChart = function (_React$Component) {
_inherits(RadialChart, _React$Component);
_createClass(RadialChart, null, [{
key: 'propTypes',
get: function get() {
return {
width: _react2.default.PropTypes.number.isRequired,
height: _react2.default.PropTypes.number.isRequired,
margin: _chartUtils.MarginPropType,
animation: _animationUtils.AnimationPropType,
onSectionMouseOver: _react2.default.PropTypes.func,
onSectionMouseOut: _react2.default.PropTypes.func,
onSectionClick: _react2.default.PropTypes.func
};
}
}]);
function RadialChart(props) {
_classCallCheck(this, RadialChart);
var _this = _possibleConstructorReturn(this, (RadialChart.__proto__ || Object.getPrototypeOf(RadialChart)).call(this, props));
var data = assignColorsToData(props.data);
var scaleProps = _this._getAllScaleProps(props, data);
var arc = _this._getArcFromProps(scaleProps);
_this.state = { scaleProps: scaleProps, data: data, arc: arc };
_this._sectionMouseOut = _this._sectionMouseOut.bind(_this);
_this._sectionMouseOver = _this._sectionMouseOver.bind(_this);
_this._sectionClick = _this._sectionClick.bind(_this);
return _this;
}
_createClass(RadialChart, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
var nextData = assignColorsToData(nextProps.data);
var scaleProps = this.state.scaleProps;
var nextscaleProps = this._getAllScaleProps(nextProps, nextData);
if (!(0, _deepEqual2.default)(nextscaleProps, scaleProps)) {
this.setState({
scaleProps: nextscaleProps,
data: nextData,
arc: this._getArcFromProps(scaleProps)
});
}
}
/**
* Triggers a callback on a section if the callback is set.
* @param {function} handler Callback function.
* @param {Object} d Data point of the arc.
* @param {Object} event Event.
* @private
*/
}, {
key: '_triggerSectionHandler',
value: function _triggerSectionHandler(handler, d, event) {
if (handler) {
var arc = this.state.arc;
var _arc$centroid = arc.centroid(d);
var _arc$centroid2 = _slicedToArray(_arc$centroid, 2);
var x = _arc$centroid2[0];
var y = _arc$centroid2[1];
handler(d.data, { event: event, x: x, y: y });
}
}
/**
* `mouseover` handler for the section.
* @param {Object} d Data point.
* @param {Object} event Event.
* @private
*/
}, {
key: '_sectionMouseOver',
value: function _sectionMouseOver(d, event) {
var onSectionMouseOver = this.props.onSectionMouseOver;
this._triggerSectionHandler(onSectionMouseOver, d, event);
}
/**
* `mouseout` handler for the section.
* @param {Object} d Data point.
* @param {Object} event Event.
* @private
*/
}, {
key: '_sectionMouseOut',
value: function _sectionMouseOut(d, event) {
var onSectionMouseOut = this.props.onSectionMouseOut;
this._triggerSectionHandler(onSectionMouseOut, d, event);
}
/**
* `click` handler for the section.
* @param {Object} d Data point.
* @param {Object} event Event.
* @private
*/
}, {
key: '_sectionClick',
value: function _sectionClick(d, event) {
var onSectionClick = this.props.onSectionClick;
this._triggerSectionHandler(onSectionClick, d, event);
}
/**
* Get the list of scale-related settings that should be applied by default.
* @param {Object} props Object of props.
* @returns {Object} Defaults.
* @private
*/
}, {
key: '_getDefaultScaleProps',
value: function _getDefaultScaleProps(props) {
var _getInnerDimensions = (0, _chartUtils.getInnerDimensions)(props, DEFAULT_MARGINS);
var innerWidth = _getInnerDimensions.innerWidth;
var innerHeight = _getInnerDimensions.innerHeight;
var radius = Math.min(innerWidth / 2, innerHeight / 2);
return {
radiusRange: [0, radius],
_radiusValue: radius,
opacityRange: _theme.OPACITY_RANGE,
_opacityValue: 1,
colorRange: _theme.DISCRETE_COLOR_RANGE,
colorType: 'category'
};
}
/**
* Get the map of scales from the props.
* @param {Object} props Props.
* @param {Array} data Array of all data.
* @returns {Object} Map of scales.
* @private
*/
}, {
key: '_getAllScaleProps',
value: function _getAllScaleProps(props, data) {
var defaultScaleProps = this._getDefaultScaleProps(props);
var userScaleProps = (0, _scalesUtils.extractScalePropsFromProps)(props, ATTRIBUTES);
var missingScaleProps = (0, _scalesUtils.getMissingScaleProps)(_extends({}, defaultScaleProps, userScaleProps), data, ATTRIBUTES);
return _extends({}, defaultScaleProps, userScaleProps, missingScaleProps, {
_allData: [],
_adjustBy: [],
_adjustWhat: []
});
}
/**
* Get attribute functor.
* @param {string} attr Attribute name.
* @returns {*} Functor.
* @protected
*/
}, {
key: '_getAttributeFunctor',
value: function _getAttributeFunctor(attr) {
return (0, _scalesUtils.getAttributeFunctor)(this.state.scaleProps, attr);
}
/**
* Extract the arc function from the props.
* @param {Object} scaleProps Scale props.
* @returns {function} Arc function, null if radius is missing.
* @private
*/
}, {
key: '_getArcFromProps',
value: function _getArcFromProps(scaleProps) {
var radiusFunctor = (0, _scalesUtils.getAttributeFunctor)(scaleProps, 'radius');
var innerRadiusFunctor = (0, _scalesUtils.getAttributeFunctor)(scaleProps, 'innerRadius');
if (!radiusFunctor) {
return null;
}
return d3Shape.arc().outerRadius(radiusFunctor).innerRadius(innerRadiusFunctor);
}
}, {
key: 'render',
value: function render() {
var _this2 = this;
var _props = this.props;
var width = _props.width;
var height = _props.height;
var animation = _props.animation;
if (animation) {
return _react2.default.createElement(
_animation2.default,
_extends({}, this.props, { animatedProps: ANIMATED_PROPS }),
_react2.default.createElement(RadialChart, _extends({}, this.props, { animation: null }))
);
}
var _state = this.state;
var data = _state.data;
var arc = _state.arc;
if (!data || !arc) {
return null;
}
var _getInnerDimensions2 = (0, _chartUtils.getInnerDimensions)(this.props, DEFAULT_MARGINS);
var innerWidth = _getInnerDimensions2.innerWidth;
var innerHeight = _getInnerDimensions2.innerHeight;
var opacityFunctor = this._getAttributeFunctor('opacity');
var fillFunctor = this._getAttributeFunctor('fill') || this._getAttributeFunctor('color');
var strokeFunctor = this._getAttributeFunctor('stroke') || this._getAttributeFunctor('color');
var pie = d3Shape.pie().sort(null).value(function (d) {
return d.angle;
});
var pieData = pie(data);
return _react2.default.createElement(
'div',
{
style: {
width: width + 'px',
height: height + 'px'
},
className: 'rv-radial-chart' },
_react2.default.createElement(
'svg',
{
width: width,
height: height,
className: 'rv-radial-chart__svg' },
_react2.default.createElement(
'g',
{
className: 'rv-radial-chart__series--pie',
transform: 'translate(' + innerWidth / 2 + ',' + innerHeight / 2 + ')',
ref: 'container' },
data.map(function (d, i) {
return _react2.default.createElement('path', {
d: arc(pieData[i]),
style: {
opacity: opacityFunctor && opacityFunctor(d),
stroke: strokeFunctor && strokeFunctor(d),
fill: fillFunctor && fillFunctor(d)
},
onMouseOver: function onMouseOver(e) {
return _this2._sectionMouseOver(pieData[i], e);
},
onMouseOut: function onMouseOut(e) {
return _this2._sectionMouseOut(pieData[i], e);
},
onClick: function onClick(e) {
return _this2._sectionClick(pieData[i], e);
},
key: i
});
})
)
)
);
}
}]);
return RadialChart;
}(_react2.default.Component);
RadialChart.displayName = 'RadialChart';
exports.default = RadialChart;