feat(katex): added common functions for aiding in KaTeX rendering
This commit is contained in:
parent
e0e038d223
commit
f8a4488050
|
@ -14,7 +14,7 @@
|
|||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:2115](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2115)
|
||||
[defaultConfig.ts:2126](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2126)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ export interface MermaidConfig {
|
|||
dompurifyConfig?: DOMPurify.Config;
|
||||
wrap?: boolean;
|
||||
fontSize?: number;
|
||||
legacyMathML?: boolean;
|
||||
}
|
||||
|
||||
// TODO: More configs needs to be moved in here
|
||||
|
|
|
@ -131,6 +131,17 @@ const config: Partial<MermaidConfig> = {
|
|||
* Default value: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize']
|
||||
*/
|
||||
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize'],
|
||||
/**
|
||||
* This option specifies if Mermaid can expected the dependnet to include KaTeX stylesheets for browsers
|
||||
* without their own MathML implementation. If this option is disabled and MathML is not supported, the math
|
||||
* equations are replaced with a warning. If this option is enabled and MathML is not supported, Mermaid will
|
||||
* fall back to legacy rendering for KaTeX.
|
||||
*
|
||||
* **Notes**:
|
||||
*
|
||||
* Default value: false
|
||||
*/
|
||||
legacyMathML: false,
|
||||
/**
|
||||
* This option controls if the generated ids of nodes in the SVG are generated randomly or based
|
||||
* on a seed. If set to false, the IDs are generated based on the current date and thus are not
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import DOMPurify from 'dompurify';
|
||||
// @ts-ignore @types/katex does not work
|
||||
import katex from 'katex';
|
||||
import { MermaidConfig } from '../../config.type.js';
|
||||
|
||||
/**
|
||||
|
@ -170,6 +172,62 @@ export const parseGenericTypes = function (text: string): string {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO: find a better method for detecting support. This interface was added in the MathML 4 spec.
|
||||
// Firefox versions between [4,71] (0.47%) and Safari versions between [5,13.4] (0.17%) don't have this interface implemented but MathML is supported
|
||||
export const isMathMLSupported = window.MathMLElement !== undefined;
|
||||
|
||||
export const katexRegex = /\$\$(.*)\$\$/g;
|
||||
|
||||
/**
|
||||
* Whether or not a text has KaTeX delimiters
|
||||
*
|
||||
* @param text - The text to test
|
||||
* @returns Whether or not the text has KaTeX delimiters
|
||||
*/
|
||||
export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.length ?? 0) > 0;
|
||||
|
||||
/**
|
||||
* Computes the minimum dimensions needed to display a div contianing MathML
|
||||
*
|
||||
* @param text - The text to test
|
||||
* @param config - Configuration for Mermaid
|
||||
* @returns Object containing {width, height}
|
||||
*/
|
||||
export const calculateMathMLDimensions = (text: string, config: MermaidConfig) => {
|
||||
text = renderKatex(text, config).split(lineBreakRegex).map((text) => hasKatex(text) ? renderKatex(text, config) : `<div>${text}</div>`).join('');
|
||||
const divElem = document.createElement('div')
|
||||
divElem.innerHTML = text;
|
||||
divElem.id = 'katex-temp';
|
||||
divElem.style.visibility = 'hidden';
|
||||
divElem.style.position = 'absolute';
|
||||
divElem.style.top = '0';
|
||||
const body = document.querySelector('body');
|
||||
body?.insertAdjacentElement('beforeend', divElem);
|
||||
const dim = {width: divElem.clientWidth, height: divElem.clientHeight};
|
||||
divElem.remove();
|
||||
return dim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to render and return the KaTeX portion of a string with MathML
|
||||
*
|
||||
* @param text - The text to test
|
||||
* @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
|
||||
*/
|
||||
export const renderKatex = (text: string, config: MermaidConfig): string => {
|
||||
if (isMathMLSupported || (!isMathMLSupported && config.legacyMathML)) {
|
||||
return text.replace(/\$\$(.*)\$\$/g, (r, c) =>
|
||||
katex
|
||||
.renderToString(c, { throwOnError: true, displayMode: true, output: isMathMLSupported ? 'mathml' : 'htmlAndMathml' })
|
||||
.replace(/\n/g, ' ')
|
||||
.replace(/<annotation.*<\/annotation>/g, '')
|
||||
);
|
||||
}
|
||||
return text.replace(/\$\$(.*)\$\$/g, (r, c) => 'MathML is unsupported in this environment.');
|
||||
};
|
||||
|
||||
export default {
|
||||
getRows,
|
||||
sanitizeText,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { select, curveLinear, selectAll } from 'd3';
|
||||
import katex from 'katex';
|
||||
|
||||
import flowDb from './flowDb.js';
|
||||
import { getConfig } from '../../config.js';
|
||||
|
@ -9,7 +8,7 @@ import utils from '../../utils.js';
|
|||
import { render } from '../../dagre-wrapper/index.js';
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { log } from '../../logger.js';
|
||||
import common, { evaluate } from '../common/common.js';
|
||||
import common, { evaluate, renderKatex } from '../common/common.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
|
||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
|
||||
|
@ -144,12 +143,8 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
|
|||
default:
|
||||
_shape = 'rect';
|
||||
}
|
||||
const labelText = vertexText.replace(/\$\$(.*)\$\$/g, (r, c) =>
|
||||
katex
|
||||
.renderToString(c, { throwOnError: true, displayMode: true, output: 'mathml' })
|
||||
.replace(/\n/g, ' ')
|
||||
.replace(/<annotation.*<\/annotation>/g, '')
|
||||
);
|
||||
const labelText = renderKatex(vertexText, getConfig());
|
||||
|
||||
// Add the node
|
||||
g.setNode(vertex.id, {
|
||||
labelStyle: styles.labelStyle,
|
||||
|
@ -323,14 +318,7 @@ export const addEdges = function (edges, g, diagObj) {
|
|||
edgeData.labelpos = 'c';
|
||||
}
|
||||
edgeData.labelType = edge.labelType;
|
||||
edgeData.label = edge.text
|
||||
.replace(common.lineBreakRegex, '\n')
|
||||
.replace(/\$\$(.*)\$\$/g, (r, c) =>
|
||||
katex
|
||||
.renderToString(c, { throwOnError: true, displayMode: true, output: 'mathml' })
|
||||
.replace(/\n/g, ' ')
|
||||
.replace(/<annotation.*<\/annotation>/g, '')
|
||||
);
|
||||
edgeData.label = renderKatex(edge.text.replace(common.lineBreakRegex, '\n')), getConfig();
|
||||
|
||||
if (edge.style === undefined) {
|
||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { select, curveLinear, selectAll } from 'd3';
|
||||
import katex from 'katex';
|
||||
import { getConfig } from '../../config.js';
|
||||
import { render as Render } from 'dagre-d3-es';
|
||||
import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js';
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { log } from '../../logger.js';
|
||||
import common, { evaluate } from '../common/common.js';
|
||||
import common, { evaluate, renderKatex } from '../common/common.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
|
||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import flowChartShapes from './flowChartShapes.js';
|
||||
|
@ -58,14 +57,12 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
|
|||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
const node = {
|
||||
label: vertexText
|
||||
.replace(/fa[blrs]?:fa-[\w-]+/g, (s) => `<i class='${s.replace(':', ' ')}'></i>`)
|
||||
.replace(/\$\$(.*)\$\$/g, (r, c) =>
|
||||
katex
|
||||
.renderToString(c, { throwOnError: true, displayMode: true, output: 'mathml' })
|
||||
.replace(/\n/g, ' ')
|
||||
.replace(/<annotation.*<\/annotation>/g, '')
|
||||
),
|
||||
label: renderKatex(
|
||||
vertexText.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g,
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
)
|
||||
),
|
||||
};
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
|
@ -244,14 +241,9 @@ export const addEdges = function (edges, g, diagObj) {
|
|||
edgeData.labelType = 'html';
|
||||
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${
|
||||
edgeData.labelStyle
|
||||
}">${edge.text
|
||||
.replace(/fa[blrs]?:fa-[\w-]+/g, (s) => `<i class='${s.replace(':', ' ')}'></i>`)
|
||||
.replace(/\$\$(.*)\$\$/g, (r, c) =>
|
||||
katex
|
||||
.renderToString(c, { throwOnError: true, displayMode: true, output: 'mathml' })
|
||||
.replace(/\n/g, ' ')
|
||||
.replace(/<annotation.*<\/annotation>/g, '')
|
||||
)}</span>`;
|
||||
}">${renderKatex(
|
||||
edge.text.replace(/fa[blrs]?:fa-[\w-]+/g, (s) => `<i class='${s.replace(':', ' ')}'></i>`)
|
||||
)}</span>`;
|
||||
} else {
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
|
Loading…
Reference in New Issue