UNPKG

butterfly-dag

Version:

一个基于数据驱动的节点式编排组件库,让你有方便快捷定制可视化流程图表

235 lines (204 loc) 6.2 kB
function gridLayout (param) { const self = param.opts; const nodes = param.data.nodes; const n = nodes.length; const center = self.center; if (n === 0) { return; } if (n === 1) { nodes[0].x = center[0]; nodes[0].y = center[1]; nodes[0].left = center[0]; nodes[0].top = center[1]; return; } const edges = param.data.edges; const layoutNodes = []; nodes.forEach((node) => { layoutNodes.push(node); }); const nodeIdxMap = {}; layoutNodes.forEach((node, i) => { nodeIdxMap[node.id] = i; }); // 排序 if ( self.sortBy === 'degree' || typeof self.sortBy === 'string' || layoutNodes[0][self.sortBy] === undefined ) { self.sortBy = 'degree'; if (isNaN(nodes[0].degree)) { const values = getDegree(layoutNodes.length, nodeIdxMap, edges); layoutNodes.forEach((node, i) => { node.degree = values[i]; }); } } // sort nodes by value layoutNodes.sort((n1, n2) => (n2)[self.sortBy] - (n1)[self.sortBy]); if (!self.width && typeof window !== 'undefined') { self.width = window.innerWidth; } if (!self.height && typeof window !== 'undefined') { self.height = window.innerHeight; } const oRows = self.rows; const oCols = self.cols != null ? self.cols : self.columns; self.cells = n; // if rows or columns were set in self, use those values if (oRows != null && oCols != null) { self.rows = oRows; self.cols = oCols; } else if (oRows != null && oCols == null) { self.rows = oRows; self.cols = Math.ceil(self.cells / self.rows); } else if (oRows == null && oCols != null) { self.cols = oCols; self.rows = Math.ceil(self.cells / self.cols); } else { // otherwise use the automatic values and adjust accordingly // otherwise use the automatic values and adjust accordingly // width/height * splits^2 = cells where splits is number of times to split width self.splits = Math.sqrt((self.cells * self.height) / self.width); self.rows = Math.round(self.splits); self.cols = Math.round((self.width / self.height) * self.splits); } self.cellWidth = self.width / self.cols; self.cellHeight = self.height / self.rows; if (self.condense) { self.cellWidth = 0; self.cellHeight = 0; } if (self.preventOverlap) { layoutNodes.forEach((node) => { if (!node.x || !node.y) { // for bb node.x = 0; node.y = 0; } let nodew; let nodeh; // if (isArray(node.size)) { // nodew = node.size[0]; // nodeh = node.size[1]; // } else if ( typeof node.size === 'number') { nodew = node.size; nodeh = node.size; } if (nodew === undefined || nodeh === undefined) { // if (isArray(self.nodeSize)) { // nodew = self.nodeSize[0]; // nodeh = self.nodeSize[1]; // } else if ( typeof node.nodeSize === 'number') { nodew = self.nodeSize; nodeh = self.nodeSize; } else { nodew = 30; nodeh = 30; } } const p = self.preventOverlapPadding; const w = nodew + p; const h = nodeh + p; self.cellWidth = Math.max(self.cellWidth, w); self.cellHeight = Math.max(self.cellHeight, h); }); } self.cellUsed = {}; // e.g. 'c-0-2' => true // to keep track of current cell position self.row = 0; self.col = 0; // get a cache of all the manual positions self.id2manPos = {}; for (let i = 0; i < layoutNodes.length; i++) { const node = layoutNodes[i]; let rcPos; if (self.position) { rcPos = self.position(node); } if (rcPos && (rcPos.row !== undefined || rcPos.col !== undefined)) { // must have at least row or col def'd const pos = { row: rcPos.row, col: rcPos.col, }; if (pos.col === undefined) { // find unused col pos.col = 0; while (used(pos.row, pos.col,self)) { pos.col++; } } else if (pos.row === undefined) { // find unused row pos.row = 0; while (used(pos.row, pos.col,self)) { pos.row++; } } self.id2manPos[node.id] = pos; use(pos.row, pos.col); } getPos(node,self); } } function getDegree (n, nodeIdxMap, edges) { const degrees = []; for (let i = 0; i < n; i++) { degrees[i] = 0; } edges.forEach((e) => { if (e.source) { degrees[nodeIdxMap[e.source]] += 1; } if (e.target) { degrees[nodeIdxMap[e.target]] += 1; } }); return degrees; }; function use(row, col,self) { self.cellUsed[`c-${row}-${col}`] = true; } function used(row, col,self) { return self.cellUsed[`c-${row}-${col}`] || false; } function moveToNextCell(param) { const self = param; const cols = self.cols || 5; self.col++; if (self.col >= cols) { self.col = 0; self.row++; } } function getPos(node,param) { const self = param; const begin = self.begin; const cellWidth = self.width; const cellHeight = self.height; let x; let y; // see if we have a manual position set const rcPos = self.id2manPos[node.id]; if (rcPos) { x = rcPos.col * cellWidth + cellWidth / 2 + begin[0]; y = rcPos.row * cellHeight + cellHeight / 2 + begin[1]; } else { // otherwise set automatically while (used(self.row, self.col,self)) { moveToNextCell(param); } x = self.col * cellWidth + cellWidth / 2 + begin[0]; y = self.row * cellHeight + cellHeight / 2 + begin[1]; use(self.row, self.col,self); moveToNextCell(param); } node.x = x; node.y = y; node.left = x; node.top = y } module.exports = gridLayout;