UNPKG

@data-ui/histogram

Version:

React + d3 library for creating histograms

286 lines (240 loc) 9.91 kB
"use strict"; exports.__esModule = true; exports.default = exports.propTypes = void 0; var _propTypes = _interopRequireDefault(require("prop-types")); var _react = _interopRequireDefault(require("react")); var _group = require("@vx/group"); var _scale = require("@vx/scale"); var _shared = require("@data-ui/shared"); var _componentIsX = require("../utils/componentIsX"); var _collectBinnedDataFromChildSeries = _interopRequireDefault(require("../utils/collectBinnedDataFromChildSeries")); var _componentName = _interopRequireDefault(require("../utils/componentName")); var _computeDomainsFromBins = _interopRequireDefault(require("../utils/computeDomainsFromBins")); var _getValueKey = _interopRequireDefault(require("../utils/getValueKey")); var _shallowCompareObjectEntries = _interopRequireDefault(require("../utils/shallowCompareObjectEntries")); var _propShapes = require("../utils/propShapes"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } 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); } var propTypes = _extends({}, _shared.withTooltipPropTypes, { ariaLabel: _propTypes.default.string.isRequired, binValues: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string])), binCount: _propTypes.default.number, binType: _propTypes.default.oneOf(['numeric', 'categorical']), children: _propTypes.default.node.isRequired, cumulative: _propTypes.default.bool, height: _propTypes.default.number.isRequired, horizontal: _propTypes.default.bool, limits: _propTypes.default.arrayOf(_propTypes.default.number), // values outside the limits are ignored margin: _propTypes.default.shape({ top: _propTypes.default.number, right: _propTypes.default.number, bottom: _propTypes.default.number, left: _propTypes.default.number }), normalized: _propTypes.default.bool, renderTooltip: _propTypes.default.func, theme: _propShapes.themeShape, width: _propTypes.default.number.isRequired, valueAccessor: _propTypes.default.func }); exports.propTypes = propTypes; var defaultProps = { binCount: 10, binType: 'numeric', binValues: null, cumulative: false, horizontal: false, limits: null, margin: { top: 32, right: 32, bottom: 64, left: 64 }, normalized: false, renderTooltip: null, theme: {}, valueAccessor: function valueAccessor(d) { return d; } }; var Histogram = /*#__PURE__*/ function (_React$PureComponent) { _inheritsLoose(Histogram, _React$PureComponent); function Histogram(props) { var _this; _this = _React$PureComponent.call(this, props) || this; _this.state = _this.getStateFromProps(props); return _this; } var _proto = Histogram.prototype; _proto.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { var _this2 = this; var shouldComputeBinsAndScales = false; // eslint-disable-next-line react/destructuring-assignment if (['width', 'height', 'children'].some(function (prop) { return _this2.props[prop] !== nextProps[prop]; })) { shouldComputeBinsAndScales = true; } if (['margin'].some( // eslint-disable-next-line react/destructuring-assignment function (prop) { return !(0, _shallowCompareObjectEntries.default)(_this2.props[prop], nextProps[prop]); })) { shouldComputeBinsAndScales = true; } if (shouldComputeBinsAndScales) this.setState(this.getStateFromProps(nextProps)); }; _proto.getStateFromProps = function getStateFromProps(props) { var dimensions = this.getDimmensions(props); var binsByIndex = this.getBinnedData(props); var scales = this.getScales(props, binsByIndex, dimensions); return _extends({ binsByIndex: binsByIndex }, dimensions, scales); }; _proto.getDimmensions = function getDimmensions(props) { var _ref = props || this.props, margin = _ref.margin, width = _ref.width, height = _ref.height; var completeMargin = _extends({}, defaultProps.margin, margin); return { margin: completeMargin, innerHeight: height - completeMargin.top - completeMargin.bottom, innerWidth: width - completeMargin.left - completeMargin.right }; }; _proto.getBinnedData = function getBinnedData(props) { var _ref2 = props || this.props, children = _ref2.children, binCount = _ref2.binCount, binType = _ref2.binType, binValues = _ref2.binValues, limits = _ref2.limits, valueAccessor = _ref2.valueAccessor; return (0, _collectBinnedDataFromChildSeries.default)({ children: children, binCount: binCount, binType: binType, binValues: binValues, limits: limits, valueAccessor: valueAccessor }); }; _proto.getScales = function getScales(props, binsByIndex, _ref3) { var innerHeight = _ref3.innerHeight, innerWidth = _ref3.innerWidth; var _ref4 = props || this.props, binType = _ref4.binType, binValues = _ref4.binValues, cumulative = _ref4.cumulative, horizontal = _ref4.horizontal, normalized = _ref4.normalized; var binScaleFunc = binType === 'numeric' ? _scale.scaleLinear : _scale.scaleBand; var valueKey = (0, _getValueKey.default)({ normalized: normalized, cumulative: cumulative }); var _computeDomainsFromBi = (0, _computeDomainsFromBins.default)({ binsByIndex: binsByIndex, binType: binType, binValues: binValues, valueKey: valueKey }), binDomain = _computeDomainsFromBi.binDomain, valueDomain = _computeDomainsFromBi.valueDomain; var binRange = horizontal ? [innerHeight, 0] : [0, innerWidth]; var valueRange = horizontal ? [0, innerWidth] : [innerHeight, 0]; // when viewing categorical data horizontally it is more natural to // read alphabetical from top down if (horizontal && binType === 'categorical') binRange.reverse(); return { binScale: binScaleFunc({ range: binRange, domain: binDomain }), valueScale: (0, _scale.scaleLinear)({ range: valueRange, domain: valueDomain }), valueKey: valueKey }; }; _proto.render = function render() { var renderTooltip = this.props.renderTooltip; if (renderTooltip) { return _react.default.createElement(_shared.WithTooltip, { renderTooltip: renderTooltip }, _react.default.createElement(Histogram, _extends({}, this.props, { renderTooltip: null }))); } var _this$props = this.props, ariaLabel = _this$props.ariaLabel, binType = _this$props.binType, binValues = _this$props.binValues, children = _this$props.children, height = _this$props.height, horizontal = _this$props.horizontal, onMouseLeave = _this$props.onMouseLeave, onMouseMove = _this$props.onMouseMove, theme = _this$props.theme, valueAccessor = _this$props.valueAccessor, width = _this$props.width; var _this$state = this.state, binsByIndex = _this$state.binsByIndex, binScale = _this$state.binScale, innerHeight = _this$state.innerHeight, innerWidth = _this$state.innerWidth, margin = _this$state.margin, valueKey = _this$state.valueKey, valueScale = _this$state.valueScale; return _react.default.createElement("svg", { "aria-label": ariaLabel, role: "img", width: width, height: height }, _react.default.createElement(_group.Group, { left: margin.left, top: margin.top }, _react.default.Children.map(children, function (Child, index) { var name = (0, _componentName.default)(Child); if ((0, _componentIsX.isSeries)(name)) { var binnedData = binsByIndex[index]; return _react.default.cloneElement(Child, { binScale: binScale, binType: binType, binnedData: binnedData, horizontal: horizontal, valueAccessor: valueAccessor, valueKey: valueKey, valueScale: valueScale, onMouseLeave: onMouseLeave, onMouseMove: onMouseMove }); } else if ((0, _componentIsX.isAxis)(name)) { var styleKey = name[0].toLowerCase(); var binOrValue = name === 'XAxis' && !horizontal || name === 'YAxis' && horizontal ? 'bin' : 'value'; var tickValues = Child.props.tickValues || (binOrValue === 'bin' && binValues ? binValues : null); return _react.default.cloneElement(Child, { top: name === 'YAxis' || Child.props.orientation === 'top' ? 0 : innerHeight, left: name === 'XAxis' || Child.props.orientation === 'left' ? 0 : innerWidth, label: Child.props.label || (binOrValue === 'value' ? valueKey : null), scale: binOrValue === 'value' ? valueScale : binScale, axisStyles: _extends({}, theme[styleKey + "AxisStyles"], Child.props.axisStyles), tickStyles: _extends({}, theme[styleKey + "TickStyles"], Child.props.tickStyles), tickValues: tickValues }); } return Child; }))); }; return Histogram; }(_react.default.PureComponent); Histogram.propTypes = propTypes; Histogram.defaultProps = defaultProps; Histogram.displayName = 'Histogram'; var _default = Histogram; exports.default = _default;