+ gitGraph TB
commit
commit
branch develop
@@ -217,7 +227,7 @@ class Class10 {
size()
}
+
%%{init: {'config': {'wrap': true }}}%%
sequenceDiagram
participant A as Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
@@ -332,7 +342,7 @@ flowchart TD
rankSpacing: 50,
defaultRenderer: 'dagre-d3',
},
- logLevel: 0,
+ logLevel: 1,
fontSize: 18,
curve: 'cardinal',
// securityLevel: 'sandbox',
diff --git a/src/defaultConfig.js b/src/defaultConfig.js
index acf85055f..14001f167 100644
--- a/src/defaultConfig.js
+++ b/src/defaultConfig.js
@@ -1818,6 +1818,11 @@ const config = {
external_component_queue_bg_color: '#CCCCCC',
external_component_queue_border_color: '#BFBFBF',
},
+ mindmap: {
+ useMaxWidth: true,
+ diagramPadding: 10,
+ maxNodeWidth: 200,
+ },
};
config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
diff --git a/src/diagram-api/detectType.js b/src/diagram-api/detectType.js
index a5f074e3e..0bcde1e17 100644
--- a/src/diagram-api/detectType.js
+++ b/src/diagram-api/detectType.js
@@ -83,8 +83,10 @@ const detectType = function (text, cnf) {
if (cnf && cnf.flowchart && cnf.flowchart.defaultRenderer === 'dagre-wrapper')
return 'flowchart-v2';
const k = Object.keys(detectors);
+ console.log('here', k);
for (let i = 0; i < k.length; i++) {
const key = k[i];
+ console.log('Detecting type for', key);
const dia = detectors[key];
if (dia && dia.detector(text)) {
return key;
diff --git a/src/diagram-api/diagram-orchestration.js b/src/diagram-api/diagram-orchestration.js
index d73bc1bbb..488a708ee 100644
--- a/src/diagram-api/diagram-orchestration.js
+++ b/src/diagram-api/diagram-orchestration.js
@@ -1,24 +1,17 @@
import { registerDiagram } from './diagramAPI.js';
-// import mindmapDb from '../diagrams/mindmap/mindmapDb';
-// import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
-// import mindmapParser from '../diagrams/mindmap/parser/mindmapDiagram';
-// import mindmapDetector from '../diagrams/mindmap/mindmapDetector';
+import mindmapDb from '../diagrams/mindmap/mindmapDb';
+import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
+import mindmapParser from '../diagrams/mindmap/parser/mindmap';
+import mindmapDetector from '../diagrams/mindmap/mindmapDetector';
+import mindmapStyles from '../diagrams/mindmap/styles';
import gitGraphDb from '../diagrams/git/gitGraphAst';
import gitGraphRenderer from '../diagrams/git/gitGraphRenderer';
import gitGraphParser from '../diagrams/git/parser/gitGraph';
import gitGraphDetector from '../diagrams/git/gitGraphDetector';
+import gitGraphStyles from '../diagrams/git/styles';
// Register mindmap and other built-in diagrams
-// registerDiagram(
-// 'mindmap',
-// mindmapParser,
-// mindmapDb,
-// mindmapRenderer,
-// undefined,
-// mindmapRenderer,
-// mindmapDetector
-// );
const addDiagrams = () => {
registerDiagram(
'gitGraph',
@@ -26,7 +19,17 @@ const addDiagrams = () => {
gitGraphDb,
gitGraphRenderer,
undefined,
- gitGraphDetector
+ gitGraphDetector,
+ gitGraphStyles
+ );
+ registerDiagram(
+ 'mindmap',
+ mindmapParser,
+ mindmapDb,
+ mindmapRenderer,
+ undefined,
+ mindmapDetector,
+ mindmapStyles
);
};
export default addDiagrams;
diff --git a/src/diagram-api/diagramAPI.js b/src/diagram-api/diagramAPI.js
index e8339ca37..837cbb4ff 100644
--- a/src/diagram-api/diagramAPI.js
+++ b/src/diagram-api/diagramAPI.js
@@ -35,15 +35,19 @@ import journeyDb from '../diagrams/user-journey/journeyDb';
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
import journeyParser from '../diagrams/user-journey/parser/journey';
import { addDetector } from './detectType';
+import { addStylesForDiagram } from '../styles';
import { sanitizeText as _sanitizeText } from '../diagrams/common/common';
import { getConfig as _getConfig } from '../config';
+import { log as _log } from '../logger';
+import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox';
+
let title = '';
let diagramTitle = '';
let description = '';
export const getConfig = _getConfig;
export const sanitizeText = (txt) => _sanitizeText(txt, getConfig());
-
+export const log = _log;
const diagrams = {
c4: {
db: c4Db,
@@ -171,13 +175,16 @@ const diagrams = {
},
},
};
-// console.log(sequenceDb);
-export const registerDiagram = (id, parser, db, renderer, init, detector) => {
+
+export const registerDiagram = (id, parser, db, renderer, init, detector, styles) => {
diagrams[id] = { parser, db, renderer, init };
addDetector(id, detector);
+ addStylesForDiagram(id, styles);
};
export const getDiagrams = () => {
// console.log('diagrams', diagrams);
return diagrams;
};
+
+export const setupGraphViewbox = _setupGraphViewbox;
diff --git a/src/diagram-api/text-wrap b/src/diagram-api/text-wrap
new file mode 100644
index 000000000..173baecec
--- /dev/null
+++ b/src/diagram-api/text-wrap
@@ -0,0 +1,227 @@
+export const lineBreakRegex = /
/gi;
+
+/**
+ * Caches results of functions based on input
+ *
+ * @param {Function} fn Function to run
+ * @param {Function} resolver Function that resolves to an ID given arguments the `fn` takes
+ * @returns {Function} An optimized caching function
+ */
+const memoize = (fn, resolver) => {
+ let cache = {};
+ return (...args) => {
+ let n = resolver ? resolver.apply(this, args) : args[0];
+ if (n in cache) {
+ return cache[n];
+ } else {
+ let result = fn(...args);
+ cache[n] = result;
+ return result;
+ }
+ };
+};
+/**
+ * This calculates the width of the given text, font size and family.
+ *
+ * @param {any} text - The text to calculate the width of
+ * @param {any} config - The config for fontSize, fontFamily, and fontWeight all impacting the resulting size
+ * @returns {any} - The width for the given text
+ */
+export const calculateTextWidth = function (text, config) {
+ config = Object.assign({ fontSize: 12, fontWeight: 400, fontFamily: 'Arial' }, config);
+ return calculateTextDimensions(text, config).width;
+};
+
+export const getTextObj = function () {
+ return {
+ x: 0,
+ y: 0,
+ fill: undefined,
+ anchor: 'start',
+ style: '#666',
+ width: 100,
+ height: 100,
+ textMargin: 0,
+ rx: 0,
+ ry: 0,
+ valign: undefined,
+ };
+};
+
+/**
+ * Adds text to an element
+ *
+ * @param {SVGElement} elem Element to add text to
+ * @param {{
+ * 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;
+ * }} textData
+ * @returns {SVGTextElement} Text element with given styling and content
+ */
+export const drawSimpleText = function (elem, textData) {
+ // Remove and ignore br:s
+ const nText = textData.text.replace(lineBreakRegex, ' ');
+
+ const textElem = elem.append('text');
+ 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);
+ }
+
+ const span = textElem.append('tspan');
+ span.attr('x', textData.x + textData.textMargin * 2);
+ span.attr('fill', textData.fill);
+ span.text(nText);
+
+ return textElem;
+};
+
+/**
+ * This calculates the dimensions of the given text, font size, font family, font weight, and margins.
+ *
+ * @param {any} text - The text to calculate the width of
+ * @param {any} config - The config for fontSize, fontFamily, fontWeight, and margin all impacting
+ * the resulting size
+ * @returns - The width for the given text
+ */
+export const calculateTextDimensions = memoize(
+ function (text, config) {
+ config = Object.assign({ fontSize: 12, fontWeight: 400, fontFamily: 'Arial' }, config);
+ const { fontSize, fontFamily, fontWeight } = config;
+ if (!text) {
+ return { width: 0, height: 0 };
+ }
+
+ // We can't really know if the user supplied font family will render on the user agent;
+ // thus, we'll take the max width between the user supplied font family, and a default
+ // of sans-serif.
+ const fontFamilies = ['sans-serif', fontFamily];
+ const lines = text.split(common.lineBreakRegex);
+ let dims = [];
+
+ const body = select('body');
+ // We don't want to leak DOM elements - if a removal operation isn't available
+ // for any reason, do not continue.
+ if (!body.remove) {
+ return { width: 0, height: 0, lineHeight: 0 };
+ }
+
+ const g = body.append('svg');
+
+ for (let fontFamily of fontFamilies) {
+ let cheight = 0;
+ let dim = { width: 0, height: 0, lineHeight: 0 };
+ for (let line of lines) {
+ const textObj = getTextObj();
+ textObj.text = line;
+ const textElem = drawSimpleText(g, textObj)
+ .style('font-size', fontSize)
+ .style('font-weight', fontWeight)
+ .style('font-family', fontFamily);
+
+ let bBox = (textElem._groups || textElem)[0][0].getBBox();
+ dim.width = Math.round(Math.max(dim.width, bBox.width));
+ cheight = Math.round(bBox.height);
+ dim.height += cheight;
+ dim.lineHeight = Math.round(Math.max(dim.lineHeight, cheight));
+ }
+ dims.push(dim);
+ }
+
+ g.remove();
+
+ let index =
+ isNaN(dims[1].height) ||
+ isNaN(dims[1].width) ||
+ isNaN(dims[1].lineHeight) ||
+ (dims[0].height > dims[1].height &&
+ dims[0].width > dims[1].width &&
+ dims[0].lineHeight > dims[1].lineHeight)
+ ? 0
+ : 1;
+ return dims[index];
+ },
+ (text, config) => `${text}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}`
+);
+
+const breakString = memoize(
+ (word, maxWidth, hyphenCharacter = '-', config) => {
+ config = Object.assign(
+ { fontSize: 12, fontWeight: 400, fontFamily: 'Arial', margin: 0 },
+ config
+ );
+ const characters = word.split('');
+ const lines = [];
+ let currentLine = '';
+ characters.forEach((character, index) => {
+ const nextLine = `${currentLine}${character}`;
+ const lineWidth = calculateTextWidth(nextLine, config);
+ if (lineWidth >= maxWidth) {
+ const currentCharacter = index + 1;
+ const isLastLine = characters.length === currentCharacter;
+ const hyphenatedNextLine = `${nextLine}${hyphenCharacter}`;
+ lines.push(isLastLine ? nextLine : hyphenatedNextLine);
+ currentLine = '';
+ } else {
+ currentLine = nextLine;
+ }
+ });
+ return { hyphenatedStrings: lines, remainingWord: currentLine };
+ },
+ (word, maxWidth, hyphenCharacter = '-', config) =>
+ `${word}-${maxWidth}-${hyphenCharacter}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}`
+);
+
+export const wrapLabel = memoize(
+ (label, maxWidth, config) => {
+ if (!label) {
+ return label;
+ }
+ config = Object.assign(
+ { fontSize: 12, fontWeight: 400, fontFamily: 'Arial', joinWith: '
' },
+ config
+ );
+ if (lineBreakRegex.test(label)) {
+ return label;
+ }
+ const words = label.split(' ');
+ const completedLines = [];
+ let nextLine = '';
+ words.forEach((word, index) => {
+ const wordLength = calculateTextWidth(`${word} `, config);
+ const nextLineLength = calculateTextWidth(nextLine, config);
+ if (wordLength > maxWidth) {
+ const { hyphenatedStrings, remainingWord } = breakString(word, maxWidth, '-', config);
+ completedLines.push(nextLine, ...hyphenatedStrings);
+ nextLine = remainingWord;
+ } else if (nextLineLength + wordLength >= maxWidth) {
+ completedLines.push(nextLine);
+ nextLine = word;
+ } else {
+ nextLine = [nextLine, word].filter(Boolean).join(' ');
+ }
+ const currentWord = index + 1;
+ const isLastWord = currentWord === words.length;
+ if (isLastWord) {
+ completedLines.push(nextLine);
+ }
+ });
+ return completedLines.filter((line) => line !== '').join(config.joinWith);
+ },
+ (label, maxWidth, config) =>
+ `${label}-${maxWidth}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}-${config.joinWith}`
+);
diff --git a/src/diagrams/mindmap/mindmapDb.js b/src/diagrams/mindmap/mindmapDb.js
index 8aed2dd2e..29a982cea 100644
--- a/src/diagrams/mindmap/mindmapDb.js
+++ b/src/diagrams/mindmap/mindmapDb.js
@@ -1,6 +1,5 @@
/** Created by knut on 15-01-14. */
-import { log } from '../../logger';
-import { sanitizeText } from '../../diagram-api/diagramAPI';
+import { log, sanitizeText, getConfig } from '../../diagram-api/diagramAPI';
var message = '';
var info = false;
@@ -26,7 +25,14 @@ export const getMindmap = () => {
return nodes.length > 0 ? nodes[0] : null;
};
export const addNode = (level, id, descr, type) => {
- const node = { id: sanitizeText(id), level, descr: sanitizeText(descr), type, children: [] };
+ const node = {
+ id: sanitizeText(id),
+ level,
+ descr: sanitizeText(descr),
+ type,
+ children: [],
+ width: getConfig().mindmap.maxNodeWidth,
+ };
const parent = getParent(level);
if (parent) {
parent.children.push(node);
diff --git a/src/diagrams/mindmap/mindamapDetector.js b/src/diagrams/mindmap/mindmapDetector.js
similarity index 72%
rename from src/diagrams/mindmap/mindamapDetector.js
rename to src/diagrams/mindmap/mindmapDetector.js
index 341e3968c..4fe85af03 100644
--- a/src/diagrams/mindmap/mindamapDetector.js
+++ b/src/diagrams/mindmap/mindmapDetector.js
@@ -1,4 +1,4 @@
-const detector = (txt) => {
+const detector = function detect(txt) {
if (txt.match(/^\s*mindmap/)) {
return 'mindmap';
}
diff --git a/src/diagrams/mindmap/mindmapRenderer.js b/src/diagrams/mindmap/mindmapRenderer.js
index cbe3c52f8..5cc8549df 100644
--- a/src/diagrams/mindmap/mindmapRenderer.js
+++ b/src/diagrams/mindmap/mindmapRenderer.js
@@ -1,7 +1,33 @@
/** Created by knut on 14-12-11. */
import { select } from 'd3';
-import { log } from '../../logger';
-import { getConfig } from '../../config';
+import { log, getConfig, setupGraphViewbox } from '../../diagram-api/diagramAPI';
+import svgDraw from './svgDraw';
+
+/**
+ * @param {any} svg The svg element to draw the diagram onto
+ * @param {object} mindmap The maindmap data and hierarchy
+ * @param {object} conf The configuration object
+ */
+function drawNodes(svg, mindmap, conf) {
+ svgDraw.drawNode(svg, mindmap, conf);
+ if (mindmap.children) {
+ mindmap.children.forEach((child) => {
+ drawNodes(svg, child, conf);
+ });
+ }
+}
+
+function drawEdges() {}
+/**
+ * @param node
+ * @param isRoot
+ */
+function layoutMindmap(node, isRoot) {}
+/**
+ * @param node
+ * @param isRoot
+ */
+function positionNodes(node, isRoot) {}
/**
* Draws a an info picture in the tag with id: id based on the graph definition in text.
@@ -12,6 +38,7 @@ import { getConfig } from '../../config';
* @param diagObj
*/
export const draw = (text, id, version, diagObj) => {
+ const conf = getConfig();
try {
// const parser = infoParser.parser;
// parser.yy = db;
@@ -30,24 +57,40 @@ export const draw = (text, id, version, diagObj) => {
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
// Parse the graph definition
- // parser.parse(text);
- // log.debug('Parsed info diagram');
- // Fetch the default direction, use TD if none was found
+
const svg = root.select('#' + id);
const g = svg.append('g');
+ const mm = diagObj.db.getMindmap();
- g.append('text') // text label for the x axis
- .attr('x', 100)
- .attr('y', 40)
- .attr('class', 'version')
- .attr('font-size', '32px')
- .style('text-anchor', 'middle')
- .text('v ' + version);
+ // mm.x = 0;
+ // mm.y = 0;
+ // svgDraw.drawNode(g, mm, getConfig());
+ // mm.children.forEach((child) => {
+ // child.x = 200;
+ // child.y = 200;
+ // child.width = 200;
+ // svgDraw.drawNode(g, child, getConfig());
+ // });
- svg.attr('height', 100);
- svg.attr('width', 400);
- // svg.attr('viewBox', '0 0 300 150');
+ // Draw the graph and start with drawing the nodes without proper position
+ // this gives us the size of the nodes and we can set the positions later
+
+ const nodesElem = svg.append('g');
+ nodesElem.attr('class', 'mindmap-nodes');
+ drawNodes(nodesElem, mm, conf);
+
+ // Next step is to layout the mindmap, giving each node a position
+
+ // layoutMindmap(mm, conf);
+
+ // After this we can draw, first the edges and the then nodes with the correct position
+ // drawEdges(svg, mm, conf);
+
+ // positionNodes(svg, mm, conf);
+
+ // Setup the view box and size of the svg element
+ setupGraphViewbox(undefined, svg, conf.mindmap.diagramPadding, conf.mindmap.useMaxWidth);
} catch (e) {
log.error('Error while rendering info diagram');
log.error(e.message);
diff --git a/src/diagrams/mindmap/styles.js b/src/diagrams/mindmap/styles.js
index 0b0729813..eba4ed284 100644
--- a/src/diagrams/mindmap/styles.js
+++ b/src/diagrams/mindmap/styles.js
@@ -1,3 +1,9 @@
-const getStyles = () => ``;
-
+const getStyles = (options) =>
+ `
+ .node{
+ stroke: ${options.pieStrokeColor};
+ stroke-width : ${options.pieStrokeWidth};
+ opacity : ${options.pieOpacity};
+ }
+`;
export default getStyles;
diff --git a/src/diagrams/mindmap/svgDraw.js b/src/diagrams/mindmap/svgDraw.js
new file mode 100644
index 000000000..edb4d2f72
--- /dev/null
+++ b/src/diagrams/mindmap/svgDraw.js
@@ -0,0 +1,100 @@
+const lineBreakRegex = /
/gi;
+import { select } from 'd3';
+/**
+ * @param {string} text The text to be wrapped
+ * @param {number} width The max width of the text
+ */
+function wrap(text, width) {
+ text.each(function () {
+ var text = select(this),
+ words = text
+ .text()
+ .split(/(\s+|
)/)
+ .reverse(),
+ word,
+ line = [],
+ lineNumber = 0,
+ lineHeight = 1.1, // ems
+ y = text.attr('y'),
+ dy = parseFloat(text.attr('dy')),
+ tspan = text
+ .text(null)
+ .append('tspan')
+ .attr('x', 0)
+ .attr('y', y)
+ .attr('dy', dy + 'em');
+ for (let j = 0; j < words.length; j++) {
+ word = words[words.length - 1 - j];
+ line.push(word);
+ tspan.text(line.join(' ').trim());
+ if (tspan.node().getComputedTextLength() > width || word === '
') {
+ line.pop();
+ tspan.text(line.join(' ').trim());
+ if (word === '
') {
+ line = [''];
+ } else {
+ line = [word];
+ }
+
+ tspan = text
+ .append('tspan')
+ .attr('x', 0)
+ .attr('y', y)
+ .attr('dy', lineHeight + 'em')
+ .text(word);
+ }
+ }
+ });
+}
+/**
+ * @param {object} elem The D3 dom element in which the node is to be added
+ * @param {object} node The node to be added
+ * @param {object} conf The configuration object
+ * @returns {number} The height nodes dom element
+ */
+export const drawNode = function (elem, node, conf) {
+ const nodeElem = elem.append('g');
+ nodeElem.attr('class', 'mindmap-node');
+
+ const rect = {
+ fill: '#EDF2AE',
+ stroke: '#666',
+ width: node.width,
+ anchor: 'start',
+ height: 100,
+ rx: 3,
+ ry: 3,
+ };
+
+ const r = nodeElem
+ .append('rect')
+ .attr('x', (-1 * node.width) / 2)
+ .attr('width', node.width)
+ .attr('fill', rect.fill)
+ .attr('stroke', rect.stroke)
+ .attr('rx', rect.rx)
+ .attr('ry', rect.ry);
+
+ const textElem = nodeElem.append('g');
+ // .attr('transform', 'translate(' + node.x + ', ' + node.y + ')');
+
+ const txt = textElem
+ .append('text')
+ .text(node.descr)
+ .attr('dy', '1em')
+ .attr('alignment-baseline', 'middle')
+ .attr('dominant-baseline', 'middle')
+ .attr('text-anchor', 'middle')
+ .call(wrap, node.width);
+ const bbox = txt.node().getBBox();
+ node.height = bbox.height + conf.fontSize * 1.1 * 0.5;
+ r.attr('height', node.height).attr('y', (-1 * node.height) / 2);
+
+ txt.attr('transform', 'translate( 0,' + (-1 * node.height) / 2 + ')');
+ // Position the node to its coordinate
+ if (node.x || node.y) {
+ nodeElem.attr('transform', 'translate(' + node.x + ',' + node.y + ')');
+ }
+ return node.height;
+};
+export default { drawNode };
diff --git a/src/setupGraphViewbox.js b/src/setupGraphViewbox.js
new file mode 100644
index 000000000..d5c00718c
--- /dev/null
+++ b/src/setupGraphViewbox.js
@@ -0,0 +1,102 @@
+import { log } from './logger';
+
+/**
+ * Applys d3 attributes
+ *
+ * @param {any} d3Elem D3 Element to apply the attributes onto
+ * @param {[string, string][]} attrs Object.keys equivalent format of key to value mapping of attributes
+ */
+const d3Attrs = function (d3Elem, attrs) {
+ for (let attr of attrs) {
+ d3Elem.attr(attr[0], attr[1]);
+ }
+};
+
+/**
+ * Gives attributes for an SVG's size given arguments
+ *
+ * @param {number} height The height of the SVG
+ * @param {number} width The width of the SVG
+ * @param {boolean} useMaxWidth Whether or not to use max-width and set width to 100%
+ * @returns {Map<'height' | 'width' | 'style', string>} Attributes for the SVG
+ */
+export const calculateSvgSizeAttrs = function (height, width, useMaxWidth) {
+ let attrs = new Map();
+ attrs.set('height', height);
+ if (useMaxWidth) {
+ attrs.set('width', '100%');
+ attrs.set('style', `max-width: ${width}px;`);
+ } else {
+ attrs.set('width', width);
+ }
+ return attrs;
+};
+
+/**
+ * Applies attributes from `calculateSvgSizeAttrs`
+ *
+ * @param {SVGSVGElement} svgElem The SVG Element to configure
+ * @param {number} height The height of the SVG
+ * @param {number} width The width of the SVG
+ * @param tx
+ * @param ty
+ * @param {boolean} useMaxWidth Whether or not to use max-width and set width to 100%
+ */
+export const configureSvgSize = function (svgElem, height, width, tx, ty, useMaxWidth) {
+ const attrs = calculateSvgSizeAttrs(height, width, useMaxWidth);
+ d3Attrs(svgElem, attrs);
+};
+export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) {
+ const svgBounds = svgElem.node().getBBox();
+ const sWidth = svgBounds.width;
+ const sHeight = svgBounds.height;
+
+ let width;
+ let height;
+ let tx = 0;
+ let ty = 0;
+ if (graph) {
+ width = graph._label.width;
+ height = graph._label.height;
+ if (sWidth > width) {
+ tx = (sWidth - width) / 2 + padding;
+ width = sWidth + padding * 2;
+ } else {
+ if (Math.abs(sWidth - width) >= 2 * padding + 1) {
+ width = width - padding;
+ }
+ }
+ if (sHeight > height) {
+ ty = (sHeight - height) / 2 + padding;
+ height = sHeight + padding * 2;
+ }
+ } else {
+ width = sWidth + padding * 2;
+ height = sHeight + padding * 2;
+ }
+
+ // Ensure the viewBox includes the whole svgBounds area with extra space for padding
+ const vBox = graph
+ ? `0 0 ${width} ${height}`
+ : `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
+ console.log(
+ 'Graph.label',
+ graph ? graph._label : null,
+ 'swidth',
+ sWidth,
+ 'sheight',
+ sHeight,
+ 'width',
+ width,
+ 'height',
+ height,
+ 'tx',
+ tx,
+ 'ty',
+ ty,
+ 'vBox',
+ vBox
+ );
+ svgElem.attr('viewBox', vBox);
+ svgElem.select('g').attr('transform', `translate(${tx}, ${ty})`);
+};
diff --git a/src/styles.js b/src/styles.js
index 15e804ef9..50da58545 100644
--- a/src/styles.js
+++ b/src/styles.js
@@ -2,7 +2,7 @@ import classDiagram from './diagrams/class/styles';
import er from './diagrams/er/styles';
import flowchart from './diagrams/flowchart/styles';
import gantt from './diagrams/gantt/styles';
-import gitGraph from './diagrams/git/styles';
+// import gitGraph from './diagrams/git/styles';
import info from './diagrams/info/styles';
import pie from './diagrams/pie/styles';
import requirement from './diagrams/requirement/styles';
@@ -22,7 +22,7 @@ const themes = {
class: classDiagram,
stateDiagram,
state: stateDiagram,
- gitGraph,
+ // gitGraph,
info,
pie,
er,
@@ -89,4 +89,8 @@ const getStyles = (type, userStyles, options) => {
`;
};
+export const addStylesForDiagram = (type, diagramTheme, options) => {
+ themes[type] = diagramTheme;
+};
+
export default getStyles;
diff --git a/src/utils.spec.js b/src/utils.spec.js
index 31517c43a..c84987879 100644
--- a/src/utils.spec.js
+++ b/src/utils.spec.js
@@ -1,7 +1,10 @@
import utils from './utils';
import assignWithDepth from './assignWithDepth';
import detectType from './diagram-api/detectType';
-import './diagram-api/diagram-orchestration';
+import addDiagrams from './diagram-api/diagram-orchestration';
+
+// Orchestrating diagrams and adding the dynamic ones to the list of diagrams
+addDiagrams();
describe('when assignWithDepth: should merge objects within objects', function () {
it('should handle simple, depth:1 types (identity)', function () {
@@ -214,7 +217,7 @@ Alice->Bob: hi`;
const type = detectType(str);
expect(type).toBe('flowchart');
});
- it('should handle a graph definition for gitGraph', function () {
+ fit('should handle a graph definition for gitGraph', function () {
const str = ' \n gitGraph TB:\nbfs1:queue';
const type = detectType(str);
expect(type).toBe('gitGraph');