UNPKG

@visactor/vgrammar-hierarchy

Version:

Layout of hierarchical data for VGrammar

102 lines (95 loc) 4.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: !0 }), exports.CirclePackingLayout = void 0; const utils_1 = require("../utils"), vutils_1 = require("@visactor/vutils"), vgrammar_util_1 = require("@visactor/vgrammar-util"), lcg_1 = require("../lcg"), siblings_1 = require("./siblings"); function radiusLeaf(radius) { return function(node) { node.children || (node.radius = Math.max(0, +radius(node) || 0)); }; } function packChildrenRandom(padding, k, random) { return function(node) { const children = null == node ? void 0 : node.children; if (children) { let i; const n = children.length, r = padding(node) * k || 0; if (r) for (i = 0; i < n; ++i) children[i].radius += r; const e = (0, siblings_1.packSiblingsRandom)(children, random); if (r) for (i = 0; i < n; ++i) children[i].radius -= r; node.radius = e + r; } }; } function translateChild(k, maxDepth) { return function(node, index, parent) { node.radius *= k, node.maxDepth = maxDepth, parent && (node.x = parent.x + k * node.x, node.y = parent.y + k * node.y); }; } class CirclePackingLayout { constructor(options) { this.options = options; const keyOption = null == options ? void 0 : options.nodeKey, keyFunc = (0, vutils_1.isFunction)(keyOption) ? keyOption : keyOption ? (0, vgrammar_util_1.field)(keyOption) : null; this._getNodeKey = keyFunc, this._getPadding = (0, vutils_1.isNumber)(null == options ? void 0 : options.padding) ? node => options.padding : (0, vutils_1.isArray)(null == options ? void 0 : options.padding) ? node => { var _a; return null !== (_a = options.padding[node.depth + 1]) && void 0 !== _a ? _a : 0; } : () => 0, this._maxDepth = -1; } layout(data, config) { var _a; 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) }; if (!data || !data.length) return []; const nodes = [], res = (0, utils_1.calculateNodeValue)(data, nodes, 0, -1, null, this._getNodeKey); this._maxDepth = res.maxDepth; const random = (0, lcg_1.randomLCG)(), root = { flattenIndex: -1, maxDepth: -1, key: "root", depth: -1, index: -1, value: res.sum, datum: null, children: nodes, x: viewBox.x0 + viewBox.width / 2, y: viewBox.y0 + viewBox.height / 2 }, {nodeSort: nodeSort, setRadius: setRadius, padding: padding, includeRoot: includeRoot} = null !== (_a = this.options) && void 0 !== _a ? _a : {}; if (!1 !== nodeSort) { const sort = (0, vutils_1.isFunction)(nodeSort) ? this.options.nodeKey : CirclePackingLayout.defaultOpionts.nodeSort; (0, utils_1.eachBefore)([ root ], (node => { node.children && node.children.length && node.children.sort(sort); })); } if (setRadius) (0, utils_1.eachBefore)([ root ], radiusLeaf(setRadius)), (0, utils_1.eachAfter)([ root ], packChildrenRandom(this._getPadding, .5, random)), (0, utils_1.eachBefore)([ root ], translateChild(1, this._maxDepth)); else { const size = Math.min(viewBox.width, viewBox.height); (0, utils_1.eachBefore)([ root ], radiusLeaf(CirclePackingLayout.defaultOpionts.setRadius)), (0, utils_1.eachAfter)([ root ], packChildrenRandom(vgrammar_util_1.zero, 1, random)), padding && (0, utils_1.eachAfter)([ root ], packChildrenRandom(this._getPadding, root.radius / size, random)), (0, utils_1.eachBefore)([ root ], translateChild(size / (2 * root.radius), this._maxDepth)); } return includeRoot ? [ root ] : nodes; } } exports.CirclePackingLayout = CirclePackingLayout, CirclePackingLayout.defaultOpionts = { setRadius: node => Math.sqrt(node.value), padding: 0, nodeSort: (a, b) => b.value - a.value }; //# sourceMappingURL=layout.js.map