UNPKG

recharts

Version:
314 lines (262 loc) 10.6 kB
'use strict'; 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, _temp; /** * @fileOverview TreemapChart */ Object.defineProperty(exports, "__esModule", { value: true }); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _Surface = require('../container/Surface'); var _Surface2 = _interopRequireDefault(_Surface); var _Layer = require('../container/Layer'); var _Layer2 = _interopRequireDefault(_Layer); var _Rectangle = require('../shape/Rectangle'); var _Rectangle2 = _interopRequireDefault(_Rectangle); var _ReactUtils = require('../util/ReactUtils'); var _ReactUtils2 = _interopRequireDefault(_ReactUtils); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } 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 Treemap = (_temp = _class = function (_Component) { _inherits(Treemap, _Component); function Treemap() { _classCallCheck(this, Treemap); return _possibleConstructorReturn(this, Object.getPrototypeOf(Treemap).apply(this, arguments)); } _createClass(Treemap, [{ key: 'pad', value: function pad(node) { return { x: node.x, y: node.y, width: node.width, height: node.height }; } // Compute the area for each child based on value & scale. }, { key: 'scale', value: function scale(children, k) { var n = children.length; var i = -1; var child = undefined; var area = undefined; while (++i < n) { area = (child = children[i]).value * (k < 0 ? 0 : k); child.area = isNaN(area) || area <= 0 ? 0 : area; } } // Recursively arranges the specified node's children into squarified rows. }, { key: 'squarify', value: function squarify(node) { var children = node.children; if (children && children.length) { var rect = this.pad(node); var row = []; var remaining = children.slice(); // copy-on-write var child = undefined; var best = Infinity; // the best row score so far var score = undefined; // the current row score var u = Math.min(rect.width, rect.height); // initial orientation this.scale(remaining, rect.width * rect.height / node.value); row.area = 0; while (remaining.length > 0) { row.push(child = remaining[0]); row.area += child.area; score = this.worst(row, u); if (score <= best) { // continue with this orientation remaining.shift(); best = score; } else { // abort, and try a different orientation row.area -= row.pop().area; this.position(row, u, rect, false); u = Math.min(rect.width, rect.height); row.length = row.area = 0; best = Infinity; } } if (row.length) { this.position(row, u, rect, true); row.length = row.area = 0; } children.forEach(this.squarify.bind(this)); } } // Computes the score for the specified row, as the worst aspect ratio. }, { key: 'worst', value: function worst(row, u) { var newU = u; var s = row.area; var r = undefined; var rmax = 0; var rmin = Infinity; var i = -1; var n = row.length; var ratio = this.props.ratio; while (++i < n) { r = row[i].area; if (!r) continue; if (r < rmin) rmin = r; if (r > rmax) rmax = r; } s *= s; newU *= newU; return s ? Math.max(newU * rmax * ratio / s, s / (newU * rmin * ratio)) : Infinity; } // Positions the specified row of nodes. Modifies `rect`. }, { key: 'position', value: function position(row, u, rect, flush) { var i = -1; var n = row.length; var x = rect.x; var y = rect.y; var v = u ? Math.round(row.area / u) : 0; var o = undefined; if (u === rect.width) { // horizontal subdivision if (flush || v > rect.height) v = rect.height; // over+underflow while (++i < n) { o = row[i]; o.x = x; o.y = y; o.height = v; x += o.width = Math.min(rect.x + rect.width - x, v ? Math.round(o.area / v) : 0); } o.z = true; o.width += rect.x + rect.width - x; // rounding error rect.y += v; rect.height -= v; } else { // vertical subdivision if (flush || v > rect.width) v = rect.width; // over+underflow while (++i < n) { o = row[i]; o.x = x; o.y = y; o.width = v; y += o.height = Math.min(rect.y + rect.height - y, v ? Math.round(o.area / v) : 0); } o.z = false; o.height += rect.y + rect.height - y; // rounding error rect.x += v; rect.width -= v; } } }, { key: 'computeNode', value: function computeNode(depth, node, index) { var dataKey = this.props.dataKey; var children = node.children; var x = node.x; var y = node.y; var width = node.width; var height = node.height; var payload = _objectWithoutProperties(node, ['children', 'x', 'y', 'width', 'height']); var childDepth = depth + 1; var computedChildren = children && children.length ? children.map(this.computeNode.bind(this, childDepth)) : null; var value = undefined; if (children && children.length) { value = computedChildren.reduce(function (a, b) { return a + b.value; }, 0); } else { value = isNaN(node[dataKey]) || node[dataKey] <= 0 ? 0 : node[dataKey]; } return { children: computedChildren, value: value, depth: depth, index: index, x: x, y: y, width: width, height: height, payload: payload }; } }, { key: 'renderDefaultNode', value: function renderDefaultNode(nodeProps) { return _react2.default.createElement(_Rectangle2.default, nodeProps); } }, { key: 'renderNode', value: function renderNode(root, node, i) { var content = this.props.content; var nodeProps = _extends({}, _ReactUtils2.default.getPresentationAttributes(this.props), node, { root: root }); return _react2.default.createElement( _Layer2.default, { key: 'recharts-treemap-node-' + i }, _react2.default.isValidElement(content) ? _react2.default.cloneElement(content, nodeProps) : this.renderDefaultNode(nodeProps), node.children && node.children.length ? node.children.map(this.renderNode.bind(this, root)) : null ); } }, { key: 'renderAllNodes', value: function renderAllNodes() { var _props = this.props; var width = _props.width; var height = _props.height; var data = _props.data; var root = this.computeNode(0, { children: data, x: 0, y: 0, width: width, height: height }, 0); this.squarify(root); return this.renderNode(root, root, 0); } }, { key: 'render', value: function render() { if (!_ReactUtils2.default.validateWidthHeight(this)) { return null; } var _props2 = this.props; var width = _props2.width; var height = _props2.height; var className = _props2.className; var style = _props2.style; return _react2.default.createElement( 'div', { className: (0, _classnames2.default)('recharts-wrapper', className), style: _extends({ position: 'relative', cursor: 'default' }, style) }, _react2.default.createElement( _Surface2.default, { width: width, height: height }, this.renderAllNodes() ) ); } }]); return Treemap; }(_react.Component), _class.displayName = 'Treemap', _class.propTypes = { width: _react.PropTypes.number, height: _react.PropTypes.number, data: _react.PropTypes.array, style: _react.PropTypes.object, ratio: _react.PropTypes.number, content: _react.PropTypes.element, fill: _react.PropTypes.string, stroke: _react.PropTypes.string, className: _react.PropTypes.string, dataKey: _react.PropTypes.string }, _class.defaultProps = { fill: '#fff', stroke: '#000', dataKey: 'value', ratio: 0.5 * (1 + Math.sqrt(5)) }, _temp); exports.default = Treemap;