#3358 Recursive positioning

This commit is contained in:
Knut Sveidqvist
2023-10-03 14:19:08 +02:00
parent b4e32542e8
commit f00871a6b4
7 changed files with 326 additions and 69 deletions

View File

@@ -69,12 +69,15 @@ block-beta
id2("2") id2("2")
block block
id3["I am a wide one"] id3["I am a wide one"]
id4 block
id44("A final one")
id45("B final one")
end end
%% id4("A final one") end
id4("Another final one")
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid">
block-beta block-beta
id3["I am a wide one"] id3["I am a wide one"]
@@ -84,7 +87,9 @@ block-beta
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart RL flowchart RL
subgraph "`one`"
id id
end
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart RL flowchart RL

View File

@@ -357,6 +357,54 @@ const rect = async (parent, node) => {
return shapeSvg; return shapeSvg;
}; };
const composite = async (parent, node) => {
console.log('This got called');
const { shapeSvg, bbox, halfPadding } = await labelHelper(
parent,
node,
'node ' + node.classes,
true
);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
// const totalWidth = bbox.width + node.padding * 2;
// const totalHeight = bbox.height + node.padding * 2;
const totalWidth = node.positioned ? node.width : bbox.width + node.padding;
const totalHeight = node.positioned ? node.height : bbox.height + node.padding;
const x = node.positioned ? -totalWidth / 2 : -bbox.width / 2 - halfPadding;
const y = node.positioned ? -totalHeight / 2 : -bbox.height / 2 - halfPadding;
rect
.attr('class', 'basic cluster composite label-container')
.attr('style', node.style)
.attr('rx', node.rx)
.attr('ry', node.ry)
.attr('x', x)
.attr('y', y)
.attr('width', totalWidth)
.attr('height', totalHeight);
if (node.props) {
const propKeys = new Set(Object.keys(node.props));
if (node.props.borders) {
applyNodePropertyBorders(rect, node.props.borders, totalWidth, totalHeight);
propKeys.delete('borders');
}
propKeys.forEach((propKey) => {
log.warn(`Unknown node property ${propKey}`);
});
}
updateNodeBounds(node, rect);
node.intersect = function (point) {
return intersect.rect(node, point);
};
return shapeSvg;
};
const labelRect = async (parent, node) => { const labelRect = async (parent, node) => {
const { shapeSvg } = await labelHelper(parent, node, 'label', true); const { shapeSvg } = await labelHelper(parent, node, 'label', true);
@@ -959,6 +1007,7 @@ const class_box = (parent, node) => {
const shapes = { const shapes = {
rhombus: question, rhombus: question,
composite,
question, question,
rect, rect,
labelRect, labelRect,

View File

@@ -27,7 +27,7 @@ const populateBlockDatabase = (blockList: Block[], parent: Block): void => {
} else { } else {
if (!block.label) { if (!block.label) {
if (block.type === 'composite') { if (block.type === 'composite') {
block.label = 'x'; block.label = '';
} else { } else {
block.label = block.id; block.label = block.id;
} }

View File

@@ -2,15 +2,17 @@ import { BlockDB } from './blockDB.js';
import type { Block } from './blockTypes.js'; import type { Block } from './blockTypes.js';
function calcBlockSizes(block: Block, db: BlockDB) { function calcBlockSizes(block: Block, db: BlockDB) {
let totalWidth = 0; const totalWidth = 0;
let totalHeight = 0; const totalHeight = 0;
let maxWidth = 0;
let maxHeight = 0;
const padding = 20;
if (block.children) { if (block.children) {
for (const child of block.children) { for (const child of block.children) {
calcBlockSizes(child, db); calcBlockSizes(child, db);
} }
// find max width of children // find max width of children
let maxWidth = 0;
let maxHeight = 0;
for (const child of block.children) { for (const child of block.children) {
const { width, height, x, y } = child.size || { width: 0, height: 0, x: 0, y: 0 }; const { width, height, x, y } = child.size || { width: 0, height: 0, x: 0, y: 0 };
if (width > maxWidth) { if (width > maxWidth) {
@@ -30,39 +32,41 @@ function calcBlockSizes(block: Block, db: BlockDB) {
} }
// Position items relative to self // Position items relative to self
let x = 0; let x = -padding / 2;
const y = 0; const y = 0;
const padding = 10;
let accumulatedPaddingX = 0;
for (const child of block.children) { for (const child of block.children) {
if (child.size) { if (child.size) {
child.size.x = x; child.size.x = x;
child.size.y = y; child.size.y = y;
x += maxWidth + padding; x += maxWidth + padding;
} }
if (x > totalWidth) { accumulatedPaddingX += padding;
totalWidth = x;
}
if (y > totalHeight) {
totalHeight = y;
}
} }
} }
if (block.children?.length > 0) { if (block.children?.length > 0) {
block.size = { width: totalWidth, height: totalHeight, x: 0, y: 0 }; const numChildren = block.children.length;
block.size = {
width: numChildren * (maxWidth + padding) + padding,
height: totalHeight + 4 * padding,
x: 0,
y: 0,
};
} }
console.log('layoutBlock (done)', block); console.log('layoutBlock (done)', block);
} }
function positionBlock(parent: Block, block: Block, db: BlockDB) { function positionBlock(parent: Block, block: Block, db: BlockDB) {
console.log('layout position block', parent.id, parent?.size?.x, block.id, block?.size?.x); console.log('layout position block', parent.id, parent?.size?.x, block.id, block?.size?.x);
let x = 0; let parentX = 0;
let y = 0; let y = 0;
if (parent) { if (parent) {
x = parent?.size?.x || 0; parentX = parent?.size?.x || 0;
y = parent?.size?.y || 0; y = parent?.size?.y || 0;
} }
if (block.size) { if (block.size && block.id !== 'root') {
block.size.x = block.size.x + x - block.size.width / 2; block.size.x = parentX + block.size.x + -block.size.width / 2;
block.size.y = block.size.y + y; block.size.y = block.size.y + y;
} }
if (block.children) { if (block.children) {
@@ -104,9 +108,9 @@ export function layout(db: BlockDB) {
const blocks = db.getBlocks(); const blocks = db.getBlocks();
const root = { id: 'root', type: 'composite', children: blocks } as Block; const root = { id: 'root', type: 'composite', children: blocks } as Block;
calcBlockSizes(root, db); calcBlockSizes(root, db);
console.log('layout getBlocks', db.getBlocks());
// Position blocks relative to parents // Position blocks relative to parents
positionBlock(root, root, db); positionBlock(root, root, db);
console.log('getBlocks', JSON.stringify(db.getBlocks(), null, 2));
minX = 0; minX = 0;
minY = 0; minY = 0;

View File

@@ -26,12 +26,17 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
let radious = 0; let radious = 0;
let _shape = ''; let _shape = '';
let layoutOptions = {}; let layoutOptions = {};
console.log('This is the type:', vertex.type);
// Set the shape based parameters // Set the shape based parameters
switch (vertex.type) { switch (vertex.type) {
case 'round': case 'round':
radious = 5; radious = 5;
_shape = 'rect'; _shape = 'rect';
break; break;
case 'composite':
radious = 4;
_shape = 'composite';
break;
case 'square': case 'square':
_shape = 'rect'; _shape = 'rect';
break; break;

View File

@@ -42,6 +42,8 @@ const getStyles = (options: FlowChartStyleOptions) =>
color: ${options.titleColor}; color: ${options.titleColor};
} }
.label text,span,p { .label text,span,p {
fill: ${options.nodeTextColor || options.textColor}; fill: ${options.nodeTextColor || options.textColor};
color: ${options.nodeTextColor || options.textColor}; color: ${options.nodeTextColor || options.textColor};
@@ -103,9 +105,11 @@ const getStyles = (options: FlowChartStyleOptions) =>
// background-color: // background-color:
} }
.cluster rect { .node .cluster {
fill: ${options.clusterBkg}; // fill: ${fade(options.mainBkg, 0.5)};
stroke: ${options.clusterBorder}; fill: ${fade(options.clusterBkg, 0.5)};
stroke: ${fade(options.clusterBorder, 0.2)};
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
stroke-width: 1px; stroke-width: 1px;
} }

File diff suppressed because one or more lines are too long