@ichigo_san/graphing
Version:
A lightweight UML-style diagram editor built with React Flow and Tailwind CSS
118 lines (117 loc) • 6.21 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.autoLayoutNodes = void 0;
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
const autoLayoutNodes = nodes => {
const updated = [...nodes];
const estimateTextSize = function (text) {
let minW = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 80;
let minH = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 50;
let maxW = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 220;
let maxH = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 220;
if (!text) return {
width: minW,
height: minH
};
const lines = text.split(/\n+/);
const maxLine = Math.max(...lines.map(l => l.length));
let width = maxLine * 6 + 16;
let height = lines.length * 16 + 16;
width = Math.max(minW, Math.min(maxW, width));
height = Math.max(minH, Math.min(maxH, height));
const ratio = width / height;
if (ratio > 1.2) {
height = width / 1.2;
} else if (ratio < 0.83) {
width = height / 0.83;
}
width = Math.min(maxW, width);
height = Math.min(maxH, height);
return {
width,
height
};
};
const layoutContainer = function (container) {
var _container$data, _container$data2;
let baseZ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
const padding = 30;
const children = updated.filter(n => n.parentNode === container.id);
const text = "".concat(((_container$data = container.data) === null || _container$data === void 0 ? void 0 : _container$data.label) || '', " ").concat(((_container$data2 = container.data) === null || _container$data2 === void 0 ? void 0 : _container$data2.description) || '').trim();
const textSize = estimateTextSize(text, 130, 100);
const headerHeight = textSize.height;
let neededWidth = textSize.width;
let neededHeight = headerHeight;
if (children.length > 0) {
children.forEach(child => {
var _child$data, _child$data2;
if (child.type === 'container') {
layoutContainer(child, baseZ + 1);
}
const childText = "".concat(((_child$data = child.data) === null || _child$data === void 0 ? void 0 : _child$data.label) || '', " ").concat(((_child$data2 = child.data) === null || _child$data2 === void 0 ? void 0 : _child$data2.description) || '').trim();
const cSize = estimateTextSize(childText);
child.style.width = Math.max(80, cSize.width);
child.style.height = Math.max(50, cSize.height);
const childZ = baseZ + 1;
child.zIndex = childZ;
child.style = _objectSpread(_objectSpread({}, child.style), {}, {
zIndex: childZ
});
});
const maxChildW = Math.max(...children.map(c => {
var _c$style;
return ((_c$style = c.style) === null || _c$style === void 0 ? void 0 : _c$style.width) || 100;
}));
const maxChildH = Math.max(...children.map(c => {
var _c$style2;
return ((_c$style2 = c.style) === null || _c$style2 === void 0 ? void 0 : _c$style2.height) || 60;
}));
const cols = Math.ceil(Math.sqrt(children.length));
const rows = Math.ceil(children.length / cols);
children.forEach((child, i) => {
const col = i % cols;
const row = Math.floor(i / cols);
child.position = {
x: padding / 2 + col * (maxChildW + padding),
y: headerHeight + padding / 2 + row * (maxChildH + padding)
};
// position already set above
});
neededWidth = Math.max(neededWidth, padding + cols * (maxChildW + padding) - padding);
neededHeight = Math.max(neededHeight, headerHeight + padding + rows * (maxChildH + padding) - padding);
}
container.zIndex = baseZ;
container.style = _objectSpread(_objectSpread({}, container.style), {}, {
width: Math.max(130, neededWidth),
height: Math.max(100, neededHeight),
zIndex: baseZ
});
};
const topContainers = updated.filter(n => n.type === 'container' && !n.parentNode);
topContainers.forEach(c => layoutContainer(c, 1));
const center = {
x: 400,
y: 300
};
const maxSize = Math.max(...topContainers.map(c => {
var _c$style3, _c$style4;
return Math.max(((_c$style3 = c.style) === null || _c$style3 === void 0 ? void 0 : _c$style3.width) || 150, ((_c$style4 = c.style) === null || _c$style4 === void 0 ? void 0 : _c$style4.height) || 120);
}), 150);
const radius = Math.max(120, maxSize * topContainers.length / (Math.PI * 1.5));
const angleStep = 2 * Math.PI / Math.max(1, topContainers.length);
topContainers.forEach((container, idx) => {
const angle = idx * angleStep;
container.position = {
x: center.x + radius * Math.cos(angle),
y: center.y + radius * Math.sin(angle)
};
});
return updated;
};
exports.autoLayoutNodes = autoLayoutNodes;