#3358 Adding arrows to syntax

This commit is contained in:
Knut Sveidqvist 2023-11-20 14:00:25 +01:00
parent 03c59adaed
commit df858dc7b6
8 changed files with 290 additions and 43 deletions

View File

@ -62,9 +62,17 @@
</style>
</head>
<body>
<pre id="diagram" class="mermaid2">
block-beta
columns 3
space blockArrowId1<["down"]>(down) space
blockArrowId2<["right"]>(right) blockArrowId3<["Sync"]>(x, y) blockArrowId4<["left"]>(left)
space blockArrowId5<["up"]>(up) space
blockArrowId6<["x"]>(x) space blockArrowId7<["y"]>(y)
</pre>
<pre id="diagram" class="mermaid">
block-beta
blockArrowId<["Label"]>(right, down)
A("APA") --> B("GORILLA")
</pre>
<pre id="diagram" class="mermaid2">
block-beta

View File

@ -0,0 +1,218 @@
const expandAndDeduplicateDirections = (directions) => {
const uniqueDirections = new Set();
for (const direction of directions) {
switch (direction) {
case 'x':
uniqueDirections.add('right');
uniqueDirections.add('left');
break;
case 'y':
uniqueDirections.add('up');
uniqueDirections.add('down');
break;
default:
uniqueDirections.add(direction);
break;
}
}
return uniqueDirections;
};
export const getArrowPoints = (directions, bbox, node) => {
const ud = expandAndDeduplicateDirections(directions);
// console.log('block_arrow abc123', node.id, node.directions, ud);
const f = 2;
const h = bbox.height + 2 * node.padding;
const m = h / f;
const w = bbox.width + 2 * m + node.padding;
const p = node.padding / 2;
let points = [];
if (ud.has('right') && ud.has('left') && ud.has('up') && ud.has('down')) {
// SQUARE
points = [
// Bottom
{ x: 0, y: 0 },
{ x: m, y: 0 },
{ x: w / 2, y: 2 * p },
{ x: w - m, y: 0 },
{ x: w, y: 0 },
// Right
{ x: w, y: -h / 3 },
{ x: w + 2 * p, y: -h / 2 },
{ x: w, y: (-2 * h) / 3 },
{ x: w, y: -h },
// Top
{ x: w - m, y: -h },
{ x: w / 2, y: -h - 2 * p },
{ x: m, y: -h },
// Left
{ x: 0, y: -h },
{ x: 0, y: (-2 * h) / 3 },
{ x: -2 * p, y: -h / 2 },
{ x: 0, y: -h / 3 },
];
} else if (ud.has('right') && ud.has('left') && ud.has('up')) {
// RECTANGLE_VERTICAL (Top Open)
points = [
{ x: m, y: 0 },
{ x: w - m, y: 0 },
{ x: w, y: -h / 2 },
{ x: w - m, y: -h },
{ x: m, y: -h },
{ x: 0, y: -h / 2 },
];
} else if (ud.has('right') && ud.has('left') && ud.has('down')) {
// RECTANGLE_VERTICAL (Bottom Open)
points = [
{ x: 0, y: 0 },
{ x: m, y: -h },
{ x: w - m, y: -h },
{ x: w, y: 0 },
];
} else if (ud.has('right') && ud.has('up') && ud.has('down')) {
// RECTANGLE_HORIZONTAL (Right Open)
points = [
{ x: 0, y: 0 },
{ x: w, y: -m },
{ x: w, y: -h + m },
{ x: 0, y: -h },
];
} else if (ud.has('left') && ud.has('up') && ud.has('down')) {
// RECTANGLE_HORIZONTAL (Left Open)
points = [
{ x: w, y: 0 },
{ x: 0, y: -m },
{ x: 0, y: -h + m },
{ x: w, y: -h },
];
} else if (ud.has('right') && ud.has('left')) {
// HORIZONTAL_LINE
points = [
{ x: m, y: 0 },
{ x: m, y: -p },
{ x: w - m, y: -p },
{ x: w - m, y: 0 },
{ x: w, y: -h / 2 },
{ x: w - m, y: -h },
{ x: w - m, y: -h + p },
{ x: m, y: -h + p },
{ x: m, y: -h },
{ x: 0, y: -h / 2 },
];
} else if (ud.has('up') && ud.has('down')) {
// VERTICAL_LINE
points = [
// Bottom center
{ x: w / 2, y: 0 },
// Left pont of bottom arrow
{ x: 0, y: -p },
{ x: m, y: -p },
// Left top over vertical section
{ x: m, y: -h + p },
{ x: 0, y: -h + p },
// Top of arrow
{ x: w / 2, y: -h },
{ x: w, y: -h + p },
// Top of right vertical bar
{ x: w - m, y: -h + p },
{ x: w - m, y: -p },
{ x: w, y: -p },
];
} else if (ud.has('right') && ud.has('up')) {
// ANGLE_RT
points = [
{ x: 0, y: 0 },
{ x: w, y: -m },
{ x: 0, y: -h },
];
} else if (ud.has('right') && ud.has('down')) {
// ANGLE_RB
points = [
{ x: 0, y: 0 },
{ x: w, y: 0 },
{ x: 0, y: -h },
];
} else if (ud.has('left') && ud.has('up')) {
// ANGLE_LT
points = [
{ x: w, y: 0 },
{ x: 0, y: -m },
{ x: w, y: -h },
];
} else if (ud.has('left') && ud.has('down')) {
// ANGLE_LB
points = [
{ x: w, y: 0 },
{ x: 0, y: 0 },
{ x: w, y: -h },
];
} else if (ud.has('right')) {
// ARROW_RIGHT
points = [
{ x: m, y: -p },
{ x: m, y: -p },
{ x: w - m, y: -p },
{ x: w - m, y: 0 },
{ x: w, y: -h / 2 },
{ x: w - m, y: -h },
{ x: w - m, y: -h + p },
// top left corner of arrow
{ x: m, y: -h + p },
{ x: m, y: -h + p },
];
} else if (ud.has('left')) {
// ARROW_LEFT
points = [
{ x: m, y: 0 },
{ x: m, y: -p },
// Two points, the right corners
{ x: w - m, y: -p },
{ x: w - m, y: -h + p },
{ x: m, y: -h + p },
{ x: m, y: -h },
{ x: 0, y: -h / 2 },
];
} else if (ud.has('up')) {
// ARROW_TOP
points = [
// Bottom center
{ x: m, y: -p },
// Left top over vertical section
{ x: m, y: -h + p },
{ x: 0, y: -h + p },
// Top of arrow
{ x: w / 2, y: -h },
{ x: w, y: -h + p },
// Top of right vertical bar
{ x: w - m, y: -h + p },
{ x: w - m, y: -p },
];
} else if (ud.has('down')) {
// ARROW_BOTTOM
points = [
// Bottom center
{ x: w / 2, y: 0 },
// Left pont of bottom arrow
{ x: 0, y: -p },
{ x: m, y: -p },
// Left top over vertical section
{ x: m, y: -h + p },
{ x: w - m, y: -h + p },
{ x: w - m, y: -p },
{ x: w, y: -p },
];
} else {
// POINT
points = [{ x: 0, y: 0 }];
}
return points;
};

View File

@ -7,6 +7,7 @@ import createLabel from './createLabel.js';
import note from './shapes/note.js';
import { parseMember } from '../diagrams/class/svgDraw.js';
import { evaluate } from '../diagrams/common/common.js';
import { getArrowPoints } from './blockArrowHelper.js';
const question = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
@ -14,6 +15,7 @@ const question = async (parent, node) => {
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
const s = w + h;
const points = [
{ x: s / 2, y: 0 },
{ x: s, y: -s / 2 },
@ -95,21 +97,33 @@ const hexagon = async (parent, node) => {
return shapeSvg;
};
const block_arrow = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const f = 2;
const h = bbox.height + node.padding;
const h = bbox.height + 2 * node.padding;
const m = h / f;
const w = bbox.width + 2 * m + node.padding;
const points = [
{ x: m, y: 0 },
{ x: w - m, y: 0 },
{ x: w, y: -h / 2 },
{ x: w - m, y: -h },
{ x: m, y: -h },
{ x: 0, y: -h / 2 },
];
const p = node.padding / 2;
//
// const points = [
// { x: m, y: 0 },
// { x: m, y: -p },
// { x: w - m, y: -p },
// { x: w - m, y: 0 },
// // Right point
// { x: w, y: -h / 2 },
// // Point moving left and up from right point
// { x: w - m, y: -h },
// { x: w - m, y: -h + p },
// { x: m, y: -h + p },
// { x: m, y: -h },
// { x: 0, y: -h / 2 },
// ];
const points = getArrowPoints(node.directions, bbox, node);
const hex = insertPolygonShape(shapeSvg, w, h, points);
hex.attr('style', node.style);
@ -1085,6 +1099,9 @@ export const insertNode = async (elem, node, dir) => {
if (node.class) {
el.attr('class', 'node default ' + node.class);
}
// MC Special
newEl.attr('data-node', 'true');
newEl.attr('data-id', node.id);
nodeElems[node.id] = newEl;

View File

@ -66,9 +66,8 @@ const clear = (): void => {
};
type ITypeStr2Type = (typeStr: string) => BlockType;
export function typeStr2Type(typeStr: string) {
export function typeStr2Type(typeStr: string): BlockType {
log.debug('typeStr2Type', typeStr);
// TODO: add all types
switch (typeStr) {
case '[]':
return 'square';
@ -80,7 +79,7 @@ export function typeStr2Type(typeStr: string) {
case '>]':
return 'rect_left_inv_arrow';
case '{}':
return 'question';
return 'diamond';
case '{{}}':
return 'hexagon';
case '([])':
@ -115,9 +114,10 @@ export const generateId = () => {
type ISetHierarchy = (block: Block[]) => void;
const setHierarchy = (block: Block[]): void => {
// log.debug('The hierarchy', JSON.stringify(block, null, 2));
rootBlock.children = block;
populateBlockDatabase(block, rootBlock);
log.debug('The hierarchy', JSON.stringify(rootBlock, null, 2));
// log.debug('The hierarchy', JSON.stringify(rootBlock, null, 2));
blocks = rootBlock.children;
};

View File

@ -44,8 +44,8 @@ CRLF \u000D\u000A
<md_string>[^`"]+ { return "MD_STR";}
<md_string>[`]["] { this.popState();}
["] this.pushState("string");
<string>["] { log.debug('LEX: POPPING STR:', yytext);this.popState();}
<string>[^"]* { log.debug('LEX: STR ebd:', yytext); return "STR";}
<string>["] { yy.getLogger().debug('LEX: POPPING STR:', yytext);this.popState();}
<string>[^"]* { yy.getLogger().debug('LEX: STR ebd:', yytext); return "STR";}
space[:]\d+ { yytext = yytext.replace(/space\:/,'');yy.getLogger().info('SPACE NUM (LEX)', yytext); return 'SPACE_BLOCK'; }
space { yytext = '1'; yy.getLogger().info('COLUMNS (LEX)', yytext); return 'SPACE_BLOCK'; }
"style" return 'STYLE';
@ -86,7 +86,7 @@ accDescr\s*"{"\s* { this.pushState("acc_descr_mul
"[/" { this.pushState('NODE');return 'NODE_DSTART'; }
"[\\" { this.pushState('NODE');return 'NODE_DSTART'; }
"<[" { this.pushState('BLOCK_ARROW');log.debug('LEX ARR START');return 'BLOCK_ARROW_START'; }
"<[" { this.pushState('BLOCK_ARROW');yy.getLogger().debug('LEX ARR START');return 'BLOCK_ARROW_START'; }
[^\(\[\n\-\)\{\}\s\<]+ { yy.getLogger().info('Lex: NODE_ID', yytext);return 'NODE_ID'; }
<<EOF>> { yy.getLogger().info('Lex: EOF', yytext);return 'EOF'; }
@ -98,8 +98,8 @@ accDescr\s*"{"\s* { this.pushState("acc_descr_mul
<md_string>[`]["] { this.popState();}
<NODE>["] { yy.getLogger().info('Lex: Starting string');this.pushState("string");}
<BLOCK_ARROW>["] { yy.getLogger().info('LEX ARR: Starting string');this.pushState("string");}
<string>[^"]+ { log.debug('LEX: NODE_DESCR:', yytext); return "NODE_DESCR";}
<string>["] {log.debug('LEX POPPING');this.popState();}
<string>[^"]+ { yy.getLogger().debug('LEX: NODE_DESCR:', yytext); return "NODE_DESCR";}
<string>["] {yy.getLogger().debug('LEX POPPING');this.popState();}
// Node end of shape
<NODE>\]\> { this.popState();yy.getLogger().info('Lex: ]>'); return "NODE_DEND"; }
@ -116,14 +116,14 @@ accDescr\s*"{"\s* { this.pushState("acc_descr_mul
<NODE>"/]" { this.popState();yy.getLogger().info('Lex: /]'); return "NODE_DEND"; }
<NODE>")]" { this.popState();yy.getLogger().info('Lex: )]'); return "NODE_DEND"; }
<BLOCK_ARROW>"]>"\s*"(" { log.debug('Lex: =>BAE'); this.pushState('ARROW_DIR'); }
<ARROW_DIR>","?right\s* { log.debug('Lex (right): dir:',yytext);return "DIR"; }
<ARROW_DIR>","?left\s* { log.debug('Lex (left):',yytext);return "DIR"; }
<ARROW_DIR>","?x\s* { log.debug('Lex (x):',yytext); return "DIR"; }
<ARROW_DIR>","?y\s* { log.debug('Lex (y):',yytext); return "DIR"; }
<ARROW_DIR>","?up\s* { log.debug('Lex (up):',yytext); return "DIR"; }
<ARROW_DIR>","?\s*down\s* { yytext = yytext.replace(/^,\s*/, ''); log.debug('Lex (down):',yytext); return "DIR"; }
<ARROW_DIR>")"\s* { yytext=']>';log.debug('Lex (ARROW_DIR end):',yytext);this.popState();this.popState();return "BLOCK_ARROW_END"; }
<BLOCK_ARROW>"]>"\s*"(" { yy.getLogger().debug('Lex: =>BAE'); this.pushState('ARROW_DIR'); }
<ARROW_DIR>","?\s*right\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (right): dir:',yytext);return "DIR"; }
<ARROW_DIR>","?\s*left\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (left):',yytext);return "DIR"; }
<ARROW_DIR>","?\s*x\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (x):',yytext); return "DIR"; }
<ARROW_DIR>","?\s*y\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (y):',yytext); return "DIR"; }
<ARROW_DIR>","?\s*up\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (up):',yytext); return "DIR"; }
<ARROW_DIR>","?\s*down\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (down):',yytext); return "DIR"; }
<ARROW_DIR>")"\s* { yytext=']>';yy.getLogger().debug('Lex (ARROW_DIR end):',yytext);this.popState();this.popState();return "BLOCK_ARROW_END"; }
// Edges
\s*[xo<]?\-\-+[-xo>]\s* { yy.getLogger().info('Lex: LINK', '#'+yytext+'#'); return 'LINK'; }
@ -157,7 +157,7 @@ seperator
;
start: BLOCK_DIAGRAM_KEY document EOF
{ yy.setHierarchy($2); }
{ yy.getLogger().info("Rule: hierarchy: ", $2); yy.setHierarchy($2); }
;
@ -171,8 +171,8 @@ stop
//array of statements
document
: statement { yy.getLogger().info("Rule: statement: ", $1); $$ = [$1]; }
| statement document { yy.getLogger().info("Rule: document statement: ", $1, $2); $$ = [$1].concat($2); }
: statement { yy.getLogger().info("Rule: statement: ", $1); typeof $1.length === 'number'?$$ = $1:$$ = [$1]; }
| statement document { yy.getLogger().info("Rule: statement #2: ", $1); $$ = [$1].concat($2); }
;
link
@ -191,12 +191,12 @@ statement
;
nodeStatement
: nodeStatement link node { yy.getLogger().info('Rule: nodeStatement (nodeStatement link node) '); $$ = {id: $1.id}; }
| node { yy.getLogger().info('Rule: nodeStatement (node) ', $1); $$ = {id: $1.id, label: $1.label, type: yy.typeStr2Type($1.typeStr)}; }
: nodeStatement link node { yy.getLogger().info('Rule: (nodeStatement link node) ', $1, $2, $3); $$ = [{id: $1.id, label: $1.label, type:$1.type, directions: $1.directions}, {id: $3.id, label: $3.label, type: yy.typeStr2Type($3.typeStr), directions: $3.directions}]; }
| node { yy.getLogger().info('Rule: nodeStatement (node) ', $1); $$ = {id: $1.id, label: $1.label, type: yy.typeStr2Type($1.typeStr), directions: $1.directions}; }
;
columnsStatement
: COLUMNS { yy.getLogger().info("COLUMNS: ", $1); $$ = {type: 'column-setting', columns: $1 === 'auto'?-1:parseInt($1) } }
: COLUMNS { yy.getLogger().info('APA123', this? this:'na'); yy.getLogger().info("COLUMNS: ", $1); $$ = {type: 'column-setting', columns: $1 === 'auto'?-1:parseInt($1) } }
;
blockStatement
@ -207,10 +207,11 @@ blockStatement
node
: NODE_ID
{ yy.getLogger().info("Rule: node (NODE_ID seperator): ", $1); $$ = { id: $1 }; }
|NODE_ID nodeShapeNLabel
{ yy.getLogger().info("Rule: node (NODE_ID nodeShapeNLabel seperator): ", $1, $2); $$ = { id: $1, label: $2.label, typeStr: $2.typeStr };}
// |nodeShapeNLabel seperator
// { yy.getLogger().info("Rule: node (nodeShapeNLabel seperator): ", $1, $2, $3); }
| NODE_ID nodeShapeNLabel
{
yy.getLogger().info("Rule: node (NODE_ID nodeShapeNLabel seperator): ", $1, $2);
$$ = { id: $1, label: $2.label, typeStr: $2.typeStr, directions: $2.directions };
}
;
dirList: DIR { yy.getLogger().info("Rule: dirList: ", $1); $$ = [$1]; }
@ -221,7 +222,7 @@ nodeShapeNLabel
: NODE_DSTART STR NODE_DEND
{ yy.getLogger().info("Rule: nodeShapeNLabel: ", $1, $2, $3); $$ = { typeStr: $1 + $3, label: $2 }; }
| BLOCK_ARROW_START STR dirList BLOCK_ARROW_END
{ yy.getLogger().info("Rule: BLOCK_ARROW nodeShapeNLabel: ", $1, $2, $3, $4); $$ = { typeStr: $1 + $4, label: $2, directions: $3}; }
{ yy.getLogger().info("Rule: BLOCK_ARROW nodeShapeNLabel: ", $1, $2, " #3:",$3, $4); $$ = { typeStr: $1 + $4, label: $2, directions: $3}; }
;
%%

View File

@ -114,6 +114,7 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
class: classStr,
style: styles.style,
id: vertex.id,
directions: vertex.directions,
// link: vertex.link,
// linkTarget: vertex.linkTarget,
// tooltip: diagObj.db.getTooltip(vertex.id) || '',

View File

@ -360,8 +360,10 @@ export const getClasses = function (text, diagObj) {
*
* @param text
* @param id
* @param _version
* @param diagObj
*/
// [MermaidChart: 33a97b35-1f95-4ce9-81b5-3038669bc170]
export const draw = async function (text, id, _version, diagObj) {
log.info('Drawing flowchart');
diagObj.db.clear();

View File

@ -332,7 +332,7 @@ spaceList
statement
: verticeStatement separator
{ /* console.warn('finat vs', $1.nodes); */ $$=$1.nodes}
{ $$=$1.nodes}
| styleStatement separator
{$$=[];}
| linkStyleStatement separator
@ -359,9 +359,9 @@ statement
separator: NEWLINE | SEMI | EOF ;
verticeStatement: verticeStatement link node
{ /* console.warn('vs',$1.stmt,$3); */ yy.addLink($1.stmt,$3,$2); $$ = { stmt: $3, nodes: $3.concat($1.nodes) } }
{/* console.warn('vs',$1.stmt,$3); */ yy.addLink($1.stmt,$3,$2); $$ = { stmt: $3, nodes: $3.concat($1.nodes) } }
| verticeStatement link node spaceList
{ /* console.warn('vs',$1.stmt,$3); */ yy.addLink($1.stmt,$3,$2); $$ = { stmt: $3, nodes: $3.concat($1.nodes) } }
|node spaceList {/*console.warn('noda', $1);*/ $$ = {stmt: $1, nodes:$1 }}
@ -377,7 +377,7 @@ node: styledVertex
styledVertex: vertex
{ /* console.warn('nod', $1); */ $$ = $1;}
| vertex STYLE_SEPARATOR idString
{$$ = $1;yy.setClass($1,$3)}
{ $$ = $1;yy.setClass($1,$3)}
;
vertex: idString SQS text SQE