mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-25 17:04:19 +02:00
#5237 Theme support
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
/* background: rgb(221, 208, 208); */
|
/* background: rgb(221, 208, 208); */
|
||||||
/* background:#333; */
|
/* background: #333; */
|
||||||
font-family: 'Arial';
|
font-family: 'Arial';
|
||||||
/* font-size: 18px !important; */
|
/* font-size: 18px !important; */
|
||||||
}
|
}
|
||||||
@@ -45,12 +45,14 @@
|
|||||||
.mermaid svg {
|
.mermaid svg {
|
||||||
/* font-size: 18px !important; */
|
/* font-size: 18px !important; */
|
||||||
|
|
||||||
background-color: #efefef;
|
/* background-color: #efefef;
|
||||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||||
radial-gradient(#fff 51%, transparent 91%);
|
radial-gradient(#fff 51%, transparent 91%);
|
||||||
background-size: 20px 20px;
|
background-size: 20px 20px;
|
||||||
background-position: 0 0, 10px 10px;
|
background-position:
|
||||||
background-repeat: repeat;
|
0 0,
|
||||||
|
10px 10px;
|
||||||
|
background-repeat: repeat; */
|
||||||
}
|
}
|
||||||
.malware {
|
.malware {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -107,6 +109,22 @@ stateDiagram-v2
|
|||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": "true"} }%%
|
||||||
|
stateDiagram-v2
|
||||||
|
state ProActive {
|
||||||
|
state Active {
|
||||||
|
Chimp --> A:One
|
||||||
|
Chimp --> B:Two
|
||||||
|
Chimp --> C:Three
|
||||||
|
state InActive {
|
||||||
|
D
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false} }%%
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
state ProActive {
|
state ProActive {
|
||||||
state Active {
|
state Active {
|
||||||
@@ -511,6 +529,7 @@ mindmap
|
|||||||
// useMaxWidth: false,
|
// useMaxWidth: false,
|
||||||
// });
|
// });
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
|
theme: 'base',
|
||||||
handdrawn: true,
|
handdrawn: true,
|
||||||
// layout: 'dagre',
|
// layout: 'dagre',
|
||||||
layout: 'elk',
|
layout: 'elk',
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
import insertMarkers from '../../rendering-elements/markers.js';
|
import insertMarkers from '../../rendering-elements/markers.js';
|
||||||
import { findCommonAncestor } from './find-common-ancestor.js';
|
import { findCommonAncestor } from './find-common-ancestor.js';
|
||||||
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
||||||
import {
|
import { insertNode, clear as clearNodes } from '../../rendering-elements/nodes.js';
|
||||||
insertNode,
|
import { insertCluster, clear as clearClusters } from '../../rendering-elements/clusters.js';
|
||||||
positionNode,
|
|
||||||
clear as clearNodes,
|
|
||||||
setNodeElem,
|
|
||||||
} from '../../rendering-elements/nodes.js';
|
|
||||||
import {
|
|
||||||
insertCluster,
|
|
||||||
clear as clearClusters,
|
|
||||||
positionCluster,
|
|
||||||
} from '../../rendering-elements/clusters.js';
|
|
||||||
import {
|
import {
|
||||||
insertEdgeLabel,
|
insertEdgeLabel,
|
||||||
positionEdgeLabel,
|
positionEdgeLabel,
|
||||||
@@ -116,14 +107,12 @@ const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, depth) => {
|
|||||||
if (node.type === 'group') {
|
if (node.type === 'group') {
|
||||||
log.debug('Id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
|
log.debug('Id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
|
||||||
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
|
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
|
||||||
|
// TODO use faster way of cloning
|
||||||
const clusterNode = JSON.parse(JSON.stringify(node));
|
const clusterNode = JSON.parse(JSON.stringify(node));
|
||||||
clusterNode.x = node.offset.posX + node.width / 2;
|
clusterNode.x = node.offset.posX + node.width / 2;
|
||||||
clusterNode.y = node.offset.posY + node.height / 2;
|
clusterNode.y = node.offset.posY + node.height / 2;
|
||||||
// clusterNode.y = node.y + node.height / 2;
|
|
||||||
const cluster = insertCluster(subgraphEl, clusterNode);
|
const cluster = insertCluster(subgraphEl, clusterNode);
|
||||||
// const bbox = cluster.node().getBBox();
|
|
||||||
// node.x -= bbox.width / 2 - 2; // Magic number 2... why??? WHY???
|
|
||||||
// node.y -= bbox.height / 2;
|
|
||||||
log.info('Id (UGH)= ', node.shape, node.labels);
|
log.info('Id (UGH)= ', node.shape, node.labels);
|
||||||
} else {
|
} else {
|
||||||
log.info(
|
log.info(
|
||||||
@@ -524,6 +513,7 @@ export const render = async (data4Layout, svg, element) => {
|
|||||||
height: node?.labelData?.height || 100,
|
height: node?.labelData?.height || 100,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
node['elk.direction'] = 'RIGHT';
|
||||||
delete node.x;
|
delete node.x;
|
||||||
delete node.y;
|
delete node.y;
|
||||||
delete node.width;
|
delete node.width;
|
||||||
@@ -533,7 +523,7 @@ export const render = async (data4Layout, svg, element) => {
|
|||||||
|
|
||||||
log.info('before layout', JSON.stringify(elkGraph, null, 2));
|
log.info('before layout', JSON.stringify(elkGraph, null, 2));
|
||||||
const g = await elk.layout(elkGraph);
|
const g = await elk.layout(elkGraph);
|
||||||
log.info('after layout DAGA', g);
|
log.info('after layout DAGA', JSON.stringify(g));
|
||||||
|
|
||||||
// debugger;
|
// debugger;
|
||||||
drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
||||||
|
|||||||
@@ -134,6 +134,12 @@ const noteGroup = (parent, node) => {
|
|||||||
const roundedWithTitle = (parent, node) => {
|
const roundedWithTitle = (parent, node) => {
|
||||||
const siteConfig = getConfig();
|
const siteConfig = getConfig();
|
||||||
|
|
||||||
|
console.log('DAGO node in roundedWithTitle', siteConfig.themeVariables);
|
||||||
|
|
||||||
|
const { themeVariables } = siteConfig;
|
||||||
|
const { altBackground, compositeBackground, compositeTitleBackground, nodeBorder } =
|
||||||
|
themeVariables;
|
||||||
|
|
||||||
// Add outer g element
|
// Add outer g element
|
||||||
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);
|
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);
|
||||||
|
|
||||||
@@ -178,28 +184,26 @@ const roundedWithTitle = (parent, node) => {
|
|||||||
// add the rect
|
// add the rect
|
||||||
let rect;
|
let rect;
|
||||||
if (node.useRough) {
|
if (node.useRough) {
|
||||||
const isAlt = node.classes.indexOf('statediagram-cluster-alt') >= 0;
|
const isAlt = node.classes.includes('statediagram-cluster-alt');
|
||||||
console.log(
|
|
||||||
'DAGA node in roundedWithTitle',
|
|
||||||
node.classes,
|
|
||||||
node.classes.indexOf('statediagram-cluster-alt'),
|
|
||||||
isAlt
|
|
||||||
);
|
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
const roughOuterNode =
|
const roughOuterNode =
|
||||||
node.rx || node.ry
|
node.rx || node.ry
|
||||||
? rc.path(createRoundedRectPathD(x, y, width, height, 10), {
|
? rc.path(createRoundedRectPathD(x, y, width, height, 10), {
|
||||||
roughness: 0.7,
|
roughness: 0.7,
|
||||||
|
fill: compositeTitleBackground,
|
||||||
|
fillStyle: 'solid',
|
||||||
|
stroke: nodeBorder,
|
||||||
})
|
})
|
||||||
: rc.rectangle(x, y, width, height);
|
: rc.rectangle(x, y, width, height);
|
||||||
|
|
||||||
rect = shapeSvg.insert(() => roughOuterNode);
|
rect = shapeSvg.insert(() => roughOuterNode, ':first-child');
|
||||||
const roughInnerNode = rc.rectangle(x, innerY, width, innerHeight, {
|
const roughInnerNode = rc.rectangle(x, innerY, width, innerHeight, {
|
||||||
fill: isAlt ? 'lightgrey' : 'white',
|
fill: isAlt ? altBackground : compositeBackground,
|
||||||
fillStyle: isAlt ? 'hachure' : 'solid',
|
fillStyle: isAlt ? 'hachure' : 'solid',
|
||||||
|
stroke: nodeBorder,
|
||||||
});
|
});
|
||||||
|
|
||||||
rect = shapeSvg.insert(() => roughOuterNode);
|
rect = shapeSvg.insert(() => roughOuterNode, ':first-child');
|
||||||
innerRect = shapeSvg.insert(() => roughInnerNode);
|
innerRect = shapeSvg.insert(() => roughInnerNode);
|
||||||
} else {
|
} else {
|
||||||
rect = outerRectG.insert('rect', ':first-child');
|
rect = outerRectG.insert('rect', ':first-child');
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import type { Node } from '$root/rendering-util/types.d.ts';
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
import type { SVG } from '$root/diagram-api/types.js';
|
import type { SVG } from '$root/diagram-api/types.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import solidFillOptions from './solidFillOptions.js';
|
import { solidStateFill } from './handdrawnStyles.js';
|
||||||
export const choice = (parent: SVG, node: Node) => {
|
export const choice = (parent: SVG, node: Node) => {
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
.insert('g')
|
.insert('g')
|
||||||
@@ -23,7 +23,7 @@ export const choice = (parent: SVG, node: Node) => {
|
|||||||
const pointArr = points.map(function (d) {
|
const pointArr = points.map(function (d) {
|
||||||
return [d.x, d.y];
|
return [d.x, d.y];
|
||||||
});
|
});
|
||||||
const roughNode = rc.polygon(pointArr, solidFillOptions);
|
const roughNode = rc.polygon(pointArr, solidStateFill('black'));
|
||||||
choice = shapeSvg.insert(() => roughNode);
|
choice = shapeSvg.insert(() => roughNode);
|
||||||
} else {
|
} else {
|
||||||
choice = shapeSvg.insert('polygon', ':first-child').attr(
|
choice = shapeSvg.insert('polygon', ':first-child').attr(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import type { Node } from '$root/rendering-util/types.d.ts';
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
import type { SVG } from '$root/diagram-api/types.js';
|
import type { SVG } from '$root/diagram-api/types.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import solidFillOptions from './solidFillOptions.js';
|
import { solidStateFill } from './handdrawnStyles.js';
|
||||||
|
|
||||||
export const forkJoin = (parent: SVG, node: Node, dir: string) => {
|
export const forkJoin = (parent: SVG, node: Node, dir: string) => {
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
@@ -25,7 +25,7 @@ export const forkJoin = (parent: SVG, node: Node, dir: string) => {
|
|||||||
let shape;
|
let shape;
|
||||||
if (node.useRough) {
|
if (node.useRough) {
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
const roughNode = rc.rectangle(x, y, width, height, solidFillOptions);
|
const roughNode = rc.rectangle(x, y, width, height, solidStateFill('black'));
|
||||||
shape = shapeSvg.insert(() => roughNode);
|
shape = shapeSvg.insert(() => roughNode);
|
||||||
} else {
|
} else {
|
||||||
shape = shapeSvg
|
shape = shapeSvg
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Striped fill like start or fork nodes in state diagrams
|
||||||
|
export const solidStateFill = (color: string) => {
|
||||||
|
return {
|
||||||
|
fill: color,
|
||||||
|
// fillStyle: 'solid',
|
||||||
|
hachureAngle: 120, // angle of hachure,
|
||||||
|
hachureGap: 4,
|
||||||
|
fillWeight: 2,
|
||||||
|
roughness: 0.7,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@ import { labelHelper, updateNodeBounds } from './util.js';
|
|||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { Node } from '$root/rendering-util/types.d.ts';
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
import { createRoundedRectPathD } from './roundedRectPath.js';
|
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||||
|
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,6 +58,21 @@ function applyNodePropertyBorders(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const rect = async (parent: SVGAElement, node: Node) => {
|
export const rect = async (parent: SVGAElement, node: Node) => {
|
||||||
|
const { themeVariables } = getConfig();
|
||||||
|
const {
|
||||||
|
textColor,
|
||||||
|
clusterTextColor,
|
||||||
|
altBackground,
|
||||||
|
compositeBackground,
|
||||||
|
compositeTitleBackground,
|
||||||
|
compositeBorder,
|
||||||
|
noteBorderColor,
|
||||||
|
noteBkgColor,
|
||||||
|
nodeBorder,
|
||||||
|
mainBkg,
|
||||||
|
stateBorder,
|
||||||
|
} = themeVariables;
|
||||||
|
|
||||||
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||||
parent,
|
parent,
|
||||||
node,
|
node,
|
||||||
@@ -77,15 +93,14 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
|||||||
rx || ry
|
rx || ry
|
||||||
? rc.path(createRoundedRectPathD(x, y, totalWidth, totalHeight, rx || 0), {
|
? rc.path(createRoundedRectPathD(x, y, totalWidth, totalHeight, rx || 0), {
|
||||||
roughness: 0.7,
|
roughness: 0.7,
|
||||||
fill:'white',
|
fill: mainBkg,
|
||||||
fillStyle: 'solid' // solid fill'
|
fillStyle: 'solid', // solid fill'
|
||||||
|
stroke: nodeBorder,
|
||||||
})
|
})
|
||||||
: rc.rectangle(x, y, totalWidth, totalHeight);
|
: rc.rectangle(x, y, totalWidth, totalHeight);
|
||||||
|
|
||||||
rect = shapeSvg.insert(() => roughNode, ':first-child');
|
rect = shapeSvg.insert(() => roughNode, ':first-child');
|
||||||
rect
|
rect.attr('class', 'basic label-container').attr('style', style);
|
||||||
.attr('class', 'basic label-container')
|
|
||||||
.attr('style', style)
|
|
||||||
} else {
|
} else {
|
||||||
rect = shapeSvg.insert('rect', ':first-child');
|
rect = shapeSvg.insert('rect', ':first-child');
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
const options = {
|
|
||||||
fill: 'black',
|
|
||||||
// fillStyle: 'solid',
|
|
||||||
hachureAngle: 120, // angle of hachure,
|
|
||||||
hachureGap: 4,
|
|
||||||
fillWeight: 2,
|
|
||||||
roughness: 0.7,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default options;
|
|
||||||
@@ -4,7 +4,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import type { Node } from '$root/rendering-util/types.d.ts';
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
import type { SVG } from '$root/diagram-api/types.js';
|
import type { SVG } from '$root/diagram-api/types.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import solidFillOptions from './solidFillOptions.js';
|
import { solidStateFill } from './handdrawnStyles.js';
|
||||||
|
|
||||||
export const stateEnd = (parent: SVG, node: Node) => {
|
export const stateEnd = (parent: SVG, node: Node) => {
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
@@ -26,7 +26,7 @@ export const stateEnd = (parent: SVG, node: Node) => {
|
|||||||
if (node.useRough) {
|
if (node.useRough) {
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
const roughNode = rc.circle(0, 0, 14, { roughness: 0.5 });
|
const roughNode = rc.circle(0, 0, 14, { roughness: 0.5 });
|
||||||
const roughInnerNode = rc.circle(0, 0, 5, { ...solidFillOptions, fillStyle: 'solid' });
|
const roughInnerNode = rc.circle(0, 0, 5, { ...solidStateFill('black'), fillStyle: 'solid' });
|
||||||
circle = shapeSvg.insert(() => roughNode);
|
circle = shapeSvg.insert(() => roughNode);
|
||||||
innerCircle = shapeSvg.insert(() => roughInnerNode);
|
innerCircle = shapeSvg.insert(() => roughInnerNode);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import type { Node } from '$root/rendering-util/types.d.ts';
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
import type { SVG } from '$root/diagram-api/types.js';
|
import type { SVG } from '$root/diagram-api/types.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import solidFillOptions from './solidFillOptions.js';
|
import { solidStateFill } from './handdrawnStyles.js';
|
||||||
|
|
||||||
export const stateStart = (parent: SVG, node: Node) => {
|
export const stateStart = (parent: SVG, node: Node) => {
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
@@ -15,7 +15,7 @@ export const stateStart = (parent: SVG, node: Node) => {
|
|||||||
let circle;
|
let circle;
|
||||||
if (node.useRough) {
|
if (node.useRough) {
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
const roughNode = rc.circle(0, 0, 14, solidFillOptions);
|
const roughNode = rc.circle(0, 0, 14, solidStateFill('black'));
|
||||||
circle = shapeSvg.insert(() => roughNode);
|
circle = shapeSvg.insert(() => roughNode);
|
||||||
} else {
|
} else {
|
||||||
circle = shapeSvg.insert('circle', ':first-child');
|
circle = shapeSvg.insert('circle', ':first-child');
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ class Theme {
|
|||||||
this.background = '#333';
|
this.background = '#333';
|
||||||
this.primaryColor = '#1f2020';
|
this.primaryColor = '#1f2020';
|
||||||
this.secondaryColor = lighten(this.primaryColor, 16);
|
this.secondaryColor = lighten(this.primaryColor, 16);
|
||||||
|
|
||||||
this.tertiaryColor = adjust(this.primaryColor, { h: -160 });
|
this.tertiaryColor = adjust(this.primaryColor, { h: -160 });
|
||||||
this.primaryBorderColor = invert(this.background);
|
this.primaryBorderColor = invert(this.background);
|
||||||
this.secondaryBorderColor = mkBorder(this.secondaryColor, this.darkMode);
|
this.secondaryBorderColor = mkBorder(this.secondaryColor, this.darkMode);
|
||||||
@@ -22,7 +21,7 @@ class Theme {
|
|||||||
this.mainContrastColor = 'lightgrey';
|
this.mainContrastColor = 'lightgrey';
|
||||||
this.darkTextColor = lighten(invert('#323D47'), 10);
|
this.darkTextColor = lighten(invert('#323D47'), 10);
|
||||||
this.lineColor = 'calculated';
|
this.lineColor = 'calculated';
|
||||||
this.border1 = '#81B1DB';
|
this.border1 = '#ccc';
|
||||||
this.border2 = rgba(255, 255, 255, 0.25);
|
this.border2 = rgba(255, 255, 255, 0.25);
|
||||||
this.arrowheadColor = 'calculated';
|
this.arrowheadColor = 'calculated';
|
||||||
this.fontFamily = '"trebuchet ms", verdana, arial, sans-serif';
|
this.fontFamily = '"trebuchet ms", verdana, arial, sans-serif';
|
||||||
@@ -333,6 +332,8 @@ class Theme {
|
|||||||
this.attributeBackgroundColorEven =
|
this.attributeBackgroundColorEven =
|
||||||
this.attributeBackgroundColorEven || lighten(this.background, 2);
|
this.attributeBackgroundColorEven || lighten(this.background, 2);
|
||||||
/* -------------------------------------------------- */
|
/* -------------------------------------------------- */
|
||||||
|
|
||||||
|
this.nodeBorder = this.nodeBorder || '#999';
|
||||||
}
|
}
|
||||||
calculate(overrides) {
|
calculate(overrides) {
|
||||||
if (typeof overrides !== 'object') {
|
if (typeof overrides !== 'object') {
|
||||||
|
|||||||
Reference in New Issue
Block a user