Compare commits

..

16 Commits

Author SHA1 Message Date
github-merge-queue[bot]
c5d3244511 Update docs 2024-05-08 05:31:45 +00:00
Sidharth Vinod
c41cdcaf23 Merge pull request #5503 from igorwessel/feat/add-from-to-id-in-edge
feat(state): add from, to ids for edge
2024-05-08 05:21:44 +00:00
Sidharth Vinod
99d3701a85 Merge pull request #5504 from mermaid-js/renovate/patch-all-patch
chore(deps): update all patch dependencies (patch)
2024-05-08 05:19:01 +00:00
Sidharth Vinod
6413529a6e Merge pull request #5490 from Timac/patch-1
Update integrations-community: Add MarkChart, a macOS app to preview …
2024-05-08 10:54:14 +05:30
Sidharth Vinod
f5e1df08a0 Merge pull request #5483 from NicolasNewman/5435/inconsistent-math-rendering
fix: inconsistent MathML rendering & erroneous <br />s being added
2024-05-08 10:53:52 +05:30
renovate[bot]
472a883c73 chore(deps): update all patch dependencies 2024-05-07 00:41:35 +00:00
Nicolas Newman
22bd26272d Merge branch 'develop' into 5435/inconsistent-math-rendering 2024-05-06 09:53:11 -05:00
Igor Wessel
da150e8767 feat: use standard edge id function for class,flow,state diagram 2024-05-06 08:07:47 -03:00
Igor Wessel
1f64452716 feat(utils): create a standard edge id function 2024-05-06 07:46:42 -03:00
Igor Wessel
9986b023d7 feat(state): add from, to in edge 2024-05-04 06:21:12 -03:00
NicolasNewman
c4ccfec316 Update docs 2024-04-29 14:49:56 +00:00
NicolasNewman
1ac9244e68 style(mathml): linting 2024-04-29 09:46:50 -05:00
Alexandre Colucci
18defaae6d Update integrations-community: Add MarkChart, a macOS app to preview Mermaid diagrams 2024-04-26 08:17:40 +02:00
NicolasNewman
7f33ae0f40 fix(mathml): fixed flowchart equations being cut off 2024-04-22 17:15:10 -05:00
NicolasNewman
13aa3265e3 docs(mathml): updated docs to include forceLegacyMathML 2024-04-22 17:14:36 -05:00
NicolasNewman
3b0687e557 feat(mathml): added additional config option for forcing legacy rendering 2024-04-22 17:12:12 -05:00
19 changed files with 566 additions and 1172 deletions

View File

@@ -55,6 +55,7 @@ export const imgSnapshotTest = (
const options: CypressMermaidConfig = {
..._options,
fontFamily: _options.fontFamily || 'courier',
// @ts-ignore TODO: Fix type of fontSize
fontSize: _options.fontSize || '16px',
sequence: {
...(_options.sequence || {}),

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -84,3 +84,13 @@ Example with legacy mode enabled (the latest version of KaTeX's stylesheet can b
</body>
</html>
```
## Handling Rendering Differences
Due to differences between default fonts across operating systems and browser's MathML implementations, inconsistent results can be seen across platforms. If having consistent results are important, or the most optimal rendered results are desired, `forceLegacyMathML` can be enabled in the config.
This option will always use KaTeX's stylesheet instead of only when MathML is not supported (as with `legacyMathML`). Note that only `forceLegacyMathML` needs to be set.
If including KaTeX's stylesheet is not a concern, enabling this option is recommended to avoid scenarios where no MathML implementation within a browser provides the desired output (as seen below).
![Image showing differences between Browsers](img/mathMLDifferences.png)

View File

@@ -249,6 +249,7 @@ Communication tools and platforms
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/)
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) ✅

View File

@@ -120,6 +120,13 @@ export interface MermaidConfig {
*
*/
legacyMathML?: boolean;
/**
* This option forces Mermaid to rely on KaTeX's own stylesheet for rendering MathML. Due to differences between OS
* fonts and browser's MathML implementation, this option is recommended if consistent rendering is important.
* If set to true, ignores legacyMathML.
*
*/
forceLegacyMathML?: boolean;
/**
* This option controls if the generated ids of nodes in the SVG are
* generated randomly or based on a seed.
@@ -158,7 +165,7 @@ export interface MermaidConfig {
block?: BlockDiagramConfig;
dompurifyConfig?: DOMPurifyConfiguration;
wrap?: boolean;
fontSize?: string | number;
fontSize?: number;
markdownAutoWrap?: boolean;
/**
* Suppresses inserting 'Syntax error' diagram in the DOM.

View File

@@ -4,7 +4,7 @@ import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { log } from '../../logger.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import { render } from '../../dagre-wrapper/index.js';
import utils from '../../utils.js';
import utils, { getEdgeId } from '../../utils.js';
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import common from '../common/common.js';
@@ -231,7 +231,10 @@ export const addRelations = function (relations: ClassRelation[], g: graphlib.Gr
//Set relationship style and line type
classes: 'relation',
pattern: edge.relation.lineType == 1 ? 'dashed' : 'solid',
id: `id_${edge.id1}_${edge.id2}_${cnt}`,
id: getEdgeId(edge.id1, edge.id2, {
prefix: 'id',
counter: cnt,
}),
// Set link type for rendering
arrowhead: edge.type === 'arrow_open' ? 'none' : 'normal',
//Set edge extra labels

View File

@@ -337,18 +337,20 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
return text;
}
if (!isMathMLSupported() && !config.legacyMathML) {
if (!(isMathMLSupported() || config.legacyMathML || config.forceLegacyMathML)) {
return text.replace(katexRegex, 'MathML is unsupported in this environment.');
}
const { default: katex } = await import('katex');
const outputMode =
config.forceLegacyMathML || (!isMathMLSupported() && config.legacyMathML)
? 'htmlAndMathml'
: 'mathml';
return text
.split(lineBreakRegex)
.map((line) =>
hasKatex(line)
? `<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">
${line}
</div>`
? `<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">${line}</div>`
: `<div>${line}</div>`
)
.join('')
@@ -357,7 +359,7 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
.renderToString(c, {
throwOnError: true,
displayMode: true,
output: isMathMLSupported() ? 'mathml' : 'htmlAndMathml',
output: outputMode,
})
.replace(/\n/g, ' ')
.replace(/<annotation.*<\/annotation>/g, '')

View File

@@ -1,7 +1,7 @@
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { select, curveLinear, selectAll } from 'd3';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import utils from '../../utils.js';
import utils, { getEdgeId } 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';
@@ -210,7 +210,11 @@ export const addEdges = async function (edges, g, diagObj) {
cnt++;
// Identify Link
const linkIdBase = 'L-' + edge.start + '-' + edge.end;
const linkIdBase = getEdgeId(edge.start, edge.end, {
counter: cnt,
prefix: 'L',
});
// count the links from+to the same node to give unique id
if (linkIdCnt[linkIdBase] === undefined) {
linkIdCnt[linkIdBase] = 0;
@@ -219,7 +223,8 @@ export const addEdges = async function (edges, g, diagObj) {
linkIdCnt[linkIdBase]++;
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
}
let linkId = linkIdBase + '-' + linkIdCnt[linkIdBase];
let linkId = `${linkIdBase}_${linkIdCnt[linkIdBase]}`;
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
const linkNameStart = 'LS-' + edge.start;
const linkNameEnd = 'LE-' + edge.end;

View File

@@ -6,7 +6,7 @@ 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, renderKatex } from '../common/common.js';
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
import { interpolateToCurve, getStylesFromArray, getEdgeId } from '../../utils.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import flowChartShapes from './flowChartShapes.js';
import { replaceIconSubstring } from '../../rendering-util/createText.js';
@@ -175,7 +175,10 @@ export const addEdges = async function (edges, g, diagObj) {
cnt++;
// Identify Link
const linkId = 'L-' + edge.start + '-' + edge.end;
const linkId = getEdgeId(edge.start, edge.end, {
counter: cnt,
prefix: 'L',
});
const linkNameStart = 'LS-' + edge.start;
const linkNameEnd = 'LE-' + edge.end;

View File

@@ -5,7 +5,7 @@ import { render } from '../../dagre-wrapper/index.js';
import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import common from '../common/common.js';
import utils from '../../utils.js';
import utils, { getEdgeId } from '../../utils.js';
import {
DEFAULT_DIAGRAM_DIRECTION,
@@ -252,7 +252,6 @@ const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) =>
type: 'group',
padding: 0, //getConfig().flowchart.padding
};
graphItemCount++;
const parentNodeId = itemId + PARENT_ID;
g.setNode(parentNodeId, groupData);
@@ -270,17 +269,23 @@ const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) =>
from = noteData.id;
to = itemId;
}
g.setEdge(from, to, {
arrowhead: 'none',
arrowType: '',
style: G_EDGE_STYLE,
labelStyle: '',
id: getEdgeId(from, to, {
counter: graphItemCount,
}),
classes: CSS_EDGE_NOTE_EDGE,
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
labelpos: G_EDGE_LABELPOS,
labelType: G_EDGE_LABELTYPE,
thickness: G_EDGE_THICKNESS,
});
graphItemCount++;
} else {
g.setNode(itemId, nodeData);
}
@@ -324,7 +329,9 @@ const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) =
setupNode(g, parentParsedItem, item.state1, diagramStates, diagramDb, altFlag);
setupNode(g, parentParsedItem, item.state2, diagramStates, diagramDb, altFlag);
const edgeData = {
id: 'edge' + graphItemCount,
id: getEdgeId(item.state1.id, item.state2.id, {
counter: graphItemCount,
}),
arrowhead: 'normal',
arrowTypeEnd: 'arrow_barb',
style: G_EDGE_STYLE,

View File

@@ -36,6 +36,7 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram
.attr('height', chartConfig.height)
.attr('class', 'background');
// @ts-ignore: TODO Fix ts errors
configureSvgSize(svg, chartConfig.height, chartConfig.width, true);
svg.attr('viewBox', `0 0 ${chartConfig.width} ${chartConfig.height}`);

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -60,3 +60,13 @@ Example with legacy mode enabled (the latest version of KaTeX's stylesheet can b
</body>
</html>
```
## Handling Rendering Differences
Due to differences between default fonts across operating systems and browser's MathML implementations, inconsistent results can be seen across platforms. If having consistent results are important, or the most optimal rendered results are desired, `forceLegacyMathML` can be enabled in the config.
This option will always use KaTeX's stylesheet instead of only when MathML is not supported (as with `legacyMathML`). Note that only `forceLegacyMathML` needs to be set.
If including KaTeX's stylesheet is not a concern, enabling this option is recommended to avoid scenarios where no MathML implementation within a browser provides the desired output (as seen below).
![Image showing differences between Browsers](img/mathMLDifferences.png)

View File

@@ -244,6 +244,7 @@ Communication tools and platforms
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/)
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) ✅

View File

@@ -10,8 +10,10 @@
*
* In addition to the render function, a number of behavioral configuration options are available.
*/
// @ts-ignore TODO: Investigate D3 issue
import { select } from 'd3';
import { compile, serialize, stringify } from 'stylis';
// @ts-ignore: TODO Fix ts errors
import { version } from '../package.json';
import * as configApi from './config.js';
import { addDiagrams } from './diagram-api/diagram-orchestration.js';

View File

@@ -180,6 +180,13 @@ properties:
fall back to legacy rendering for KaTeX.
type: boolean
default: false
forceLegacyMathML:
description: |
This option forces Mermaid to rely on KaTeX's own stylesheet for rendering MathML. Due to differences between OS
fonts and browser's MathML implementation, this option is recommended if consistent rendering is important.
If set to true, ignores legacyMathML.
type: boolean
default: false
deterministicIds:
description: |
This option controls if the generated ids of nodes in the SVG are

View File

@@ -1,5 +1,3 @@
import type { interpolateToCurve } from './utils.js';
export interface Point {
x: number;
y: number;
@@ -32,7 +30,7 @@ export interface EdgeData {
arrowTypeEnd: string;
style: string;
labelStyle: string;
curve: ReturnType<typeof interpolateToCurve>;
curve: any;
}
export type ArrayElement<A> = A extends readonly (infer T)[] ? T : never;

View File

@@ -1,5 +1,5 @@
import { sanitizeUrl } from '@braintree/sanitize-url';
import type { CurveFactory, Selection } from 'd3';
import type { CurveFactory } from 'd3';
import {
curveBasis,
curveBasisClosed,
@@ -230,12 +230,16 @@ export const isSubstringInArray = function (str: string, arr: string[]): number
* @param defaultCurve - The default curve to return
* @returns The curve factory to use
*/
export function interpolateToCurve(interpolate: string | undefined, defaultCurve: CurveFactory) {
export function interpolateToCurve(
interpolate: string | undefined,
defaultCurve: CurveFactory
): CurveFactory {
if (!interpolate) {
return defaultCurve;
}
const curveName = `curve${interpolate.charAt(0).toUpperCase() + interpolate.slice(1)}`;
// @ts-ignore TODO: Fix issue with curve type
return d3CurveTypes[curveName as keyof typeof d3CurveTypes] ?? defaultCurve;
}
@@ -483,25 +487,6 @@ export const random = (options: { length: number }) => {
return makeRandomHex(options.length);
};
interface TextData {
text: string;
x: number;
y: number;
anchor: 'start' | 'middle' | 'end';
fontFamily?: string;
fontSize?: string | number;
fontWeight?: string | number;
fill?: string;
class?: string;
textMargin: number;
style?: string;
width?: number;
height?: number;
rx?: number;
ry?: number;
valign?: string;
}
export const getTextObj = function () {
return {
x: 0,
@@ -516,7 +501,7 @@ export const getTextObj = function () {
ry: 0,
valign: undefined,
text: '',
} satisfies TextData;
};
};
/**
@@ -527,9 +512,20 @@ export const getTextObj = function () {
* @returns Text element with given styling and content
*/
export const drawSimpleText = function (
elem: Selection<SVGSVGElement, any, HTMLElement, any>,
textData: TextData
) {
elem: SVGElement,
textData: {
text: string;
x: number;
y: number;
anchor: 'start' | 'middle' | 'end';
fontFamily: string;
fontSize: string | number;
fontWeight: string | number;
fill: string;
class: string | undefined;
textMargin: number;
}
): SVGTextElement {
// Remove and ignore br:s
const nText = textData.text.replace(common.lineBreakRegex, ' ');
@@ -693,7 +689,7 @@ export const calculateTextDimensions: (
text: string,
config: TextDimensionConfig
) => TextDimensions = memoize(
(text: string, config: TextDimensionConfig) => {
(text: string, config: TextDimensionConfig): TextDimensions => {
const { fontSize = 12, fontFamily = 'Arial', fontWeight = 400 } = config;
if (!text) {
return { width: 0, height: 0 };
@@ -723,7 +719,9 @@ export const calculateTextDimensions: (
for (const line of lines) {
const textObj = getTextObj();
textObj.text = line || ZERO_WIDTH_SPACE;
// @ts-ignore TODO: Fix D3 types
const textElem = drawSimpleText(g, textObj)
// @ts-ignore TODO: Fix D3 types
.style('font-size', _fontSizePx)
.style('font-weight', fontWeight)
.style('font-family', fontFamily);
@@ -931,3 +929,19 @@ export const decodeEntities = function (text: string): string {
export const isString = (value: unknown): value is string => {
return typeof value === 'string';
};
export const getEdgeId = (
from: string,
to: string,
{
counter = 0,
prefix,
suffix,
}: {
counter?: number;
prefix?: string;
suffix?: string;
}
) => {
return `${prefix ? `${prefix}_` : ''}${from}_${to}_${counter}${suffix ? `_${suffix}` : ''}`;
};

1576
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff