UNPKG

@visactor/vgrammar-hierarchy

Version:

Layout of hierarchical data for VGrammar

147 lines (142 loc) 7.91 kB
"use strict"; var __importDefault = this && this.__importDefault || function(mod) { return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: !0 }), exports.TreemapLayout = void 0; const vutils_1 = require("@visactor/vutils"), binary_1 = __importDefault(require("./binary")), dice_1 = __importDefault(require("./dice")), slice_1 = __importDefault(require("./slice")), sliceDice_1 = __importDefault(require("./sliceDice")), squarify_1 = require("./squarify"), vgrammar_util_1 = require("@visactor/vgrammar-util"), utils_1 = require("../utils"), algorithms = { binary: binary_1.default, dice: dice_1.default, slice: slice_1.default, sliceDice: sliceDice_1.default }; class TreemapLayout { constructor(options) { var _a; this._filterByArea = (node, ratio) => { var _a; const minArea = this._getMinAreaByDepth(node.depth); if (minArea > 0 && node.value * ratio < minArea) return !1; if (null === (_a = node.children) || void 0 === _a ? void 0 : _a.length) { const newChildren = node.children.filter((child => this._filterByArea(child, ratio))); newChildren.length ? newChildren.length !== node.children.length && (node.children = newChildren) : (node.isLeaf = !0, node.children = null); } return !0; }, this._getMinAreaByDepth = depth => { var _a; return depth < 0 ? 0 : null !== (_a = (0, vutils_1.isArray)(this.options.minVisibleArea) ? this.options.minVisibleArea[depth] : this.options.minVisibleArea) && void 0 !== _a ? _a : 0; }, this._getGapWidthByDepth = depth => { var _a; return depth < 0 ? 0 : null !== (_a = (0, vutils_1.isArray)(this.options.gapWidth) ? this.options.gapWidth[depth] : this.options.gapWidth) && void 0 !== _a ? _a : 0; }, this._getPaddingByDepth = depth => { var _a; return depth < 0 ? 0 : null !== (_a = (0, vutils_1.isArray)(this.options.padding) ? this.options.padding[depth] : this.options.padding) && void 0 !== _a ? _a : 0; }, this._getLabelPaddingByDepth = depth => { var _a; return depth < 0 ? 0 : null !== (_a = (0, vutils_1.isArray)(this.options.labelPadding) ? this.options.labelPadding[depth] : this.options.labelPadding) && void 0 !== _a ? _a : 0; }, this._layoutNode = parent => { const gapWidth = this._getGapWidthByDepth(parent.depth); let x0 = parent.x0, y0 = parent.y0, x1 = parent.x1, y1 = parent.y1; if (parent.maxDepth = this._maxDepth, gapWidth > 0 && (x0 += gapWidth / 2, x1 -= gapWidth / 2, y0 += gapWidth / 2, y1 -= gapWidth / 2, x0 > x1 && (x0 = (x0 + x1) / 2, x1 = x0), y0 > y1 && (y0 = (y0 + y1) / 2, y1 = y0), parent.x0 = x0, parent.x1 = x1, parent.y0 = y0, parent.y1 = y1), parent.children) { const labelPadding = this._getLabelPaddingByDepth(parent.depth), padding = this._getPaddingByDepth(parent.depth); padding > 0 && padding < Math.min(x1 - x0, y1 - y0) / 2 && (y0 += padding, y1 -= padding, x0 += padding, x1 -= padding), labelPadding > 0 && ("top" === this.options.labelPosition && y0 + labelPadding < y1 ? (parent.labelRect = { x0: x0, y0: y0, x1: x1, y1: y0 + labelPadding }, y0 += labelPadding) : "bottom" === this.options.labelPosition && y1 - labelPadding > y0 ? (parent.labelRect = { x0: x0, y0: y1 - labelPadding, x1: x1, y1: y1 }, y1 -= labelPadding) : "left" === this.options.labelPosition && x0 + labelPadding < x1 ? (parent.labelRect = { x0: x0, y0: y0, x1: x0 + labelPadding, y1: y1 }, x0 += labelPadding) : "right" === this.options.labelPosition && x1 - labelPadding > x0 && (parent.labelRect = { x0: x1 - labelPadding, y0: y0, x1: x1, y1: y1 }, x1 -= labelPadding)); const childGapWidth = this._getGapWidthByDepth(parent.depth + 1); childGapWidth > 0 && (x0 -= childGapWidth / 2, x1 += childGapWidth / 2, y0 -= childGapWidth / 2, y1 += childGapWidth / 2), this._splitNode(parent, x0, y0, x1, y1); } }, this.options = Object.assign({}, TreemapLayout.defaultOpionts, options); const keyOption = this.options.nodeKey, keyFunc = (0, vutils_1.isFunction)(keyOption) ? keyOption : keyOption ? (0, vgrammar_util_1.field)(keyOption) : null; this._getNodeKey = keyFunc, this._splitNode = "squarify" === this.options.splitType ? (0, squarify_1.generateSquarify)(this.options.aspectRatio) : null !== (_a = algorithms[this.options.splitType]) && void 0 !== _a ? _a : algorithms.binary, this._maxDepth = -1; } layout(data, config) { var _a; if (!data || !data.length) return []; const viewBox = "width" in config ? { x0: 0, x1: config.width, y0: 0, y1: config.height, width: config.width, height: config.height } : { x0: Math.min(config.x0, config.x1), x1: Math.max(config.x0, config.x1), y0: Math.min(config.y0, config.y1), y1: Math.max(config.y0, config.y1), width: Math.abs(config.x1 - config.x0), height: Math.abs(config.y1 - config.y0) }, nodes = [], res = (0, utils_1.calculateNodeValue)(data, nodes, 0, -1, null, this._getNodeKey, this.options.valueField); if (this._maxDepth = res.maxDepth, res.sum <= 0) return []; const root = { flattenIndex: -1, maxDepth: -1, key: "-1", depth: -1, index: -1, value: res.sum, datum: null, x0: viewBox.x0, x1: viewBox.x1, y0: viewBox.y0, y1: viewBox.y1, children: nodes }, areaRatio = viewBox.width * viewBox.height / res.sum; return this._filterByArea(root, areaRatio), this._layout(root), null !== (_a = root.children) && void 0 !== _a ? _a : []; } _filterChildren(node) { const maxDepth = this.options.maxDepth; if ((0, vutils_1.isNumber)(maxDepth) && maxDepth >= 0 && node.depth >= maxDepth) return !1; const minChildrenVisibleArea = this.options.minChildrenVisibleArea; if ((0, vutils_1.isNumber)(minChildrenVisibleArea) && Math.abs((node.x1 - node.x0) * (node.y1 - node.y0)) < minChildrenVisibleArea) return !1; const minChildrenVisibleSize = this.options.minChildrenVisibleSize; return !(0, vutils_1.isNumber)(minChildrenVisibleSize) || !(Math.abs(node.x1 - node.x0) < minChildrenVisibleSize || Math.abs(node.y1 - node.y0) < minChildrenVisibleSize); } _layout(parent) { var _a; this._filterChildren(parent) || (parent.children = null, parent.isLeaf = !0), this._layoutNode(parent), (null === (_a = parent.children) || void 0 === _a ? void 0 : _a.length) && parent.children.forEach((child => { var _a; (null === (_a = null == child ? void 0 : child.children) || void 0 === _a ? void 0 : _a.length) ? this._layout(child) : this._layoutNode(child); })); } } exports.TreemapLayout = TreemapLayout, TreemapLayout.defaultOpionts = { aspectRatio: (1 + Math.sqrt(5)) / 2, gapWidth: 0, labelPadding: 0, labelPosition: "top", splitType: "binary", minVisibleArea: 10 }; //# sourceMappingURL=layout.js.map