This commit is contained in:
Knut Sveidqvist
2024-01-30 16:05:16 +01:00
parent 4a04ce6bf8
commit df9b801b0e
8 changed files with 64 additions and 196 deletions

View File

@@ -65,7 +65,7 @@
<body> <body>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
block-beta block-beta
blockArrowId<["Label"]>(right) blockArrowId<["`Label`"]>(right)
blockArrowId2<["Label"]>(left) blockArrowId2<["Label"]>(left)
blockArrowId3<["Label"]>(up) blockArrowId3<["Label"]>(up)
blockArrowId4<["Label"]>(down) blockArrowId4<["Label"]>(down)

View File

@@ -1,5 +1,5 @@
import type { DiagramDB } from '../../diagram-api/types.js'; import type { DiagramDB } from '../../diagram-api/types.js';
import type { BlockConfig, BlockType, Block, Link, ClassDef } from './blockTypes.js'; import type { BlockConfig, BlockType, Block, ClassDef } from './blockTypes.js';
import * as configApi from '../../config.js'; import * as configApi from '../../config.js';
import { clear as commonClear } from '../common/commonDb.js'; import { clear as commonClear } from '../common/commonDb.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
@@ -240,11 +240,6 @@ const setHierarchy = (block: Block[]): void => {
blocks = rootBlock.children; blocks = rootBlock.children;
}; };
const addLink = (link: Link): Link => {
links.push(link);
return link;
};
const getColumns = (blockid: string): number => { const getColumns = (blockid: string): number => {
const block = blockDatabase[blockid]; const block = blockDatabase[blockid];
if (!block) { if (!block) {
@@ -264,13 +259,6 @@ const getColumns = (blockid: string): number => {
* @returns * @returns
*/ */
const getBlocksFlat = () => { const getBlocksFlat = () => {
// const result: Block[] = [];
// // log.debug('abc88 getBlocksFlat', blockDatabase);
// const keys = Object.keys(blockDatabase);
// for (const key of keys) {
// result.push(blockDatabase[key]);
// }
// return result;
return [...Object.values(blockDatabase)]; return [...Object.values(blockDatabase)];
}; };
/** /**
@@ -292,11 +280,8 @@ const setBlock = (block: Block) => {
blockDatabase[block.id] = block; blockDatabase[block.id] = block;
}; };
const getLinks = () => links;
const getLogger = () => console; const getLogger = () => console;
// type IGetClasses = () => Record<string, ClassDef>;
/** /**
* Return all of the style classes * Return all of the style classes
*/ */
@@ -306,15 +291,13 @@ export const getClasses = function () {
const db = { const db = {
getConfig: () => configApi.getConfig().block, getConfig: () => configApi.getConfig().block,
addLink: addLink,
typeStr2Type: typeStr2Type, typeStr2Type: typeStr2Type,
edgeTypeStr2Type: edgeTypeStr2Type, edgeTypeStr2Type: edgeTypeStr2Type,
edgeStrToEdgeData, edgeStrToEdgeData,
getLogger, // TODO: remove getLogger,
getBlocksFlat, getBlocksFlat,
getBlocks, getBlocks,
getEdges, getEdges,
getLinks,
setHierarchy, setHierarchy,
getBlock, getBlock,
setBlock, setBlock,

View File

@@ -2,19 +2,17 @@ import type { Diagram } from '../../Diagram.js';
import * as configApi from '../../config.js'; import * as configApi from '../../config.js';
import { calculateBlockSizes, insertBlocks, insertEdges } from './renderHelpers.js'; import { calculateBlockSizes, insertBlocks, insertEdges } from './renderHelpers.js';
import { layout } from './layout.js'; import { layout } from './layout.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js'; import type { MermaidConfig, BaseDiagramConfig } from '../../config.type.js';
import insertMarkers from '../../dagre-wrapper/markers.js'; import insertMarkers from '../../dagre-wrapper/markers.js';
import { import {
select as d3select, select as d3select,
scaleOrdinal as d3scaleOrdinal, scaleOrdinal as d3scaleOrdinal,
schemeTableau10 as d3schemeTableau10, schemeTableau10 as d3schemeTableau10,
} from 'd3'; } from 'd3';
import type { ContainerElement } from 'd3';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import type { BlockDB } from './blockDB.js'; import type { BlockDB } from './blockDB.js';
import type { Block } from './blockTypes.js'; import type { Block } from './blockTypes.js';
// import { diagram as BlockDiagram } from './blockDiagram.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
/** /**
@@ -34,7 +32,7 @@ export const draw = async function (
_version: string, _version: string,
diagObj: Diagram diagObj: Diagram
): Promise<void> { ): Promise<void> {
const { securityLevel, flowchart: conf } = configApi.getConfig(); const { securityLevel, block: conf } = configApi.getConfig();
const db = diagObj.db as BlockDB; const db = diagObj.db as BlockDB;
let sandboxElement: any; let sandboxElement: any;
if (securityLevel === 'sandbox') { if (securityLevel === 'sandbox') {
@@ -65,7 +63,6 @@ export const draw = async function (
const nodes = svg.insert('g').attr('class', 'block'); const nodes = svg.insert('g').attr('class', 'block');
await calculateBlockSizes(nodes, bl, db); await calculateBlockSizes(nodes, bl, db);
const bounds = layout(db); const bounds = layout(db);
// log.debug('Here be blocks', bl);
await insertBlocks(nodes, bl, db); await insertBlocks(nodes, bl, db);
await insertEdges(nodes, edges, blArr, db, id); await insertEdges(nodes, edges, blArr, db, id);
@@ -80,32 +77,14 @@ export const draw = async function (
const magicFactor = Math.max(1, Math.round(0.125 * (bounds2.width / bounds2.height))); const magicFactor = Math.max(1, Math.round(0.125 * (bounds2.width / bounds2.height)));
const height = bounds2.height + magicFactor + 10; const height = bounds2.height + magicFactor + 10;
const width = bounds2.width + 10; const width = bounds2.width + 10;
const useMaxWidth = false; const { useMaxWidth } = conf as Exclude<MermaidConfig['block'], undefined>;
configureSvgSize(svg, height, width, useMaxWidth); configureSvgSize(svg, height, width, !!useMaxWidth);
log.debug('Here Bounds', bounds, bounds2); log.debug('Here Bounds', bounds, bounds2);
svg.attr( svg.attr(
'viewBox', 'viewBox',
`${bounds2.x - 5} ${bounds2.y - 5} ${bounds2.width + 10} ${bounds2.height + 10}` `${bounds2.x - 5} ${bounds2.y - 5} ${bounds2.width + 10} ${bounds2.height + 10}`
); );
} }
// svg.attr('viewBox', `${-200} ${-200} ${400} ${400}`);
// Prepare data for construction based on diagObj.db
// This must be a mutable object with `nodes` and `links` properties:
//
// @ts-ignore TODO: db type
// const graph = diagObj.db.getGraph();
// const nodeWidth = 10;
// Create rectangles for nodes
// const db:BlockDB = diagObj.db;
interface LayedBlock extends Block {
children?: LayedBlock[];
x?: number;
y?: number;
}
// Get color scheme for the graph // Get color scheme for the graph
const colorScheme = d3scaleOrdinal(d3schemeTableau10); const colorScheme = d3scaleOrdinal(d3schemeTableau10);

View File

@@ -56,12 +56,7 @@ export interface Block {
styleClass?: string; styleClass?: string;
styles?: string[]; styles?: string[];
stylesStr?: string; stylesStr?: string;
w?: number; widthInColumns?: number;
}
export interface Link {
source: Block;
target: Block;
} }
export interface ClassDef { export interface ClassDef {

View File

@@ -1,7 +1,8 @@
import type { BlockDB } from './blockDB.js'; import type { BlockDB } from './blockDB.js';
import type { Block } from './blockTypes.js'; import type { Block } from './blockTypes.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
const padding = 8; import { getConfig } from '../../diagram-api/diagramAPI.js';
const padding = getConfig()?.block?.padding || 8;
interface BlockPosition { interface BlockPosition {
px: number; px: number;
@@ -59,7 +60,7 @@ const getMaxChildSize = (block: Block) => {
continue; continue;
} }
if (width > maxWidth) { if (width > maxWidth) {
maxWidth = width / (block.w || 1); maxWidth = width / (block.widthInColumns || 1);
} }
if (height > maxHeight) { if (height > maxHeight) {
maxHeight = height; maxHeight = height;
@@ -68,7 +69,7 @@ const getMaxChildSize = (block: Block) => {
return { width: maxWidth, height: maxHeight }; return { width: maxWidth, height: maxHeight };
}; };
function setBlockSizes(block: Block, db: BlockDB, sieblingWidth = 0, sieblingHeight = 0) { function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeight = 0) {
log.debug( log.debug(
'setBlockSizes abc95 (start)', 'setBlockSizes abc95 (start)',
block.id, block.id,
@@ -76,18 +77,16 @@ function setBlockSizes(block: Block, db: BlockDB, sieblingWidth = 0, sieblingHei
'block width =', 'block width =',
block?.size, block?.size,
'sieblingWidth', 'sieblingWidth',
sieblingWidth siblingWidth
); );
if (!block?.size?.width) { if (!block?.size?.width) {
block.size = { block.size = {
width: sieblingWidth, width: siblingWidth,
height: sieblingHeight, height: siblingHeight,
x: 0, x: 0,
y: 0, y: 0,
}; };
} }
const totalWidth = 0;
const totalHeight = 0;
let maxWidth = 0; let maxWidth = 0;
let maxHeight = 0; let maxHeight = 0;
@@ -105,34 +104,21 @@ function setBlockSizes(block: Block, db: BlockDB, sieblingWidth = 0, sieblingHei
for (const child of block.children) { for (const child of block.children) {
if (child.size) { if (child.size) {
log.debug( log.debug(
'abc95 Setting size of children of', `abc95 Setting size of children of ${block.id} id=${child.id} ${maxWidth} ${maxHeight} ${child.size}`
block.id,
'id=',
child.id,
maxWidth,
maxHeight,
child.size
); );
child.size.width = maxWidth * (child.w || 1) + padding * ((child.w || 1) - 1); child.size.width =
maxWidth * (child.widthInColumns || 1) + padding * ((child.widthInColumns || 1) - 1);
child.size.height = maxHeight; child.size.height = maxHeight;
child.size.x = 0; child.size.x = 0;
child.size.y = 0; child.size.y = 0;
log.debug( log.debug(
'abc95 updating size of ', `abc95 updating size of ${block.id} children child:${child.id} maxWidth:${maxWidth} maxHeight:${maxHeight}`
block.id,
' children child:',
child.id,
'maxWidth:',
maxWidth,
'maxHeight:',
maxHeight
); );
} }
} }
for (const child of block.children) { for (const child of block.children) {
// log.debug('abc95 fin 2 Setting size', child.id, maxWidth, maxHeight, child.size);
setBlockSizes(child, db, maxWidth, maxHeight); setBlockSizes(child, db, maxWidth, maxHeight);
// log.debug('abc95 fin 3 Setting size', child.id, maxWidth, maxHeight, child.size);
} }
const columns = block.columns || -1; const columns = block.columns || -1;
@@ -144,28 +130,21 @@ function setBlockSizes(block: Block, db: BlockDB, sieblingWidth = 0, sieblingHei
xSize = columns; xSize = columns;
} }
const w = block.w || 1; const w = block.widthInColumns || 1;
const ySize = Math.ceil(numItems / xSize); const ySize = Math.ceil(numItems / xSize);
let width = xSize * (maxWidth + padding) + padding; let width = xSize * (maxWidth + padding) + padding;
let height = ySize * (maxHeight + padding) + padding; let height = ySize * (maxHeight + padding) + padding;
// If maxWidth // If maxWidth
if (width < sieblingWidth) { if (width < siblingWidth) {
log.debug( log.debug(
'Detected to small siebling: abc95', `Detected to small siebling: abc95 ${block.id} sieblingWidth ${siblingWidth} sieblingHeight ${siblingHeight} width ${width}`
block.id,
'sieblingWidth',
sieblingWidth,
'sieblingHeight',
sieblingHeight,
'width',
width
); );
width = sieblingWidth; width = siblingWidth;
height = sieblingHeight; height = siblingHeight;
const childWidth = (sieblingWidth - xSize * padding - padding) / xSize; const childWidth = (siblingWidth - xSize * padding - padding) / xSize;
const childHeight = (sieblingHeight - ySize * padding - padding) / ySize; const childHeight = (siblingHeight - ySize * padding - padding) / ySize;
log.debug('Size indata abc88', block.id, 'childWidth', childWidth, 'maxWidth', maxWidth); log.debug('Size indata abc88', block.id, 'childWidth', childWidth, 'maxWidth', maxWidth);
log.debug('Size indata abc88', block.id, 'childHeight', childHeight, 'maxHeight', maxHeight); log.debug('Size indata abc88', block.id, 'childHeight', childHeight, 'maxHeight', maxHeight);
log.debug('Size indata abc88 xSize', xSize, 'paddiong', padding); log.debug('Size indata abc88 xSize', xSize, 'paddiong', padding);
@@ -182,17 +161,9 @@ function setBlockSizes(block: Block, db: BlockDB, sieblingWidth = 0, sieblingHei
} }
log.debug( log.debug(
'abc95 (finale calc)', `abc95 (finale calc) ${block.id} xSize ${xSize} ySize ${ySize} columns ${columns}${
block.id, block.children.length
'xSize', } width=${Math.max(width, block.size?.width || 0)}`
xSize,
'ySize',
ySize,
'columns',
columns,
block.children.length,
'width=',
Math.max(width, block.size?.width || 0)
); );
if (width < (block?.size?.width || 0)) { if (width < (block?.size?.width || 0)) {
width = block?.size?.width || 0; width = block?.size?.width || 0;
@@ -229,14 +200,7 @@ function setBlockSizes(block: Block, db: BlockDB, sieblingWidth = 0, sieblingHei
function layoutBlocks(block: Block, db: BlockDB) { function layoutBlocks(block: Block, db: BlockDB) {
log.debug( log.debug(
'abc85 layout blocks (=>layoutBlocks)', `abc85 layout blocks (=>layoutBlocks) ${block.id} x: ${block?.size?.x} y: ${block?.size?.y} width: ${block?.size?.width}`
block.id,
'x:',
block?.size?.x,
'y:',
block?.size?.y,
'width:',
block?.size?.width
); );
const columns = block.columns || -1; const columns = block.columns || -1;
log.debug('layoutBlocks columns abc95', block.id, '=>', columns, block); log.debug('layoutBlocks columns abc95', block.id, '=>', columns, block);
@@ -268,56 +232,22 @@ function layoutBlocks(block: Block, db: BlockDB) {
log.debug('New row in layout for block', block.id, ' and child ', child.id, rowPos); log.debug('New row in layout for block', block.id, ' and child ', child.id, rowPos);
} }
log.debug( log.debug(
'abc89 layout blocks (child) id:', `abc89 layout blocks (child) id: ${child.id} Pos: ${columnPos} (px, py) ${px},${py} (${parent?.size?.x},${parent?.size?.y}) parent: ${parent.id} width: ${width}${padding}`
child.id,
'Pos:',
columnPos,
' (px, py)',
px,
py,
' (',
parent?.size?.x,
',',
parent?.size?.y,
')',
'parent:',
parent.id,
'width:',
width,
padding
); );
if (parent.size) { if (parent.size) {
// child.size.x =
// block.size.x -
// block.size.width / 2 +
// px * (child?.w || 1) * (width + padding) +
// width / 2 +
// padding;
const halfWidth = width / 2; const halfWidth = width / 2;
child.size.x = startingPosX + padding + halfWidth; child.size.x = startingPosX + padding + halfWidth;
log.debug( log.debug(
'abc91 layout blocks (calc) px, py', `abc91 layout blocks (calc) px, pyid:${
'id:', child.id
child.id, } startingPos=X${startingPosX} new startingPosX${
'startingPosX', child.size.x
startingPosX, } ${halfWidth} padding=${padding} width=${width} halfWidth=${halfWidth} => x:${
'new startingPosX', child.size.x
child.size.x + halfWidth, } y:${child.size.y} ${child.widthInColumns} (width * (child?.w || 1)) / 2 ${
'padding', (width * (child?.widthInColumns || 1)) / 2
padding, }`
'width=',
width,
'halfWidth',
halfWidth,
'=>',
'x:',
child.size.x,
'y:',
child.size.y,
child.w,
'(width * (child?.w || 1)) / 2',
(width * (child?.w || 1)) / 2
); );
startingPosX = child.size.x + halfWidth; startingPosX = child.size.x + halfWidth;
@@ -326,21 +256,11 @@ function layoutBlocks(block: Block, db: BlockDB) {
parent.size.y - parent.size.height / 2 + py * (height + padding) + height / 2 + padding; parent.size.y - parent.size.height / 2 + py * (height + padding) + height / 2 + padding;
log.debug( log.debug(
'abc88 layout blocks (calc) px, py', `abc88 layout blocks (calc) px, pyid:${
'id:', child.id
child.id, }startingPosX${startingPosX}${padding}${halfWidth}=>x:${child.size.x}y:${child.size.y}${
'startingPosX', child.widthInColumns
startingPosX, }(width * (child?.w || 1)) / 2${(width * (child?.widthInColumns || 1)) / 2}`
padding,
halfWidth,
'=>',
'x:',
child.size.x,
'y:',
child.size.y,
child.w,
'(width * (child?.w || 1)) / 2',
(width * (child?.w || 1)) / 2
); );
} }
@@ -348,19 +268,12 @@ function layoutBlocks(block: Block, db: BlockDB) {
if (child.children) { if (child.children) {
layoutBlocks(child, db); layoutBlocks(child, db);
} }
columnPos += child?.w || 1; columnPos += child?.widthInColumns || 1;
log.debug('abc88 columnsPos', child, columnPos); log.debug('abc88 columnsPos', child, columnPos);
} }
} }
log.debug( log.debug(
'layout blocks (<==layoutBlocks)', `layout blocks (<==layoutBlocks) ${block.id} x: ${block?.size?.x} y: ${block?.size?.y} width: ${block?.size?.width}`
block.id,
'x:',
block?.size?.x,
'y:',
block?.size?.y,
'width:',
block?.size?.width
); );
} }

View File

@@ -79,12 +79,7 @@ accDescr\s*":"\s* { this.pushState
accDescr\s*"{"\s* { this.pushState("acc_descr_multiline");} accDescr\s*"{"\s* { this.pushState("acc_descr_multiline");}
<acc_descr_multiline>[\}] { this.popState(); } <acc_descr_multiline>[\}] { this.popState(); }
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value"; <acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
"subgraph" return 'subgraph';
"end"\b\s* return 'end';
.*direction\s+TB[^\n]* return 'direction_tb';
.*direction\s+BT[^\n]* return 'direction_bt';
.*direction\s+RL[^\n]* return 'direction_rl';
.*direction\s+LR[^\n]* return 'direction_lr';
// Node end of shape // Node end of shape
<NODE>"(((" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; } <NODE>"(((" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }

View File

@@ -353,7 +353,7 @@ describe('Block diagram', function () {
expect(blocks.length).toBe(2); expect(blocks.length).toBe(2);
const one = blocks[0]; const one = blocks[0];
const two = blocks[1]; const two = blocks[1];
expect(two.w).toBe(2); expect(two.widthInColumns).toBe(2);
}); });
it('empty blocks', async () => { it('empty blocks', async () => {
const str = `block-beta const str = `block-beta

View File

@@ -130,7 +130,11 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
return node; return node;
} }
type IOperation = (elem: any, block: any, db: any) => Promise<void>; type IOperation = (elem: any, block: any, db: any) => Promise<void>;
async function calculateBlockSize(elem: any, block: any, db: any) { async function calculateBlockSize(
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
block: any,
db: any
) {
const node = getNodeFromBlock(block, db, false); const node = getNodeFromBlock(block, db, false);
if (node.type === 'group') { if (node.type === 'group') {
return; return;
@@ -147,9 +151,6 @@ async function calculateBlockSize(elem: any, block: any, db: any) {
export async function insertBlockPositioned(elem: any, block: Block, db: any) { export async function insertBlockPositioned(elem: any, block: Block, db: any) {
const node = getNodeFromBlock(block, db, true); const node = getNodeFromBlock(block, db, true);
// if (node.type === 'composite') {
// return;
// }
// Add the element to the DOM to size it // Add the element to the DOM to size it
const obj = db.getBlock(node.id); const obj = db.getBlock(node.id);
if (obj.type !== 'space') { if (obj.type !== 'space') {
@@ -160,7 +161,7 @@ export async function insertBlockPositioned(elem: any, block: Block, db: any) {
} }
export async function performOperations( export async function performOperations(
elem: ContainerElement, elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
blocks: Block[], blocks: Block[],
db: BlockDB, db: BlockDB,
operation: IOperation operation: IOperation
@@ -173,16 +174,20 @@ export async function performOperations(
} }
} }
export async function calculateBlockSizes(elem: ContainerElement, blocks: Block[], db: BlockDB) { export async function calculateBlockSizes(elem: any, blocks: Block[], db: BlockDB) {
await performOperations(elem, blocks, db, calculateBlockSize); await performOperations(elem, blocks, db, calculateBlockSize);
} }
export async function insertBlocks(elem: ContainerElement, blocks: Block[], db: BlockDB) { export async function insertBlocks(
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
blocks: Block[],
db: BlockDB
) {
await performOperations(elem, blocks, db, insertBlockPositioned); await performOperations(elem, blocks, db, insertBlockPositioned);
} }
export async function insertEdges( export async function insertEdges(
elem: ContainerElement, elem: any,
edges: Block[], edges: Block[],
blocks: Block[], blocks: Block[],
db: BlockDB, db: BlockDB,
@@ -214,9 +219,7 @@ export async function insertEdges(
// elem, e, edge, clusterDb, diagramType, graph; // elem, e, edge, clusterDb, diagramType, graph;
if (edge.start && edge.end) { if (edge.start && edge.end) {
const startBlock = db.getBlock(edge.start); const startBlock = db.getBlock(edge.start);
const startBlock2 = g.node(edge.start);
const endBlock = db.getBlock(edge.end); const endBlock = db.getBlock(edge.end);
const endBlock2 = g.node(edge.end);
if (startBlock?.size && endBlock?.size) { if (startBlock?.size && endBlock?.size) {
const start = startBlock.size; const start = startBlock.size;