diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 315c33b21..ab5c0aa3c 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -62,9 +62,17 @@
++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) +
block-beta - blockArrowId<["Label"]>(right, down) + A("APA") --> B("GORILLA")
block-beta diff --git a/packages/mermaid/src/dagre-wrapper/blockArrowHelper.js b/packages/mermaid/src/dagre-wrapper/blockArrowHelper.js new file mode 100644 index 000000000..60ff77a57 --- /dev/null +++ b/packages/mermaid/src/dagre-wrapper/blockArrowHelper.js @@ -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; +}; diff --git a/packages/mermaid/src/dagre-wrapper/nodes.js b/packages/mermaid/src/dagre-wrapper/nodes.js index 41578f584..afe1b3a3f 100644 --- a/packages/mermaid/src/dagre-wrapper/nodes.js +++ b/packages/mermaid/src/dagre-wrapper/nodes.js @@ -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; diff --git a/packages/mermaid/src/diagrams/block/blockDB.ts b/packages/mermaid/src/diagrams/block/blockDB.ts index 3cc9ec11d..86f0b78bb 100644 --- a/packages/mermaid/src/diagrams/block/blockDB.ts +++ b/packages/mermaid/src/diagrams/block/blockDB.ts @@ -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; }; diff --git a/packages/mermaid/src/diagrams/block/parser/block.jison b/packages/mermaid/src/diagrams/block/parser/block.jison index 91d26faf3..448ce0f41 100644 --- a/packages/mermaid/src/diagrams/block/parser/block.jison +++ b/packages/mermaid/src/diagrams/block/parser/block.jison @@ -44,8 +44,8 @@ CRLF \u000D\u000A[^`"]+ { return "MD_STR";} [`]["] { this.popState();} ["] this.pushState("string"); - ["] { log.debug('LEX: POPPING STR:', yytext);this.popState();} - [^"]* { log.debug('LEX: STR ebd:', yytext); return "STR";} + ["] { yy.getLogger().debug('LEX: POPPING STR:', yytext);this.popState();} + [^"]* { 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'; } < > { yy.getLogger().info('Lex: EOF', yytext);return 'EOF'; } @@ -98,8 +98,8 @@ accDescr\s*"{"\s* { this.pushState("acc_descr_mul [`]["] { this.popState();} ["] { yy.getLogger().info('Lex: Starting string');this.pushState("string");} ["] { yy.getLogger().info('LEX ARR: Starting string');this.pushState("string");} - [^"]+ { log.debug('LEX: NODE_DESCR:', yytext); return "NODE_DESCR";} - ["] {log.debug('LEX POPPING');this.popState();} + [^"]+ { yy.getLogger().debug('LEX: NODE_DESCR:', yytext); return "NODE_DESCR";} + ["] {yy.getLogger().debug('LEX POPPING');this.popState();} // Node end of shape \]\> { this.popState();yy.getLogger().info('Lex: ]>'); return "NODE_DEND"; } @@ -116,14 +116,14 @@ accDescr\s*"{"\s* { this.pushState("acc_descr_mul "/]" { this.popState();yy.getLogger().info('Lex: /]'); return "NODE_DEND"; } ")]" { this.popState();yy.getLogger().info('Lex: )]'); return "NODE_DEND"; } - "]>"\s*"(" { log.debug('Lex: =>BAE'); this.pushState('ARROW_DIR'); } - ","?right\s* { log.debug('Lex (right): dir:',yytext);return "DIR"; } - ","?left\s* { log.debug('Lex (left):',yytext);return "DIR"; } - ","?x\s* { log.debug('Lex (x):',yytext); return "DIR"; } - ","?y\s* { log.debug('Lex (y):',yytext); return "DIR"; } - ","?up\s* { log.debug('Lex (up):',yytext); return "DIR"; } - ","?\s*down\s* { yytext = yytext.replace(/^,\s*/, ''); log.debug('Lex (down):',yytext); return "DIR"; } - ")"\s* { yytext=']>';log.debug('Lex (ARROW_DIR end):',yytext);this.popState();this.popState();return "BLOCK_ARROW_END"; } + "]>"\s*"(" { yy.getLogger().debug('Lex: =>BAE'); this.pushState('ARROW_DIR'); } + ","?\s*right\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (right): dir:',yytext);return "DIR"; } + ","?\s*left\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (left):',yytext);return "DIR"; } + ","?\s*x\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (x):',yytext); return "DIR"; } + ","?\s*y\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (y):',yytext); return "DIR"; } + ","?\s*up\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (up):',yytext); return "DIR"; } + ","?\s*down\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (down):',yytext); return "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}; } ; %% diff --git a/packages/mermaid/src/diagrams/block/renderHelpers.ts b/packages/mermaid/src/diagrams/block/renderHelpers.ts index 142de0c5c..125cd2997 100644 --- a/packages/mermaid/src/diagrams/block/renderHelpers.ts +++ b/packages/mermaid/src/diagrams/block/renderHelpers.ts @@ -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) || '', diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js index 23f94942c..a887511d5 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js @@ -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(); diff --git a/packages/mermaid/src/diagrams/flowchart/parser/flow.jison b/packages/mermaid/src/diagrams/flowchart/parser/flow.jison index 70fb49162..1957b4555 100644 --- a/packages/mermaid/src/diagrams/flowchart/parser/flow.jison +++ b/packages/mermaid/src/diagrams/flowchart/parser/flow.jison @@ -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