feat(katex): optimized importing of katex

This commit is contained in:
NicolasNewman 2023-06-23 16:53:01 +09:00
parent b193013c84
commit 5c69e5fdb0
5 changed files with 93 additions and 98 deletions

View File

@ -1,6 +1,4 @@
import DOMPurify from 'dompurify'; import DOMPurify from 'dompurify';
// @ts-ignore @types/katex does not work
import katex from 'katex';
import { MermaidConfig } from '../../config.type.js'; import { MermaidConfig } from '../../config.type.js';
export const lineBreakRegex = /<br\s*\/?>/gi; export const lineBreakRegex = /<br\s*\/?>/gi;
@ -219,8 +217,8 @@ export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.leng
* @param config - Configuration for Mermaid * @param config - Configuration for Mermaid
* @returns Object containing \{width, height\} * @returns Object containing \{width, height\}
*/ */
export const calculateMathMLDimensions = (text: string, config: MermaidConfig) => { export const calculateMathMLDimensions = async (text: string, config: MermaidConfig) => {
text = renderKatex(text, config); text = await renderKatex(text, config);
const divElem = document.createElement('div'); const divElem = document.createElement('div');
divElem.innerHTML = text; divElem.innerHTML = text;
divElem.id = 'katex-temp'; divElem.id = 'katex-temp';
@ -234,13 +232,6 @@ export const calculateMathMLDimensions = (text: string, config: MermaidConfig) =
return dim; return dim;
}; };
// export const temp = (text: string, config: MermaidConfig) => {
// return renderKatex(text, config).split(lineBreakRegex).map((text) =>
// hasKatex(text) ?
// `<div style="display: flex;">${text}</div>` :
// `<div>${text}</div>`).join('');
// }
/** /**
* Attempts to render and return the KaTeX portion of a string with MathML * Attempts to render and return the KaTeX portion of a string with MathML
* *
@ -248,8 +239,10 @@ export const calculateMathMLDimensions = (text: string, config: MermaidConfig) =
* @param config - Configuration for Mermaid * @param config - Configuration for Mermaid
* @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present * @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present
*/ */
export const renderKatex = (text: string, config: MermaidConfig): string => { export const renderKatex = async (text: string, config: MermaidConfig): Promise<string> => {
if (isMathMLSupported() || (!isMathMLSupported() && config.legacyMathML)) { if ((hasKatex(text) && isMathMLSupported()) || (!isMathMLSupported() && config.legacyMathML)) {
// @ts-ignore @types/katex does not work
const katex = (await import('katex')).default;
return text return text
.split(lineBreakRegex) .split(lineBreakRegex)
.map((line) => .map((line) =>

View File

@ -30,12 +30,12 @@ export const setConf = function (cnf) {
* @param doc * @param doc
* @param diagObj * @param diagObj
*/ */
export const addVertices = function (vert, g, svgId, root, doc, diagObj) { export const addVertices = async function (vert, g, svgId, root, doc, diagObj) {
const svg = root.select(`[id="${svgId}"]`); const svg = root.select(`[id="${svgId}"]`);
const keys = Object.keys(vert); const keys = Object.keys(vert);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function (id) { for (const id of keys) {
const vertex = vert[id]; const vertex = vert[id];
/** /**
@ -143,7 +143,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
default: default:
_shape = 'rect'; _shape = 'rect';
} }
const labelText = renderKatex(vertexText, getConfig()); const labelText = await renderKatex(vertexText, getConfig());
// Add the node // Add the node
g.setNode(vertex.id, { g.setNode(vertex.id, {
@ -185,7 +185,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
props: vertex.props, props: vertex.props,
padding: getConfig().flowchart.padding, padding: getConfig().flowchart.padding,
}); });
}); }
}; };
/** /**
@ -195,7 +195,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
* @param {object} g The graph object * @param {object} g The graph object
* @param diagObj * @param diagObj
*/ */
export const addEdges = function (edges, g, diagObj) { export const addEdges = async function (edges, g, diagObj) {
log.info('abc78 edges = ', edges); log.info('abc78 edges = ', edges);
let cnt = 0; let cnt = 0;
let linkIdCnt = {}; let linkIdCnt = {};
@ -209,7 +209,7 @@ export const addEdges = function (edges, g, diagObj) {
defaultLabelStyle = defaultStyles.labelStyle; defaultLabelStyle = defaultStyles.labelStyle;
} }
edges.forEach(function (edge) { for (const edge of edges) {
cnt++; cnt++;
// Identify Link // Identify Link
@ -318,7 +318,7 @@ export const addEdges = function (edges, g, diagObj) {
edgeData.labelpos = 'c'; edgeData.labelpos = 'c';
} }
edgeData.labelType = edge.labelType; edgeData.labelType = edge.labelType;
edgeData.label = renderKatex(edge.text.replace(common.lineBreakRegex, '\n'), getConfig()); edgeData.label = await renderKatex(edge.text.replace(common.lineBreakRegex, '\n'), getConfig());
if (edge.style === undefined) { if (edge.style === undefined) {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;'; edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
@ -331,7 +331,7 @@ export const addEdges = function (edges, g, diagObj) {
// Add the edge to the graph // Add the edge to the graph
g.setEdge(edge.start, edge.end, edgeData, cnt); g.setEdge(edge.start, edge.end, edgeData, cnt);
}); }
}; };
/** /**
@ -438,8 +438,8 @@ export const draw = async function (text, id, _version, diagObj) {
g.setParent(subG.nodes[j], subG.id); g.setParent(subG.nodes[j], subG.id);
} }
} }
addVertices(vert, g, id, root, doc, diagObj); await addVertices(vert, g, id, root, doc, diagObj);
addEdges(edges, g, diagObj); await addEdges(edges, g, diagObj);
// Add custom shapes // Add custom shapes
// flowChartShapes.addToRenderV2(addShape); // flowChartShapes.addToRenderV2(addShape);

View File

@ -28,13 +28,13 @@ export const setConf = function (cnf) {
* @param _doc * @param _doc
* @param diagObj * @param diagObj
*/ */
export const addVertices = function (vert, g, svgId, root, _doc, diagObj) { export const addVertices = async function (vert, g, svgId, root, _doc, diagObj) {
const svg = !root ? select(`[id="${svgId}"]`) : root.select(`[id="${svgId}"]`); const svg = !root ? select(`[id="${svgId}"]`) : root.select(`[id="${svgId}"]`);
const doc = !_doc ? document : _doc; const doc = !_doc ? document : _doc;
const keys = Object.keys(vert); const keys = Object.keys(vert);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function (id) { for (const id of keys) {
const vertex = vert[id]; const vertex = vert[id];
/** /**
@ -57,7 +57,7 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
if (evaluate(getConfig().flowchart.htmlLabels)) { if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that? // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
const node = { const node = {
label: renderKatex( label: await renderKatex(
vertexText.replace( vertexText.replace(
/fa[blrs]?:fa-[\w-]+/g, /fa[blrs]?:fa-[\w-]+/g,
(s) => `<i class='${s.replace(':', ' ')}'></i>` (s) => `<i class='${s.replace(':', ' ')}'></i>`
@ -153,7 +153,7 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
style: styles.style, style: styles.style,
id: diagObj.db.lookUpDomId(vertex.id), id: diagObj.db.lookUpDomId(vertex.id),
}); });
}); }
}; };
/** /**
@ -163,7 +163,7 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
* @param {object} g The graph object * @param {object} g The graph object
* @param diagObj * @param diagObj
*/ */
export const addEdges = function (edges, g, diagObj) { export const addEdges = async function (edges, g, diagObj) {
let cnt = 0; let cnt = 0;
let defaultStyle; let defaultStyle;
@ -175,7 +175,7 @@ export const addEdges = function (edges, g, diagObj) {
defaultLabelStyle = defaultStyles.labelStyle; defaultLabelStyle = defaultStyles.labelStyle;
} }
edges.forEach(function (edge) { for (const edge of edges) {
cnt++; cnt++;
// Identify Link // Identify Link
@ -242,7 +242,7 @@ export const addEdges = function (edges, g, diagObj) {
edgeData.labelType = 'html'; edgeData.labelType = 'html';
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${ edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${
edgeData.labelStyle edgeData.labelStyle
}">${renderKatex( }">${await renderKatex(
edge.text.replace( edge.text.replace(
/fa[blrs]?:fa-[\w-]+/g, /fa[blrs]?:fa-[\w-]+/g,
(s) => `<i class='${s.replace(':', ' ')}'></i>` (s) => `<i class='${s.replace(':', ' ')}'></i>`
@ -267,7 +267,7 @@ export const addEdges = function (edges, g, diagObj) {
// Add the edge to the graph // Add the edge to the graph
g.setEdge(diagObj.db.lookUpDomId(edge.start), diagObj.db.lookUpDomId(edge.end), edgeData, cnt); g.setEdge(diagObj.db.lookUpDomId(edge.start), diagObj.db.lookUpDomId(edge.end), edgeData, cnt);
}); }
}; };
/** /**
@ -298,7 +298,7 @@ export const getClasses = function (text, diagObj) {
* @param _version * @param _version
* @param diagObj * @param diagObj
*/ */
export const draw = function (text, id, _version, diagObj) { export const draw = async function (text, id, _version, diagObj) {
log.info('Drawing flowchart'); log.info('Drawing flowchart');
diagObj.db.clear(); diagObj.db.clear();
const { securityLevel, flowchart: conf } = getConfig(); const { securityLevel, flowchart: conf } = getConfig();
@ -372,8 +372,8 @@ export const draw = function (text, id, _version, diagObj) {
g.setParent(diagObj.db.lookUpDomId(subG.nodes[j]), diagObj.db.lookUpDomId(subG.id)); g.setParent(diagObj.db.lookUpDomId(subG.nodes[j]), diagObj.db.lookUpDomId(subG.id));
} }
} }
addVertices(vert, g, id, root, doc, diagObj); await addVertices(vert, g, id, root, doc, diagObj);
addEdges(edges, g, diagObj); await addEdges(edges, g, diagObj);
// Create the renderer // Create the renderer
const render = new Render(); const render = new Render();

View File

@ -237,7 +237,7 @@ interface NoteModel {
* @param elem - The diagram to draw to. * @param elem - The diagram to draw to.
* @param noteModel - Note model options. * @param noteModel - Note model options.
*/ */
const drawNote = function (elem: any, noteModel: NoteModel) { const drawNote = async function (elem: any, noteModel: NoteModel) {
bounds.bumpVerticalPos(conf.boxMargin); bounds.bumpVerticalPos(conf.boxMargin);
noteModel.height = conf.boxMargin; noteModel.height = conf.boxMargin;
noteModel.starty = bounds.getVerticalPos(); noteModel.starty = bounds.getVerticalPos();
@ -263,7 +263,7 @@ const drawNote = function (elem: any, noteModel: NoteModel) {
textObj.textMargin = conf.noteMargin; textObj.textMargin = conf.noteMargin;
textObj.valign = 'center'; textObj.valign = 'center';
const textElem = hasKatex(textObj.text) ? drawKatex(g, textObj) : drawText(g, textObj); const textElem = hasKatex(textObj.text) ? await drawKatex(g, textObj) : drawText(g, textObj);
const textHeight = Math.round( const textHeight = Math.round(
textElem textElem
@ -311,13 +311,13 @@ const actorFont = (cnf) => {
* @param msgModel - The model containing fields describing a message * @param msgModel - The model containing fields describing a message
* @returns `lineStartY` - The Y coordinate at which the message line starts * @returns `lineStartY` - The Y coordinate at which the message line starts
*/ */
function boundMessage(_diagram, msgModel): number { async function boundMessage(_diagram, msgModel): number {
bounds.bumpVerticalPos(10); bounds.bumpVerticalPos(10);
const { startx, stopx, message } = msgModel; const { startx, stopx, message } = msgModel;
const lines = common.splitBreaks(message).length; const lines = common.splitBreaks(message).length;
const isKatexMsg = hasKatex(message); const isKatexMsg = hasKatex(message);
const textDims = isKatexMsg const textDims = isKatexMsg
? calculateMathMLDimensions(message, configApi.getConfig()) ? await calculateMathMLDimensions(message, configApi.getConfig())
: utils.calculateTextDimensions(message, messageFont(conf)); : utils.calculateTextDimensions(message, messageFont(conf));
if (!isKatexMsg) { if (!isKatexMsg) {
@ -365,7 +365,7 @@ function boundMessage(_diagram, msgModel): number {
* @param lineStartY - The Y coordinate at which the message line starts * @param lineStartY - The Y coordinate at which the message line starts
* @param diagObj - The diagram object. * @param diagObj - The diagram object.
*/ */
const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Diagram) { const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel; const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
const textDims = utils.calculateTextDimensions(message, messageFont(conf)); const textDims = utils.calculateTextDimensions(message, messageFont(conf));
const textObj = svgDrawCommon.getTextObj(); const textObj = svgDrawCommon.getTextObj();
@ -384,7 +384,7 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
textObj.tspan = false; textObj.tspan = false;
hasKatex(textObj.text) hasKatex(textObj.text)
? drawKatex(diagram, textObj, { startx, stopx, starty: lineStartY }) ? await drawKatex(diagram, textObj, { startx, stopx, starty: lineStartY })
: drawText(diagram, textObj); : drawText(diagram, textObj);
const textWidth = textDims.width; const textWidth = textDims.width;
@ -485,7 +485,7 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
} }
}; };
export const drawActors = function ( export const drawActors = async function (
diagram, diagram,
actors, actors,
actorKeys, actorKeys,
@ -539,7 +539,7 @@ export const drawActors = function (
actor.y = bounds.getVerticalPos(); actor.y = bounds.getVerticalPos();
// Draw the box with the attached line // Draw the box with the attached line
const height = svgDraw.drawActor(diagram, actor, conf, isFooter); const height = await svgDraw.drawActor(diagram, actor, conf, isFooter);
maxHeight = common.getMax(maxHeight, height); maxHeight = common.getMax(maxHeight, height);
bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height); bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height);
@ -648,7 +648,7 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
* @param _version - Mermaid version from package.json * @param _version - Mermaid version from package.json
* @param diagObj - A standard diagram containing the db and the text and type etc of the diagram * @param diagObj - A standard diagram containing the db and the text and type etc of the diagram
*/ */
export const draw = function (_text: string, id: string, _version: string, diagObj: Diagram) { export const draw = async function (_text: string, id: string, _version: string, diagObj: Diagram) {
const { securityLevel, sequence } = configApi.getConfig(); const { securityLevel, sequence } = configApi.getConfig();
conf = sequence; conf = sequence;
diagObj.db.clear(); diagObj.db.clear();
@ -679,8 +679,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
const title = diagObj.db.getDiagramTitle(); const title = diagObj.db.getDiagramTitle();
const hasBoxes = diagObj.db.hasAtLeastOneBox(); const hasBoxes = diagObj.db.hasAtLeastOneBox();
const hasBoxTitles = diagObj.db.hasAtLeastOneBoxWithTitle(); const hasBoxTitles = diagObj.db.hasAtLeastOneBoxWithTitle();
const maxMessageWidthPerActor = getMaxMessageWidthPerActor(actors, messages, diagObj); const maxMessageWidthPerActor = await getMaxMessageWidthPerActor(actors, messages, diagObj);
conf.height = calculateActorMargins(actors, maxMessageWidthPerActor, boxes); conf.height = await calculateActorMargins(actors, maxMessageWidthPerActor, boxes);
svgDraw.insertComputerIcon(diagram); svgDraw.insertComputerIcon(diagram);
svgDraw.insertDatabaseIcon(diagram); svgDraw.insertDatabaseIcon(diagram);
@ -693,8 +693,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
} }
} }
drawActors(diagram, actors, actorKeys, 0, conf, messages, false); await drawActors(diagram, actors, actorKeys, 0, conf, messages, false);
const loopWidths = calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj); const loopWidths = await calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
// The arrow head definition is attached to the svg once // The arrow head definition is attached to the svg once
svgDraw.insertArrowHead(diagram); svgDraw.insertArrowHead(diagram);
@ -727,14 +727,14 @@ export const draw = function (_text: string, id: string, _version: string, diagO
let sequenceIndex = 1; let sequenceIndex = 1;
let sequenceIndexStep = 1; let sequenceIndexStep = 1;
const messagesToDraw = []; const messagesToDraw = [];
messages.forEach(function (msg) { for (const msg of messages) {
let loopModel, noteModel, msgModel; let loopModel, noteModel, msgModel;
switch (msg.type) { switch (msg.type) {
case diagObj.db.LINETYPE.NOTE: case diagObj.db.LINETYPE.NOTE:
bounds.resetVerticalPos(); bounds.resetVerticalPos();
noteModel = msg.noteModel; noteModel = msg.noteModel;
drawNote(diagram, noteModel); await drawNote(diagram, noteModel);
break; break;
case diagObj.db.LINETYPE.ACTIVE_START: case diagObj.db.LINETYPE.ACTIVE_START:
bounds.newActivation(msg, diagram, actors); bounds.newActivation(msg, diagram, actors);
@ -753,7 +753,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break; break;
case diagObj.db.LINETYPE.LOOP_END: case diagObj.db.LINETYPE.LOOP_END:
loopModel = bounds.endLoop(); loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'loop', conf); await svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos()); bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel); bounds.models.addLoop(loopModel);
break; break;
@ -779,7 +779,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break; break;
case diagObj.db.LINETYPE.OPT_END: case diagObj.db.LINETYPE.OPT_END:
loopModel = bounds.endLoop(); loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'opt', conf); await svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos()); bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel); bounds.models.addLoop(loopModel);
break; break;
@ -803,7 +803,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break; break;
case diagObj.db.LINETYPE.ALT_END: case diagObj.db.LINETYPE.ALT_END:
loopModel = bounds.endLoop(); loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'alt', conf); await svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos()); bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel); bounds.models.addLoop(loopModel);
break; break;
@ -829,7 +829,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break; break;
case diagObj.db.LINETYPE.PAR_END: case diagObj.db.LINETYPE.PAR_END:
loopModel = bounds.endLoop(); loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'par', conf); await svgDraw.drawLoop(diagram, loopModel, 'par', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos()); bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel); bounds.models.addLoop(loopModel);
break; break;
@ -862,7 +862,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break; break;
case diagObj.db.LINETYPE.CRITICAL_END: case diagObj.db.LINETYPE.CRITICAL_END:
loopModel = bounds.endLoop(); loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'critical', conf); await svgDraw.drawLoop(diagram, loopModel, 'critical', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos()); bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel); bounds.models.addLoop(loopModel);
break; break;
@ -877,7 +877,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break; break;
case diagObj.db.LINETYPE.BREAK_END: case diagObj.db.LINETYPE.BREAK_END:
loopModel = bounds.endLoop(); loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'break', conf); await svgDraw.drawLoop(diagram, loopModel, 'break', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos()); bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel); bounds.models.addLoop(loopModel);
break; break;
@ -889,7 +889,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
msgModel.starty = bounds.getVerticalPos(); msgModel.starty = bounds.getVerticalPos();
msgModel.sequenceIndex = sequenceIndex; msgModel.sequenceIndex = sequenceIndex;
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers(); msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
const lineStartY = boundMessage(diagram, msgModel); const lineStartY = await boundMessage(diagram, msgModel);
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY }); messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
bounds.models.addMessage(msgModel); bounds.models.addMessage(msgModel);
} catch (e) { } catch (e) {
@ -912,19 +912,21 @@ export const draw = function (_text: string, id: string, _version: string, diagO
) { ) {
sequenceIndex = sequenceIndex + sequenceIndexStep; sequenceIndex = sequenceIndex + sequenceIndexStep;
} }
}); }
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj)); for (const e of messagesToDraw) {
await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj);
}
if (conf.mirrorActors) { if (conf.mirrorActors) {
// Draw actors below diagram // Draw actors below diagram
bounds.bumpVerticalPos(conf.boxMargin * 2); bounds.bumpVerticalPos(conf.boxMargin * 2);
drawActors(diagram, actors, actorKeys, bounds.getVerticalPos(), conf, messages, true); await drawActors(diagram, actors, actorKeys, bounds.getVerticalPos(), conf, messages, true);
bounds.bumpVerticalPos(conf.boxMargin); bounds.bumpVerticalPos(conf.boxMargin);
fixLifeLineHeights(diagram, bounds.getVerticalPos()); fixLifeLineHeights(diagram, bounds.getVerticalPos());
} }
bounds.models.boxes.forEach(function (box) { for (const box of bounds.models.boxes) {
box.height = bounds.getVerticalPos() - box.y; box.height = bounds.getVerticalPos() - box.y;
bounds.insert(box.x, box.y, box.x + box.width, box.height); bounds.insert(box.x, box.y, box.x + box.width, box.height);
box.startx = box.x; box.startx = box.x;
@ -932,8 +934,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
box.stopx = box.startx + box.width; box.stopx = box.startx + box.width;
box.stopy = box.starty + box.height; box.stopy = box.starty + box.height;
box.stroke = 'rgb(0,0,0, 0.5)'; box.stroke = 'rgb(0,0,0, 0.5)';
svgDraw.drawBox(diagram, box, conf); await svgDraw.drawBox(diagram, box, conf);
}); }
if (hasBoxes) { if (hasBoxes) {
bounds.bumpVerticalPos(conf.boxMargin); bounds.bumpVerticalPos(conf.boxMargin);
@ -1004,14 +1006,14 @@ export const draw = function (_text: string, id: string, _version: string, diagO
* @param diagObj - The diagram object. * @param diagObj - The diagram object.
* @returns The max message width of each actor. * @returns The max message width of each actor.
*/ */
function getMaxMessageWidthPerActor( async function getMaxMessageWidthPerActor(
actors: { [id: string]: any }, actors: { [id: string]: any },
messages: any[], messages: any[],
diagObj: Diagram diagObj: Diagram
): { [id: string]: number } { ): Promise<{ [id: string]: number }> {
const maxMessageWidthPerActor = {}; const maxMessageWidthPerActor = {};
messages.forEach(function (msg) { for (const msg of messages) {
if (actors[msg.to] && actors[msg.from]) { if (actors[msg.to] && actors[msg.from]) {
const actor = actors[msg.to]; const actor = actors[msg.to];
@ -1033,7 +1035,7 @@ function getMaxMessageWidthPerActor(
? utils.wrapLabel(msg.message, conf.width - 2 * conf.wrapPadding, textFont) ? utils.wrapLabel(msg.message, conf.width - 2 * conf.wrapPadding, textFont)
: msg.message; : msg.message;
const messageDimensions = hasKatex(wrappedMessage) const messageDimensions = hasKatex(wrappedMessage)
? calculateMathMLDimensions(msg.message, configApi.getConfig()) ? await calculateMathMLDimensions(msg.message, configApi.getConfig())
: utils.calculateTextDimensions(wrappedMessage, textFont); : utils.calculateTextDimensions(wrappedMessage, textFont);
const messageWidth = messageDimensions.width + 2 * conf.wrapPadding; const messageWidth = messageDimensions.width + 2 * conf.wrapPadding;
@ -1099,7 +1101,7 @@ function getMaxMessageWidthPerActor(
} }
} }
} }
}); }
log.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor); log.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
return maxMessageWidthPerActor; return maxMessageWidthPerActor;
@ -1130,13 +1132,13 @@ const getRequiredPopupWidth = function (actor) {
* @param actorToMessageWidth - A map of actor key max message width it holds * @param actorToMessageWidth - A map of actor key max message width it holds
* @param boxes - The boxes around the actors if any * @param boxes - The boxes around the actors if any
*/ */
function calculateActorMargins( async function calculateActorMargins(
actors: { [id: string]: any }, actors: { [id: string]: any },
actorToMessageWidth: ReturnType<typeof getMaxMessageWidthPerActor>, actorToMessageWidth: Awaited<ReturnType<typeof getMaxMessageWidthPerActor>>,
boxes boxes
) { ) {
let maxHeight = 0; let maxHeight = 0;
Object.keys(actors).forEach((prop) => { for (const prop of Object.keys(actors)) {
const actor = actors[prop]; const actor = actors[prop];
if (actor.wrap) { if (actor.wrap) {
actor.description = utils.wrapLabel( actor.description = utils.wrapLabel(
@ -1146,7 +1148,7 @@ function calculateActorMargins(
); );
} }
const actDims = hasKatex(actor.description) const actDims = hasKatex(actor.description)
? calculateMathMLDimensions(actor.description, configApi.getConfig()) ? await calculateMathMLDimensions(actor.description, configApi.getConfig())
: utils.calculateTextDimensions(actor.description, actorFont(conf)); : utils.calculateTextDimensions(actor.description, actorFont(conf));
actor.width = actor.wrap actor.width = actor.wrap
@ -1155,7 +1157,7 @@ function calculateActorMargins(
actor.height = actor.wrap ? common.getMax(actDims.height, conf.height) : conf.height; actor.height = actor.wrap ? common.getMax(actDims.height, conf.height) : conf.height;
maxHeight = common.getMax(maxHeight, actor.height); maxHeight = common.getMax(maxHeight, actor.height);
}); }
for (const actorKey in actorToMessageWidth) { for (const actorKey in actorToMessageWidth) {
const actor = actors[actorKey]; const actor = actors[actorKey];
@ -1206,13 +1208,13 @@ function calculateActorMargins(
return common.getMax(maxHeight, conf.height); return common.getMax(maxHeight, conf.height);
} }
const buildNoteModel = function (msg, actors, diagObj) { const buildNoteModel = async function (msg, actors, diagObj) {
const startx = actors[msg.from].x; const startx = actors[msg.from].x;
const stopx = actors[msg.to].x; const stopx = actors[msg.to].x;
const shouldWrap = msg.wrap && msg.message; const shouldWrap = msg.wrap && msg.message;
let textDimensions: { width: number; height: number; lineHeight?: number } = hasKatex(msg.message) let textDimensions: { width: number; height: number; lineHeight?: number } = hasKatex(msg.message)
? calculateMathMLDimensions(msg.message, configApi.getConfig()) ? await calculateMathMLDimensions(msg.message, configApi.getConfig())
: utils.calculateTextDimensions( : utils.calculateTextDimensions(
shouldWrap ? utils.wrapLabel(msg.message, conf.width, noteFont(conf)) : msg.message, shouldWrap ? utils.wrapLabel(msg.message, conf.width, noteFont(conf)) : msg.message,
noteFont(conf) noteFont(conf)
@ -1338,12 +1340,12 @@ const buildMessageModel = function (msg, actors, diagObj) {
}; };
}; };
const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagObj) { const calculateLoopBounds = async function (messages, actors, _maxWidthPerActor, diagObj) {
const loops = {}; const loops = {};
const stack = []; const stack = [];
let current, noteModel, msgModel; let current, noteModel, msgModel;
messages.forEach(function (msg) { for (const msg of messages) {
msg.id = utils.random({ length: 10 }); msg.id = utils.random({ length: 10 });
switch (msg.type) { switch (msg.type) {
case diagObj.db.LINETYPE.LOOP_START: case diagObj.db.LINETYPE.LOOP_START:
@ -1406,7 +1408,7 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
} }
const isNote = msg.placement !== undefined; const isNote = msg.placement !== undefined;
if (isNote) { if (isNote) {
noteModel = buildNoteModel(msg, actors, diagObj); noteModel = await buildNoteModel(msg, actors, diagObj);
msg.noteModel = noteModel; msg.noteModel = noteModel;
stack.forEach((stk) => { stack.forEach((stk) => {
current = stk; current = stk;
@ -1445,7 +1447,7 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
}); });
} }
} }
}); }
bounds.activations = []; bounds.activations = [];
log.debug('Loop type widths:', loops); log.debug('Loop type widths:', loops);
return loops; return loops;

View File

@ -119,9 +119,9 @@ const popupMenuDownFunc = function (popupId) {
} }
}; };
export const drawKatex = function (elem, textData, msgModel = null) { export const drawKatex = async function (elem, textData, msgModel = null) {
let textElem = elem.append('foreignObject'); let textElem = elem.append('foreignObject');
const lines = renderKatex(textData.text, configApi.getConfig()); const lines = await renderKatex(textData.text, configApi.getConfig());
const divElem = textElem const divElem = textElem
.append('xhtml:div') .append('xhtml:div')
@ -353,7 +353,7 @@ export const fixLifeLineHeights = (diagram, bounds) => {
* @param {any} conf - DrawText implementation discriminator object * @param {any} conf - DrawText implementation discriminator object
* @param {boolean} isFooter - If the actor is the footer one * @param {boolean} isFooter - If the actor is the footer one
*/ */
const drawActorTypeParticipant = function (elem, actor, conf, isFooter) { const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
const center = actor.x + actor.width / 2; const center = actor.x + actor.width / 2;
const centerY = actor.y + 5; const centerY = actor.y + 5;
@ -407,7 +407,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
} }
} }
_drawTextCandidateFunc(conf, hasKatex(actor.description))( await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
actor.description, actor.description,
g, g,
rect.x, rect.x,
@ -428,10 +428,9 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
return height; return height;
}; };
const drawActorTypeActor = function (elem, actor, conf, isFooter) { const drawActorTypeActor = async function (elem, actor, conf, isFooter) {
const center = actor.x + actor.width / 2; const center = actor.x + actor.width / 2;
const centerY = actor.y + 80; const centerY = actor.y + 80;
if (!isFooter) { if (!isFooter) {
actorCnt++; actorCnt++;
elem elem
@ -496,7 +495,7 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
const bounds = actElem.node().getBBox(); const bounds = actElem.node().getBBox();
actor.height = bounds.height; actor.height = bounds.height;
_drawTextCandidateFunc(conf, hasKatex(actor.description))( await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
actor.description, actor.description,
actElem, actElem,
rect.x, rect.x,
@ -510,21 +509,21 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
return actor.height; return actor.height;
}; };
export const drawActor = function (elem, actor, conf, isFooter) { export const drawActor = async function (elem, actor, conf, isFooter) {
switch (actor.type) { switch (actor.type) {
case 'actor': case 'actor':
return drawActorTypeActor(elem, actor, conf, isFooter); return await drawActorTypeActor(elem, actor, conf, isFooter);
case 'participant': case 'participant':
return drawActorTypeParticipant(elem, actor, conf, isFooter); return await drawActorTypeParticipant(elem, actor, conf, isFooter);
} }
}; };
export const drawBox = function (elem, box, conf) { export const drawBox = async function (elem, box, conf) {
const boxplustextGroup = elem.append('g'); const boxplustextGroup = elem.append('g');
const g = boxplustextGroup; const g = boxplustextGroup;
drawBackgroundRect(g, box); drawBackgroundRect(g, box);
if (box.name) { if (box.name) {
_drawTextCandidateFunc(conf)( await _drawTextCandidateFunc(conf)(
box.name, box.name,
g, g,
box.x, box.x,
@ -571,7 +570,7 @@ export const drawActivation = function (elem, bounds, verticalPos, conf, actorAc
* @param {any} conf - Diagram configuration * @param {any} conf - Diagram configuration
* @returns {any} * @returns {any}
*/ */
export const drawLoop = function (elem, loopModel, labelText, conf) { export const drawLoop = async function (elem, loopModel, labelText, conf) {
const { const {
boxMargin, boxMargin,
boxTextMargin, boxTextMargin,
@ -633,10 +632,10 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
txt.fontWeight = fontWeight; txt.fontWeight = fontWeight;
txt.wrap = true; txt.wrap = true;
let textElem = hasKatex(txt.text) ? drawKatex(g, txt, loopModel) : drawText(g, txt); let textElem = hasKatex(txt.text) ? await drawKatex(g, txt, loopModel) : drawText(g, txt);
if (loopModel.sectionTitles !== undefined) { if (loopModel.sectionTitles !== undefined) {
loopModel.sectionTitles.forEach(function (item, idx) { for (const [idx, item] of Object.entries(loopModel.sectionTitles)) {
if (item.message) { if (item.message) {
txt.text = item.message; txt.text = item.message;
txt.x = loopModel.startx + (loopModel.stopx - loopModel.startx) / 2; txt.x = loopModel.startx + (loopModel.stopx - loopModel.startx) / 2;
@ -652,7 +651,7 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
if (hasKatex(txt.text)) { if (hasKatex(txt.text)) {
loopModel.starty = loopModel.sections[idx].y; loopModel.starty = loopModel.sections[idx].y;
drawKatex(g, txt, loopModel); await drawKatex(g, txt, loopModel);
} else { } else {
drawText(g, txt); drawText(g, txt);
} }
@ -663,7 +662,7 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
); );
loopModel.sections[idx].height += sectionHeight - (boxMargin + boxTextMargin); loopModel.sections[idx].height += sectionHeight - (boxMargin + boxTextMargin);
} }
}); }
} }
loopModel.height = Math.round(loopModel.stopy - loopModel.starty); loopModel.height = Math.round(loopModel.stopy - loopModel.starty);
@ -951,9 +950,10 @@ const _drawTextCandidateFunc = (function () {
* @param textAttrs * @param textAttrs
* @param conf * @param conf
*/ */
function byKatex(content, g, x, y, width, height, textAttrs, conf) { async function byKatex(content, g, x, y, width, height, textAttrs, conf) {
// TODO duplicate render calls, optimize // TODO duplicate render calls, optimize
const dim = calculateMathMLDimensions(content, configApi.getConfig());
const dim = await calculateMathMLDimensions(content, configApi.getConfig());
const s = g.append('switch'); const s = g.append('switch');
const f = s const f = s
.append('foreignObject') .append('foreignObject')
@ -968,7 +968,7 @@ const _drawTextCandidateFunc = (function () {
.append('div') .append('div')
.style('text-align', 'center') .style('text-align', 'center')
.style('vertical-align', 'middle') .style('vertical-align', 'middle')
.html(renderKatex(content, configApi.getConfig())); .html(await renderKatex(content, configApi.getConfig()));
byTspan(content, s, x, y, width, height, textAttrs, conf); byTspan(content, s, x, y, width, height, textAttrs, conf);
_setTextAttrs(text, textAttrs); _setTextAttrs(text, textAttrs);