## Work in progress.
Implemented directives per PR review comment: %%{directive: json-encoded-arg-string}%% example: %%{init: { 'logLevel': 0, 'theme': 'dark' }}%% Also changed wrap and config to directives: %%{wrap}%% %%{config: { 'fontSize': 18 }}%%
This commit is contained in:
parent
dba617a7fe
commit
04b4da0c75
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -506,8 +506,11 @@ mermaid.sequenceConfig = {
|
|||
| bottomMarginAdj | Adjusts how far down the graph ended. Wide borders styles with css could generate unwanted clipping which is why this config param exists. | 1 |
|
||||
| actorFontSize | Sets the font size for the actor's description | 14 |
|
||||
| actorFontFamily | Sets the font family for the actor's description | "Open-Sans", "sans-serif" |
|
||||
| actorFontWeight | Sets the font weight for the actor's description | "Open-Sans", "sans-serif" |
|
||||
| noteFontSize | Sets the font size for actor-attached notes | 14 |
|
||||
| noteFontFamily | Sets the font family for actor-attached notes | "trebuchet ms", verdana, arial |
|
||||
| noteFontWeight | Sets the font weight for actor-attached notes | "trebuchet ms", verdana, arial |
|
||||
| noteAlign | Sets the text alignment for text in actor-attached notes | center |
|
||||
| messageFontSize | Sets the font size for actor<->actor messages | 16 |
|
||||
| messageFontFamily | Sets the font family for actor<->actor messages | "trebuchet ms", verdana, arial |
|
||||
| messageFontWeight | Sets the font weight for actor<->actor messages | "trebuchet ms", verdana, arial |
|
||||
|
|
|
@ -16,60 +16,62 @@
|
|||
%x ID
|
||||
%x ALIAS
|
||||
|
||||
// Directive states
|
||||
%x OPEN_DIRECTIVE
|
||||
%x IN_DIRECTIVE
|
||||
|
||||
// A special state for grabbing text up to the first comment/newline
|
||||
%x LINE
|
||||
|
||||
%%
|
||||
|
||||
[\n]+ return 'NL';
|
||||
\s+ /* skip all whitespace */
|
||||
<ID,ALIAS,LINE>((?!\n)\s)+ /* skip same-line whitespace */
|
||||
<INITIAL,ID,ALIAS,LINE>\#[^\n]* /* skip comments */
|
||||
\%%[^\n]* /* skip comments */
|
||||
"participant" { this.begin('ID'); return 'participant'; }
|
||||
<ID>[^\->:\n,;]+?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NL'; }
|
||||
"loop" { this.begin('LINE'); return 'loop'; }
|
||||
"rect" { this.begin('LINE'); return 'rect'; }
|
||||
"opt" { this.begin('LINE'); return 'opt'; }
|
||||
"alt" { this.begin('LINE'); return 'alt'; }
|
||||
"else" { this.begin('LINE'); return 'else'; }
|
||||
"par" { this.begin('LINE'); return 'par'; }
|
||||
"and" { this.begin('LINE'); return 'and'; }
|
||||
<LINE>[^#\n;]* { this.popState(); return 'restOfLine'; }
|
||||
"end" return 'end';
|
||||
"left of" return 'left_of';
|
||||
"right of" return 'right_of';
|
||||
"over" return 'over';
|
||||
"note" return 'note';
|
||||
"activate" { this.begin('ID'); return 'activate'; }
|
||||
"deactivate" { this.begin('ID'); return 'deactivate'; }
|
||||
"title" return 'title';
|
||||
"sequenceDiagram" return 'SD';
|
||||
"autonumber" return 'autonumber';
|
||||
"init" return 'INIT';
|
||||
"initialize" return 'INIT';
|
||||
"conf" return 'conf';
|
||||
"config" return 'conf';
|
||||
"configure" return 'conf';
|
||||
"configuration" return 'conf';
|
||||
"wrap" return 'wrap';
|
||||
"nowrap" return 'nowrap';
|
||||
"," return ',';
|
||||
";" return 'NL';
|
||||
[^\+\->:\n,;]+ { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
"->>" return 'SOLID_ARROW';
|
||||
"-->>" return 'DOTTED_ARROW';
|
||||
"->" return 'SOLID_OPEN_ARROW';
|
||||
"-->" return 'DOTTED_OPEN_ARROW';
|
||||
\-[x] return 'SOLID_CROSS';
|
||||
\-\-[x] return 'DOTTED_CROSS';
|
||||
":"[^#\n;]+ return 'TXT';
|
||||
"+" return '+';
|
||||
"-" return '-';
|
||||
<<EOF>> return 'NL';
|
||||
. return 'INVALID';
|
||||
\%\%\{ { this.begin('OPEN_DIRECTIVE'); return 'open_directive'; }
|
||||
<OPEN_DIRECTIVE>(?!\}\%\%)(?:\w+)\s*[:]?\s*(?:.*?)?(?=\}\%\%) { this.popState(); return 'IN_DIRECTIVE'; }
|
||||
\}\%\% { this.popState(); return 'close_directive'; }
|
||||
"close_directive" return 'NL';
|
||||
"open_directive" return 'NL';
|
||||
[\n]+ return 'NL';
|
||||
\s+ /* skip all whitespace */
|
||||
<ID,ALIAS,LINE>((?!\n)\s)+ /* skip same-line whitespace */
|
||||
<INITIAL,ID,ALIAS,LINE,IN_DIRECTIVE,OPEN_DIRECTIVE>\#[^\n]* /* skip comments */
|
||||
\%%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
"participant" { this.begin('ID'); return 'participant'; }
|
||||
<ID>[^\->:\n,;]+?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NL'; }
|
||||
"loop" { this.begin('LINE'); return 'loop'; }
|
||||
"rect" { this.begin('LINE'); return 'rect'; }
|
||||
"opt" { this.begin('LINE'); return 'opt'; }
|
||||
"alt" { this.begin('LINE'); return 'alt'; }
|
||||
"else" { this.begin('LINE'); return 'else'; }
|
||||
"par" { this.begin('LINE'); return 'par'; }
|
||||
"and" { this.begin('LINE'); return 'and'; }
|
||||
<LINE>(?:[:]?(?:no)?wrap:)?[^#\n;]* { this.popState(); return 'restOfLine'; }
|
||||
"end" return 'end';
|
||||
"left of" return 'left_of';
|
||||
"right of" return 'right_of';
|
||||
"over" return 'over';
|
||||
"note" return 'note';
|
||||
"activate" { this.begin('ID'); return 'activate'; }
|
||||
"deactivate" { this.begin('ID'); return 'deactivate'; }
|
||||
"title" return 'title';
|
||||
"sequenceDiagram" return 'SD';
|
||||
"autonumber" return 'autonumber';
|
||||
"," return ',';
|
||||
";" return 'NL';
|
||||
[^\+\->:\n,;]+ { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
"->>" return 'SOLID_ARROW';
|
||||
"-->>" return 'DOTTED_ARROW';
|
||||
"->" return 'SOLID_OPEN_ARROW';
|
||||
"-->" return 'DOTTED_OPEN_ARROW';
|
||||
\-[x] return 'SOLID_CROSS';
|
||||
\-\-[x] return 'DOTTED_CROSS';
|
||||
":"(?:(?:no)?wrap:)?[^#\n;]+ return 'TXT';
|
||||
"+" return '+';
|
||||
"-" return '-';
|
||||
<<EOF>> return 'NL';
|
||||
. return 'INVALID';
|
||||
|
||||
/lex
|
||||
|
||||
|
@ -82,7 +84,7 @@
|
|||
start
|
||||
: SPACE start
|
||||
| NL start
|
||||
| INIT text3 start
|
||||
| directive start
|
||||
| SD document { yy.apply($2);return $2; }
|
||||
;
|
||||
|
||||
|
@ -97,37 +99,39 @@ line
|
|||
| NL { $$=[]; }
|
||||
;
|
||||
|
||||
directive
|
||||
: open_directive textDirective close_directive { yy.handleDirective($2); }
|
||||
;
|
||||
|
||||
statement
|
||||
: 'participant' actor 'AS' restOfLine 'NL' {$2.description=$4; $$=$2;}
|
||||
: 'participant' actor 'AS' restOfLine 'NL' {$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant' actor 'NL' {$$=$2;}
|
||||
| signal 'NL'
|
||||
| autonumber {yy.enableSequenceNumbers()}
|
||||
| wrap {yy.enableWrap()}
|
||||
| nowrap {yy.disableWrap()}
|
||||
| directive 'NL'
|
||||
| 'activate' actor 'NL' {$$={type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $2};}
|
||||
| 'deactivate' actor 'NL' {$$={type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $2};}
|
||||
| note_statement 'NL'
|
||||
| conf text3 'NL' {$$=[{type:'config', config:$2}]}
|
||||
| title text2 'NL' {$$=[{type:'setTitle', text:$2}]}
|
||||
| 'loop' restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'loopStart', loopText:$2, signalType: yy.LINETYPE.LOOP_START});
|
||||
$3.unshift({type: 'loopStart', loopText:yy.parseMessage($2), signalType: yy.LINETYPE.LOOP_START});
|
||||
$3.push({type: 'loopEnd', loopText:$2, signalType: yy.LINETYPE.LOOP_END});
|
||||
$$=$3;}
|
||||
| 'rect' restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'rectStart', color:$2, signalType: yy.LINETYPE.RECT_START });
|
||||
$3.push({type: 'rectEnd', color:$2, signalType: yy.LINETYPE.RECT_END });
|
||||
$3.unshift({type: 'rectStart', color:yy.parseMessage($2), signalType: yy.LINETYPE.RECT_START });
|
||||
$3.push({type: 'rectEnd', color:yy.parseMessage($2), signalType: yy.LINETYPE.RECT_END });
|
||||
$$=$3;}
|
||||
| opt restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'optStart', optText:$2, signalType: yy.LINETYPE.OPT_START});
|
||||
$3.push({type: 'optEnd', optText:$2, signalType: yy.LINETYPE.OPT_END});
|
||||
$3.unshift({type: 'optStart', optText:yy.parseMessage($2), signalType: yy.LINETYPE.OPT_START});
|
||||
$3.push({type: 'optEnd', optText:yy.parseMessage($2), signalType: yy.LINETYPE.OPT_END});
|
||||
$$=$3;}
|
||||
| alt restOfLine else_sections end
|
||||
{
|
||||
// Alt start
|
||||
$3.unshift({type: 'altStart', altText:$2, signalType: yy.LINETYPE.ALT_START});
|
||||
$3.unshift({type: 'altStart', altText:yy.parseMessage($2), signalType: yy.LINETYPE.ALT_START});
|
||||
// Content in alt is already in $3
|
||||
// End
|
||||
$3.push({type: 'altEnd', signalType: yy.LINETYPE.ALT_END});
|
||||
|
@ -135,7 +139,7 @@ statement
|
|||
| par restOfLine par_sections end
|
||||
{
|
||||
// Parallel start
|
||||
$3.unshift({type: 'parStart', parText:$2, signalType: yy.LINETYPE.PAR_START});
|
||||
$3.unshift({type: 'parStart', parText:yy.parseMessage($2), signalType: yy.LINETYPE.PAR_START});
|
||||
// Content in par is already in $3
|
||||
// End
|
||||
$3.push({type: 'parEnd', signalType: yy.LINETYPE.PAR_END});
|
||||
|
@ -145,13 +149,13 @@ statement
|
|||
par_sections
|
||||
: document
|
||||
| document and restOfLine par_sections
|
||||
{ $$ = $1.concat([{type: 'and', parText:$3, signalType: yy.LINETYPE.PAR_AND}, $4]); }
|
||||
{ $$ = $1.concat([{type: 'and', parText:yy.parseMessage($3), signalType: yy.LINETYPE.PAR_AND}, $4]); }
|
||||
;
|
||||
|
||||
else_sections
|
||||
: document
|
||||
| document else restOfLine else_sections
|
||||
{ $$ = $1.concat([{type: 'else', altText:$3, signalType: yy.LINETYPE.ALT_ELSE}, $4]); }
|
||||
{ $$ = $1.concat([{type: 'else', altText:yy.parseMessage($3), signalType: yy.LINETYPE.ALT_ELSE}, $4]); }
|
||||
;
|
||||
|
||||
note_statement
|
||||
|
@ -207,8 +211,23 @@ signaltype
|
|||
| DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; }
|
||||
;
|
||||
|
||||
text2: TXT {$$ = $1.substring(1).trim().replace(/\\n/gm, "\n");} ;
|
||||
text2
|
||||
: TXT {$$ = yy.parseMessage($1.trim().substring(1)) } ;
|
||||
|
||||
text3: TXT {$$ = JSON.parse($1.substring(1).trim().replace(/\\n/gm, "\n").replace(/'/gm, "\""));} ;
|
||||
text3
|
||||
: TXT {$$ = JSON.parse($1.substring(1).trim().replace(/\\n/gm, "\n").replace(/'/gm, "\""));} ;
|
||||
|
||||
textDirective
|
||||
: IN_DIRECTIVE
|
||||
{
|
||||
$1 = $1.trim().replace(/'/gm, '"');
|
||||
if (/(\w+)[:]?\s*(\{.*}(?!%%))?/.test($1)) {
|
||||
$1 = $1.match(/(\w+)[:]?\s*(\{.*}(?!%%))?/);
|
||||
$$ = { type: $1[1], args: $1[2] !== undefined ? JSON.parse($1[2]) : null };
|
||||
} else {
|
||||
$$ = { type: $1, args: null };
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
import { logger } from '../../logger';
|
||||
import { getConfig, setConfig } from '../../config';
|
||||
import mermaidAPI from '../../mermaidAPI';
|
||||
|
||||
let prevActor = undefined;
|
||||
let actors = {};
|
||||
let messages = [];
|
||||
const notes = [];
|
||||
let title = '';
|
||||
let titleWrapped = false;
|
||||
let sequenceNumbersEnabled = false;
|
||||
let wrapEnabled = false;
|
||||
let configUpdated = false;
|
||||
|
||||
export const handleDirective = function(directive) {
|
||||
switch (directive.type) {
|
||||
case 'init':
|
||||
case 'initialize':
|
||||
mermaidAPI.reinitialize(directive.args);
|
||||
break;
|
||||
case 'config':
|
||||
updateConfig(directive.args);
|
||||
break;
|
||||
case 'wrap':
|
||||
wrapEnabled = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export const addActor = function(id, name, description) {
|
||||
// Don't allow description nulling
|
||||
|
@ -15,9 +33,16 @@ export const addActor = function(id, name, description) {
|
|||
if (old && name === old.name && description == null) return;
|
||||
|
||||
// Don't allow null descriptions, either
|
||||
if (description == null) description = name;
|
||||
if (description == null || description.text == null) {
|
||||
description = { text: name, wrap: null };
|
||||
}
|
||||
|
||||
actors[id] = { name: name, description: description, prevActor: prevActor };
|
||||
actors[id] = {
|
||||
name: name,
|
||||
description: description.text,
|
||||
wrap: (description.wrap === null && autoWrap()) || !!description.wrap,
|
||||
prevActor: prevActor
|
||||
};
|
||||
if (prevActor && actors[prevActor]) {
|
||||
actors[prevActor].nextActor = id;
|
||||
}
|
||||
|
@ -26,7 +51,7 @@ export const addActor = function(id, name, description) {
|
|||
};
|
||||
|
||||
const activationCount = part => {
|
||||
let i = 0;
|
||||
let i;
|
||||
let count = 0;
|
||||
for (i = 0; i < messages.length; i++) {
|
||||
// console.warn(i, messages[i]);
|
||||
|
@ -45,12 +70,27 @@ const activationCount = part => {
|
|||
};
|
||||
|
||||
export const addMessage = function(idFrom, idTo, message, answer) {
|
||||
messages.push({ from: idFrom, to: idTo, message: message, answer: answer });
|
||||
messages.push({
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
|
||||
answer: answer
|
||||
});
|
||||
};
|
||||
|
||||
export const addSignal = function(idFrom, idTo, message, messageType) {
|
||||
export const addSignal = function(idFrom, idTo, message = { text: null, wrap: null }, messageType) {
|
||||
logger.debug(
|
||||
'Adding message from=' + idFrom + ' to=' + idTo + ' message=' + message + ' type=' + messageType
|
||||
'Adding message from=' +
|
||||
idFrom +
|
||||
' to=' +
|
||||
idTo +
|
||||
' message=' +
|
||||
message.text +
|
||||
' wrap=' +
|
||||
message.wrap +
|
||||
' type=' +
|
||||
messageType
|
||||
);
|
||||
|
||||
if (messageType === LINETYPE.ACTIVE_END) {
|
||||
|
@ -58,7 +98,7 @@ export const addSignal = function(idFrom, idTo, message, messageType) {
|
|||
logger.debug('Adding message from=', messages, cnt);
|
||||
if (cnt < 1) {
|
||||
// Bail out as there is an activation signal from an inactive participant
|
||||
var error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')');
|
||||
let error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')');
|
||||
error.hash = {
|
||||
text: '->>-',
|
||||
token: '->>-',
|
||||
|
@ -69,7 +109,13 @@ export const addSignal = function(idFrom, idTo, message, messageType) {
|
|||
throw error;
|
||||
}
|
||||
}
|
||||
messages.push({ from: idFrom, to: idTo, message: message, type: messageType });
|
||||
messages.push({
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
|
||||
type: messageType
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -89,6 +135,9 @@ export const getActorKeys = function() {
|
|||
export const getTitle = function() {
|
||||
return title;
|
||||
};
|
||||
export const getTitleWrapped = function() {
|
||||
return titleWrapped;
|
||||
};
|
||||
export const enableSequenceNumbers = function() {
|
||||
sequenceNumbersEnabled = true;
|
||||
};
|
||||
|
@ -107,6 +156,22 @@ export const autoWrap = () => wrapEnabled;
|
|||
export const clear = function() {
|
||||
actors = {};
|
||||
messages = [];
|
||||
configUpdated = false;
|
||||
};
|
||||
|
||||
export const parseMessage = function(str) {
|
||||
const _str = str.trim();
|
||||
return {
|
||||
text: _str.replace(/^[:]?(?:no)?wrap:/, '').trim(),
|
||||
wrap:
|
||||
_str.match(/^[:]?(?:no)?wrap:/) === null
|
||||
? autoWrap()
|
||||
: _str.match(/^[:]?wrap:/) !== null
|
||||
? true
|
||||
: _str.match(/^[:]?nowrap:/) !== null
|
||||
? false
|
||||
: autoWrap()
|
||||
};
|
||||
};
|
||||
|
||||
export const LINETYPE = {
|
||||
|
@ -145,7 +210,12 @@ export const PLACEMENT = {
|
|||
};
|
||||
|
||||
export const addNote = function(actor, placement, message) {
|
||||
const note = { actor: actor, placement: placement, message: message };
|
||||
const note = {
|
||||
actor: actor,
|
||||
placement: placement,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap
|
||||
};
|
||||
|
||||
// Coerce actor into a [to, from, ...] array
|
||||
const actors = [].concat(actor, actor);
|
||||
|
@ -154,14 +224,29 @@ export const addNote = function(actor, placement, message) {
|
|||
messages.push({
|
||||
from: actors[0],
|
||||
to: actors[1],
|
||||
message: message,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
|
||||
type: LINETYPE.NOTE,
|
||||
placement: placement
|
||||
});
|
||||
};
|
||||
|
||||
export const setTitle = function(titleText) {
|
||||
title = titleText;
|
||||
export const setTitle = function(titleWrap) {
|
||||
title = titleWrap.text;
|
||||
titleWrapped = (titleWrap.wrap === null && autoWrap()) || !!titleWrap.wrap;
|
||||
};
|
||||
|
||||
export const updateConfig = function(config = getConfig()) {
|
||||
try {
|
||||
setConfig(config);
|
||||
configUpdated = true;
|
||||
} catch (error) {
|
||||
logger.error('Error: unable to parse config');
|
||||
}
|
||||
};
|
||||
|
||||
export const hasConfigChange = function() {
|
||||
return configUpdated;
|
||||
};
|
||||
|
||||
export const apply = function(param) {
|
||||
|
@ -225,16 +310,6 @@ export const apply = function(param) {
|
|||
case 'parEnd':
|
||||
addSignal(undefined, undefined, undefined, param.signalType);
|
||||
break;
|
||||
case 'config':
|
||||
try {
|
||||
let cfg = param.config;
|
||||
let _config = getConfig();
|
||||
let config = Object.assign(_config, cfg);
|
||||
setConfig(config);
|
||||
} catch (error) {
|
||||
logger.error('Error: unable to parse config');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -253,7 +328,13 @@ export default {
|
|||
getActor,
|
||||
getActorKeys,
|
||||
getTitle,
|
||||
handleDirective,
|
||||
hasConfigChange,
|
||||
getConfig,
|
||||
updateConfig,
|
||||
getTitleWrapped,
|
||||
clear,
|
||||
parseMessage,
|
||||
LINETYPE,
|
||||
ARROWTYPE,
|
||||
PLACEMENT,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -79,6 +79,9 @@ export const bounds = {
|
|||
stopy: undefined
|
||||
};
|
||||
this.verticalPos = 0;
|
||||
if (parser.yy.hasConfigChange()) {
|
||||
setConf(getConfig());
|
||||
}
|
||||
},
|
||||
updateVal: function(obj, key, val, fun) {
|
||||
if (typeof obj[key] === 'undefined') {
|
||||
|
@ -182,7 +185,11 @@ export const bounds = {
|
|||
return this.data;
|
||||
}
|
||||
};
|
||||
|
||||
const wrapLabel = (label, maxWidth, joinWith = '<br/>') => {
|
||||
if (common.lineBreakRegex.test(label)) {
|
||||
return label;
|
||||
}
|
||||
const words = label.split(' ');
|
||||
const completedLines = [];
|
||||
let nextLine = '';
|
||||
|
@ -207,6 +214,7 @@ const wrapLabel = (label, maxWidth, joinWith = '<br/>') => {
|
|||
});
|
||||
return completedLines.filter(line => line !== '').join(joinWith);
|
||||
};
|
||||
|
||||
const breakString = (word, maxWidth, hyphenCharacter = '-') => {
|
||||
const characters = word.split('');
|
||||
const lines = [];
|
||||
|
@ -266,6 +274,7 @@ const _drawLongText = (text, x, y, g, width) => {
|
|||
.style('text-anchor', alignment)
|
||||
.style('font-size', conf.noteFontSize)
|
||||
.style('font-family', conf.noteFontFamily)
|
||||
.style('font-weight', conf.noteFontWeight)
|
||||
.attr('dominant-baseline', 'central')
|
||||
.attr('alignment-baseline', 'central');
|
||||
|
||||
|
@ -322,17 +331,40 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
|
|||
const txtCenter = startx + (stopx - startx) / 2;
|
||||
|
||||
let textElems = [];
|
||||
/*
|
||||
let textHeight = 0;
|
||||
const breaklines = msg.message.split(common.lineBreakRegex);
|
||||
for (const breakline of breaklines) {
|
||||
let textElem = g
|
||||
.append('text') // text label for the x axis
|
||||
.attr('x', txtCenter)
|
||||
.attr('y', verticalPos + textHeight)
|
||||
.style('font-size', conf.messageFontSize)
|
||||
.style('font-family', conf.messageFontFamily)
|
||||
.style('font-weight', conf.messageFontWeight)
|
||||
.style('text-anchor', 'middle')
|
||||
.attr('class', 'messageText')
|
||||
.text(breakline.trim());
|
||||
textElems.push(textElem);
|
||||
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
|
||||
}
|
||||
|
||||
let totalOffset = textHeight;
|
||||
*/
|
||||
|
||||
let counterBreaklines = 0;
|
||||
let breaklineOffset = 17;
|
||||
let breaklineOffset = conf.messageFontSize + 4;
|
||||
const breaklines = msg.message.split(common.lineBreakRegex);
|
||||
for (const breakline of breaklines) {
|
||||
textElems.push(
|
||||
g
|
||||
.append('text') // text label for the x axis
|
||||
.attr('x', txtCenter)
|
||||
// .attr('y', verticalPos - breaklineVerticalOffset + counterBreaklines * breaklineOffset)
|
||||
.attr('y', verticalPos - 7 + counterBreaklines * breaklineOffset)
|
||||
.style('font-size', conf.messageFontSize)
|
||||
.style('font-family', conf.messageFontFamily)
|
||||
.style('font-weight', conf.messageFontWeight)
|
||||
.style('text-anchor', 'middle')
|
||||
.attr('class', 'messageText')
|
||||
.text(breakline.trim())
|
||||
|
@ -341,7 +373,6 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
|
|||
}
|
||||
const offsetLineCounter = counterBreaklines - 1;
|
||||
let totalOffset = offsetLineCounter * breaklineOffset;
|
||||
|
||||
let textWidths = textElems.map(function(textElem) {
|
||||
return (textElem._groups || textElem)[0][0].getBBox().width;
|
||||
});
|
||||
|
@ -469,28 +500,42 @@ export const drawActors = function(diagram, actors, actorKeys, verticalPos) {
|
|||
// Draw the actors
|
||||
let prevWidth = 0;
|
||||
let prevMargin = 0;
|
||||
let maxActorHeight = conf.height;
|
||||
|
||||
for (let i = 0; i < actorKeys.length; i++) {
|
||||
const actor = actors[actorKeys[i]];
|
||||
|
||||
// Add some rendering data to the object
|
||||
actor.width = actor.width || calculateActorWidth(actor);
|
||||
actor.height = conf.height;
|
||||
actor.height = actor.wrap
|
||||
? calculateTextHeight(
|
||||
actor.message,
|
||||
conf.height,
|
||||
actor.width,
|
||||
conf.wrapPadding,
|
||||
actor.wrap,
|
||||
conf.actorFontSize
|
||||
)
|
||||
: conf.height;
|
||||
maxActorHeight = Math.max(maxActorHeight, actor.height);
|
||||
actor.margin = actor.margin || conf.actorMargin;
|
||||
|
||||
actor.x = prevWidth + prevMargin;
|
||||
actor.y = verticalPos;
|
||||
|
||||
if (actor.wrap) {
|
||||
actor.description = wrapLabel(actor.description, actor.width);
|
||||
}
|
||||
// Draw the box with the attached line
|
||||
svgDraw.drawActor(diagram, actor, conf);
|
||||
bounds.insert(actor.x, verticalPos, actor.x + actor.width, conf.height);
|
||||
bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height);
|
||||
|
||||
prevWidth += actor.width;
|
||||
prevMargin += actor.margin;
|
||||
}
|
||||
|
||||
// Add a margin between the actor boxes and the first arrow
|
||||
bounds.bumpVerticalPos(conf.height);
|
||||
bounds.bumpVerticalPos(maxActorHeight);
|
||||
};
|
||||
|
||||
export const setConf = function(cnf) {
|
||||
|
@ -505,6 +550,7 @@ export const setConf = function(cnf) {
|
|||
}
|
||||
if (cnf.fontSize) {
|
||||
conf.actorFontSize = conf.noteFontSize = conf.messageFontSize = cnf.fontSize;
|
||||
// conf.height = cnf.fontSize * (65 / 14);
|
||||
}
|
||||
if (cnf.fontWeight) {
|
||||
conf.actorFontWeight = conf.noteFontWeight = conf.messageFontWeight = cnf.fontWeight;
|
||||
|
@ -546,15 +592,50 @@ const calculateActorWidth = function(actor) {
|
|||
return conf.width;
|
||||
}
|
||||
|
||||
return Math.max(
|
||||
conf.width,
|
||||
calculateTextWidth(
|
||||
actor.description,
|
||||
conf.actorFontSize,
|
||||
conf.actorFontFamily,
|
||||
conf.actorFontWeight
|
||||
)
|
||||
);
|
||||
return actor.wrap
|
||||
? conf.width
|
||||
: Math.max(
|
||||
conf.width,
|
||||
calculateTextWidth(
|
||||
actor.description,
|
||||
conf.actorFontSize,
|
||||
conf.actorFontFamily,
|
||||
conf.actorFontWeight
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* This calculates the text's height, taking into account the wrap value and
|
||||
* both the statically configured height, width, and the length of the text (in pixels).
|
||||
*
|
||||
* If the wrapped text text has greater height, we extend the height, so it's
|
||||
* value won't overflow.
|
||||
*
|
||||
* @return - The height for the given actor
|
||||
* @param message the text to measure
|
||||
* @param elementHeight the height of the default bounding box containing the text
|
||||
* @param elementWidth the width of the default bounding box containing the text
|
||||
* @param margin space above and below
|
||||
* @param wrap wrap the text based on: elementWidth - 2 * margin
|
||||
* @param fontSize
|
||||
*/
|
||||
export const calculateTextHeight = function(
|
||||
message,
|
||||
elementHeight,
|
||||
elementWidth,
|
||||
margin,
|
||||
wrap,
|
||||
fontSize
|
||||
) {
|
||||
if (!message) {
|
||||
return elementHeight;
|
||||
}
|
||||
let lineHeightFactor = wrap
|
||||
? wrapLabel(message, elementWidth - 2 * margin).split(common.lineBreakRegex).length
|
||||
: 1;
|
||||
|
||||
return wrap ? Math.max(elementHeight, lineHeightFactor * fontSize) : elementHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -616,11 +697,8 @@ export const calculateTextWidth = function(text, fontSize, fontFamily, fontWeigh
|
|||
* @param id
|
||||
*/
|
||||
export const draw = function(text, id) {
|
||||
logger.debug(`Config (preclear): ${JSON.stringify(conf)}`, conf);
|
||||
parser.yy.clear();
|
||||
parser.parse(text + '\n');
|
||||
logger.debug(`Config (postclear): ${JSON.stringify(conf)}`, conf);
|
||||
setConf(getConfig());
|
||||
|
||||
bounds.init();
|
||||
const diagram = select(`[id="${id}"]`);
|
||||
|
@ -636,10 +714,16 @@ export const draw = function(text, id) {
|
|||
const title = parser.yy.getTitle();
|
||||
|
||||
const maxMessageWidthPerActor = getMaxMessageWidthPerActor(actors, messages);
|
||||
calculateActorMargins(actors, maxMessageWidthPerActor);
|
||||
const maxActorHeight = calculateActorMargins(actors, maxMessageWidthPerActor);
|
||||
|
||||
drawActors(diagram, actors, actorKeys, 0);
|
||||
|
||||
bounds.bumpVerticalPos(
|
||||
maxActorHeight > conf.height
|
||||
? Math.min(conf.boxMargin, Math.abs(maxActorHeight - conf.height))
|
||||
: 0
|
||||
);
|
||||
|
||||
// The arrow head definition is attached to the svg once
|
||||
svgDraw.insertArrowHead(diagram);
|
||||
svgDraw.insertArrowCrossHead(diagram);
|
||||
|
@ -667,16 +751,8 @@ export const draw = function(text, id) {
|
|||
messages.forEach(function(msg) {
|
||||
let loopData,
|
||||
noteWidth,
|
||||
textWidth = calculateTextWidth(
|
||||
msg.message,
|
||||
conf.noteFontSize,
|
||||
conf.noteFontFamily,
|
||||
conf.noteFontWeight
|
||||
),
|
||||
shouldWrap =
|
||||
(sequenceDb.autoWrap() || conf.wrapEnabled) &&
|
||||
msg.message &&
|
||||
!common.lineBreakRegex.test(msg.message);
|
||||
textWidth,
|
||||
shouldWrap = msg.wrap && msg.message && !common.lineBreakRegex.test(msg.message);
|
||||
|
||||
switch (msg.type) {
|
||||
case parser.yy.LINETYPE.NOTE:
|
||||
|
@ -684,11 +760,17 @@ export const draw = function(text, id) {
|
|||
|
||||
startx = actors[msg.from].x;
|
||||
stopx = actors[msg.to].x;
|
||||
textWidth = calculateTextWidth(
|
||||
msg.message,
|
||||
conf.noteFontSize,
|
||||
conf.noteFontFamily,
|
||||
conf.noteFontWeight
|
||||
);
|
||||
noteWidth = shouldWrap ? conf.width : Math.max(conf.width, textWidth);
|
||||
|
||||
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
||||
if (shouldWrap) {
|
||||
msg.message = wrapLabel(msg.message, noteWidth - conf.noteMargin * 2);
|
||||
msg.message = wrapLabel(msg.message, noteWidth);
|
||||
}
|
||||
drawNote(
|
||||
diagram,
|
||||
|
@ -699,7 +781,7 @@ export const draw = function(text, id) {
|
|||
);
|
||||
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
|
||||
if (shouldWrap) {
|
||||
msg.message = wrapLabel(msg.message, noteWidth - conf.noteMargin * 2);
|
||||
msg.message = wrapLabel(msg.message, noteWidth);
|
||||
}
|
||||
drawNote(
|
||||
diagram,
|
||||
|
@ -711,7 +793,7 @@ export const draw = function(text, id) {
|
|||
} else if (msg.to === msg.from) {
|
||||
// Single-actor over
|
||||
if (shouldWrap) {
|
||||
msg.message = wrapLabel(msg.message, noteWidth - conf.noteMargin * 2);
|
||||
msg.message = wrapLabel(msg.message, noteWidth);
|
||||
}
|
||||
drawNote(
|
||||
diagram,
|
||||
|
@ -722,16 +804,17 @@ export const draw = function(text, id) {
|
|||
);
|
||||
} else {
|
||||
// Multi-actor over
|
||||
forceWidth = Math.abs(startx - stopx) + conf.actorMargin;
|
||||
noteWidth =
|
||||
(shouldWrap ? forceWidth : Math.max(forceWidth, textWidth)) - conf.noteMargin * 2;
|
||||
forceWidth = Math.abs(startx - stopx) + conf.actorMargin / 2;
|
||||
if (shouldWrap) {
|
||||
noteWidth = forceWidth;
|
||||
msg.message = wrapLabel(msg.message, noteWidth);
|
||||
} else {
|
||||
noteWidth = Math.max(forceWidth, textWidth - 2 * conf.noteMargin);
|
||||
}
|
||||
let x =
|
||||
startx < stopx
|
||||
? startx + (actors[msg.from].width - conf.actorMargin) / 2
|
||||
: stopx + (actors[msg.to].width - conf.actorMargin) / 2;
|
||||
? startx + (actors[msg.from].width - conf.actorMargin / 2) / 2
|
||||
: stopx + (actors[msg.to].width - conf.actorMargin / 2) / 2;
|
||||
|
||||
drawNote(diagram, x, bounds.getVerticalPos(), msg, forceWidth);
|
||||
}
|
||||
|
@ -793,6 +876,9 @@ export const draw = function(text, id) {
|
|||
break;
|
||||
case parser.yy.LINETYPE.PAR_START:
|
||||
bounds.bumpVerticalPos(conf.boxMargin);
|
||||
if (shouldWrap) {
|
||||
msg.message = wrapLabel(msg.message, conf.boxMargin);
|
||||
}
|
||||
bounds.newLoop(msg.message);
|
||||
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
|
||||
break;
|
||||
|
@ -817,7 +903,13 @@ export const draw = function(text, id) {
|
|||
startx = fromBounds[fromIdx];
|
||||
stopx = toBounds[toIdx];
|
||||
if (shouldWrap) {
|
||||
msg.message = wrapLabel(msg.message, Math.abs(stopx - startx - conf.messageMargin));
|
||||
msg.message = wrapLabel(
|
||||
msg.message,
|
||||
Math.max(
|
||||
Math.abs(stopx - startx) + conf.messageMargin * 2,
|
||||
conf.width + conf.messageMargin * 2
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const verticalPos = bounds.getVerticalPos();
|
||||
|
@ -927,19 +1019,12 @@ const getMaxMessageWidthPerActor = function(actors, messages) {
|
|||
|
||||
const isNote = msg.placement !== undefined;
|
||||
const isMessage = !isNote;
|
||||
const wrapped = sequenceDb.autoWrap() || conf.wrapEnabled;
|
||||
|
||||
const fontSize = isNote ? conf.noteFontSize : conf.messageFontSize;
|
||||
const fontFamily = isNote ? conf.noteFontFamily : conf.messageFontFamily;
|
||||
const fontWeight = isNote ? conf.noteFontWeight : conf.messageFontWeight;
|
||||
const messageWidth = calculateTextWidth(
|
||||
wrapped
|
||||
? wrapLabel(
|
||||
msg.message,
|
||||
conf.width -
|
||||
(isNote ? conf.noteMargin * 2 + conf.messageMargin * 2 : conf.messageMargin * 2)
|
||||
)
|
||||
: msg.message,
|
||||
msg.wrap ? wrapLabel(msg.message, conf.width - conf.noteMargin) : msg.message,
|
||||
fontSize,
|
||||
fontFamily,
|
||||
fontWeight
|
||||
|
@ -997,7 +1082,6 @@ const getMaxMessageWidthPerActor = function(actors, messages) {
|
|||
}
|
||||
});
|
||||
|
||||
logger.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
|
||||
return maxMessageWidthPerActor;
|
||||
};
|
||||
|
||||
|
@ -1012,6 +1096,7 @@ const getMaxMessageWidthPerActor = function(actors, messages) {
|
|||
* @param actorToMessageWidth - A map of actor key -> max message width it holds
|
||||
*/
|
||||
const calculateActorMargins = function(actors, actorToMessageWidth) {
|
||||
let maxHeight = 0;
|
||||
for (let actorKey in actorToMessageWidth) {
|
||||
const actor = actors[actorKey];
|
||||
|
||||
|
@ -1026,37 +1111,42 @@ const calculateActorMargins = function(actors, actorToMessageWidth) {
|
|||
continue;
|
||||
}
|
||||
|
||||
const wrapped = sequenceDb.autoWrap() || conf.wrapEnabled;
|
||||
[actor, nextActor].forEach(function(act) {
|
||||
act.width = act.wrap
|
||||
? conf.width
|
||||
: Math.max(
|
||||
conf.width,
|
||||
calculateTextWidth(
|
||||
act.description,
|
||||
conf.actorFontSize,
|
||||
conf.actorFontFamily,
|
||||
conf.actorFontWeight
|
||||
)
|
||||
);
|
||||
|
||||
actor.width = wrapped
|
||||
? conf.width
|
||||
: Math.max(
|
||||
conf.width,
|
||||
calculateTextWidth(
|
||||
actor.description,
|
||||
conf.actorFontSize,
|
||||
conf.actorFontFamily,
|
||||
conf.actorFontWeight
|
||||
act.height = act.wrap
|
||||
? calculateTextHeight(
|
||||
act.description,
|
||||
conf.height,
|
||||
actor.width,
|
||||
conf.actorMargin,
|
||||
act.wrap,
|
||||
conf.actorFontSize
|
||||
)
|
||||
);
|
||||
|
||||
nextActor.width = wrapped
|
||||
? conf.width
|
||||
: Math.max(
|
||||
conf.width,
|
||||
calculateTextWidth(
|
||||
nextActor.description,
|
||||
conf.actorFontSize,
|
||||
conf.actorFontFamily,
|
||||
conf.actorFontWeight
|
||||
)
|
||||
);
|
||||
: conf.height;
|
||||
maxHeight = Math.max(maxHeight, act.height);
|
||||
});
|
||||
|
||||
const messageWidth = actorToMessageWidth[actorKey];
|
||||
const actorWidth = messageWidth + conf.actorMargin - actor.width / 2 - nextActor.width / 2;
|
||||
|
||||
actor.margin = Math.max(actorWidth, conf.actorMargin);
|
||||
}
|
||||
Object.keys(actors).forEach(function(key) {
|
||||
actors[key].height = maxHeight;
|
||||
});
|
||||
|
||||
return maxHeight;
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
@ -26,6 +26,9 @@ export const drawText = function(elem, textData) {
|
|||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
textElem.style('font-family', textData.fontFamily);
|
||||
textElem.style('font-size', textData.fontSize);
|
||||
textElem.style('font-weight', textData.fontWeight);
|
||||
textElem.attr('fill', textData.fill);
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
textElem.attr('class', textData.class);
|
||||
|
@ -77,7 +80,7 @@ let actorCnt = -1;
|
|||
* Draws an actor in the diagram with the attaced line
|
||||
* @param elem - The diagram we'll draw to.
|
||||
* @param actor - The actor to draw.
|
||||
* @param config - The sequence diagram config object.
|
||||
* @param conf - drawText implementation discriminator object
|
||||
*/
|
||||
export const drawActor = function(elem, actor, conf) {
|
||||
const center = actor.x + actor.width / 2;
|
||||
|
@ -146,7 +149,7 @@ export const drawActivation = function(elem, bounds, verticalPos, conf, actorAct
|
|||
* @param elem - elemenet to append the loop to.
|
||||
* @param bounds - bounds of the given loop.
|
||||
* @param labelText - Text within the loop.
|
||||
* @param config - sequence diagram config object.
|
||||
* @param conf
|
||||
*/
|
||||
export const drawLoop = function(elem, bounds, labelText, conf) {
|
||||
const g = elem.append('g');
|
||||
|
@ -169,11 +172,17 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
|
|||
});
|
||||
}
|
||||
|
||||
let minSize =
|
||||
Math.round((3 * conf.fontSize) / 4) < 10 ? conf.fontSize : Math.round((3 * conf.fontSize) / 4);
|
||||
|
||||
let txt = getTextObj();
|
||||
txt.text = labelText;
|
||||
txt.x = bounds.startx;
|
||||
txt.y = bounds.starty;
|
||||
txt.labelMargin = 1.5 * 10; // This is the small box that says "loop"
|
||||
txt.fontFamily = conf.fontFamily;
|
||||
txt.fontSize = minSize;
|
||||
txt.fontWeight = conf.fontWeight;
|
||||
txt.class = 'labelText'; // Its size & position are fixed.
|
||||
|
||||
drawLabel(g, txt);
|
||||
|
@ -184,23 +193,31 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
|
|||
txt.y = bounds.starty + 1.5 * conf.boxMargin;
|
||||
txt.anchor = 'middle';
|
||||
txt.class = 'loopText';
|
||||
txt.fontFamily = conf.fontFamily;
|
||||
txt.fontSize = minSize;
|
||||
txt.fontWeight = conf.fontWeight;
|
||||
|
||||
drawText(g, txt);
|
||||
let textElem = drawText(g, txt);
|
||||
let textHeight = (textElem._groups || textElem)[0][0].getBBox().height;
|
||||
|
||||
if (typeof bounds.sectionTitles !== 'undefined') {
|
||||
bounds.sectionTitles.forEach(function(item, idx) {
|
||||
if (item !== '') {
|
||||
txt.text = '[ ' + item + ' ]';
|
||||
txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin;
|
||||
drawText(g, txt);
|
||||
textElem = drawText(g, txt);
|
||||
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return textHeight + 4;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a background rectangle
|
||||
* @param color - The fill color for the background
|
||||
* @param elem diagram (reference for bounds)
|
||||
* @param bounds shape of the rectangle
|
||||
*/
|
||||
export const drawBackgroundRect = function(elem, bounds) {
|
||||
const rectElem = drawRect(elem, {
|
||||
|
@ -325,7 +342,7 @@ const _drawTextCandidateFunc = (function() {
|
|||
}
|
||||
|
||||
function byTspan(content, g, x, y, width, height, textAttrs, conf) {
|
||||
const { actorFontSize, actorFontFamily } = conf;
|
||||
const { actorFontSize, actorFontFamily, actorFontWeight } = conf;
|
||||
|
||||
const lines = content.split(common.lineBreakRegex);
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
|
@ -336,6 +353,7 @@ const _drawTextCandidateFunc = (function() {
|
|||
.attr('y', y)
|
||||
.style('text-anchor', 'middle')
|
||||
.style('font-size', actorFontSize)
|
||||
.style('font-weight', actorFontWeight)
|
||||
.style('font-family', actorFontFamily);
|
||||
text
|
||||
.append('tspan')
|
||||
|
|
|
@ -561,6 +561,11 @@ setLogLevel(config.logLevel);
|
|||
setConfig(config);
|
||||
|
||||
function parse(text) {
|
||||
const graphInit = utils.detectInit(text);
|
||||
if (graphInit) {
|
||||
reinitialize(graphInit);
|
||||
logger.debug('Init ', graphInit);
|
||||
}
|
||||
const graphType = utils.detectType(text);
|
||||
let parser;
|
||||
|
||||
|
@ -949,14 +954,12 @@ const setConf = function(cnf) {
|
|||
};
|
||||
|
||||
function reinitialize(options) {
|
||||
let _config = getConfig();
|
||||
if (typeof options === 'object') {
|
||||
_config = Object.assign(_config, options);
|
||||
setConf(_config);
|
||||
setConf(options);
|
||||
}
|
||||
setConfig(_config);
|
||||
setLogLevel(_config.logLevel);
|
||||
logger.debug('RE-Initializing mermaidAPI ', { version: pkg.version, options, _config });
|
||||
setConfig(config);
|
||||
setLogLevel(config.logLevel);
|
||||
logger.debug('RE-Initializing mermaidAPI ', { version: pkg.version, options, config });
|
||||
}
|
||||
|
||||
function initialize(options) {
|
||||
|
@ -980,6 +983,7 @@ const mermaidAPI = {
|
|||
render,
|
||||
parse,
|
||||
initialize,
|
||||
reinitialize,
|
||||
getConfig
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
$mainBkg: #1f2020;
|
||||
$secondBkg: lighten(#1f2020, 100);
|
||||
$secondBkg: lighten(#1f2020, 16);
|
||||
$mainContrastColor: lightgrey;
|
||||
$darkTextColor: #323D47;
|
||||
$lineColor: $mainContrastColor;
|
||||
|
@ -31,8 +31,8 @@ $labelTextColor: $mainContrastColor;
|
|||
$loopTextColor: $mainContrastColor;
|
||||
$noteBorderColor: $border2;
|
||||
$noteBkgColor: #fff5ad;
|
||||
$activationBorderColor: #666;
|
||||
$activationBkgColor: #f4f4f4;
|
||||
$activationBorderColor: $border1;
|
||||
$activationBkgColor: $secondBkg;
|
||||
$sequenceNumberColor: white;
|
||||
|
||||
/* Gantt chart variables */
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
// }
|
||||
|
||||
:root {
|
||||
--mermaid-font-family: '"trebuchet ms", verdana, arial';
|
||||
--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive;
|
||||
--mermaid-font-family: '"trebuchet ms", verdana, arial, "Comic Sans MS", "Comic Sans", cursive';
|
||||
// --mermaid-alt-font-family: '"Lucida Console", Monaco, monospace';
|
||||
}
|
||||
|
||||
|
@ -23,4 +22,4 @@
|
|||
.error-text {
|
||||
fill: $errorTextColor;
|
||||
stroke: $errorTextColor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,8 +78,6 @@ text.actor > tspan {
|
|||
.noteText {
|
||||
fill: $actorBkg;
|
||||
stroke: none;
|
||||
font-family: 'trebuchet ms', verdana, arial, var(--mermaid-font-family);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.activation0 {
|
||||
|
|
27
src/utils.js
27
src/utils.js
|
@ -28,14 +28,19 @@ const d3CurveTypes = {
|
|||
curveStepAfter: curveStepAfter,
|
||||
curveStepBefore: curveStepBefore
|
||||
};
|
||||
|
||||
const initPart = /^\s*init(?:ialize)?:\s*(\{.*})$/m;
|
||||
const fullDirective = /%%\{(\w+)[:]?\s*(\{.*}(?!%%))?\s*}%%/;
|
||||
const directiveWithoutOpen = /\{(\w+)[:]?\s*(\{.*}(?!%%))?\s*}%%/;
|
||||
const commentWithoutDirectives = new RegExp(
|
||||
`\\s*%%(?!${directiveWithoutOpen.source})(?=}%%).*\n`,
|
||||
'gm'
|
||||
);
|
||||
const anyComment = new RegExp(`\\s*%%.*\n`, 'gm');
|
||||
|
||||
/**
|
||||
* @function detectInit
|
||||
* Detects the init config object from the text
|
||||
* ```mermaid
|
||||
* init: {"startOnLoad": true, "logLevel": 1 }
|
||||
* %%{init: {"startOnLoad": true, "logLevel": 1 }}%%
|
||||
* graph LR
|
||||
* a-->b
|
||||
* b-->c
|
||||
|
@ -47,7 +52,7 @@ const initPart = /^\s*init(?:ialize)?:\s*(\{.*})$/m;
|
|||
* ```
|
||||
* or
|
||||
* ```mermaid
|
||||
* initialize: {"startOnLoad": true, logLevel: "fatal" }
|
||||
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
|
||||
* graph LR
|
||||
* a-->b
|
||||
* b-->c
|
||||
|
@ -62,12 +67,12 @@ const initPart = /^\s*init(?:ialize)?:\s*(\{.*})$/m;
|
|||
* @returns {object} An object representing the initialization to pass to mermaidAPI.initialize()
|
||||
*/
|
||||
export const detectInit = function(text) {
|
||||
text = text.replace(/^\s*%%.*\n/g, '\n');
|
||||
text = text.replace(commentWithoutDirectives, '\n');
|
||||
logger.debug('Detecting diagram init based on the text ' + text);
|
||||
if (text.match(initPart)) {
|
||||
const matches = text.match(fullDirective);
|
||||
if (matches && /init(?:ialize)?/.test(matches[1])) {
|
||||
return JSON.parse(
|
||||
text
|
||||
.match(initPart)[1]
|
||||
matches[2]
|
||||
.trim()
|
||||
.replace(/\\n/g, '\n')
|
||||
.replace(/'/g, '"')
|
||||
|
@ -77,8 +82,10 @@ export const detectInit = function(text) {
|
|||
|
||||
/**
|
||||
* @function detectType
|
||||
* Detects the type of the graph text.
|
||||
* Detects the type of the graph text. Takes into consideration the possible existence of an %%init
|
||||
* directive
|
||||
* ```mermaid
|
||||
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
|
||||
* graph LR
|
||||
* a-->b
|
||||
* b-->c
|
||||
|
@ -93,7 +100,7 @@ export const detectInit = function(text) {
|
|||
* @returns {string} A graph definition key
|
||||
*/
|
||||
export const detectType = function(text) {
|
||||
text = text.replace(/^\s*%%.*\n/g, '\n').replace(initPart, '');
|
||||
text = text.replace(anyComment, '\n');
|
||||
logger.debug('Detecting diagram type based on the text ' + text);
|
||||
if (text.match(/^\s*sequenceDiagram/)) {
|
||||
return 'sequence';
|
||||
|
|
|
@ -8,12 +8,19 @@ describe('when detecting chart type ', function() {
|
|||
expect(type).toBe('flowchart');
|
||||
});
|
||||
it('should handle an initialize defintion', function() {
|
||||
const str = 'initialize: { "logLevel": 0, "theme": "dark" }\ngraph TB\nbfs1:queue';
|
||||
const str = `
|
||||
%%{initialize: { 'logLevel': 0, 'theme': 'dark' }}%%
|
||||
graph TB
|
||||
bfs1:queue
|
||||
`;
|
||||
const init = JSON.stringify(utils.detectInit(str));
|
||||
expect(init).toBe('{"logLevel":0,"theme":"dark"}');
|
||||
});
|
||||
it('should handle an init defintion', function() {
|
||||
const str = 'init: { "logLevel": 0, "theme": "dark" }\ngraph TB\nbfs1:queue';
|
||||
const str = `
|
||||
%%{init: { 'logLevel': 0, 'theme': 'dark' }}%%
|
||||
graph TB
|
||||
bfs1:queue`;
|
||||
const init = JSON.stringify(utils.detectInit(str));
|
||||
expect(init).toBe('{"logLevel":0,"theme":"dark"}');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue