diff --git a/cypress/downloads/downloads.html b/cypress/downloads/downloads.html
new file mode 100644
index 000000000..b42fc821e
--- /dev/null
+++ b/cypress/downloads/downloads.html
@@ -0,0 +1 @@
+Cr24
\ No newline at end of file
diff --git a/cypress/integration/rendering/mermaid.spec.js b/cypress/integration/rendering/mermaid.spec.js
new file mode 100644
index 000000000..4b7de3027
--- /dev/null
+++ b/cypress/integration/rendering/mermaid.spec.js
@@ -0,0 +1,75 @@
+import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
+
+describe('Mindmap', () => {
+  it('square shape', () => {
+    imgSnapshotTest(
+      `
+mindmap
+    root[
+      The root
+    ]
+      `,
+      {}
+    );
+    cy.get('svg');
+  });
+  it('rounded rect shape', () => {
+    imgSnapshotTest(
+      `
+mindmap
+    root((
+      The root
+    ))
+      `,
+      {}
+    );
+    cy.get('svg');
+  });
+  it('circle shape', () => {
+    imgSnapshotTest(
+      `
+mindmap
+    root(
+      The root
+    )
+      `,
+      {}
+    );
+    cy.get('svg');
+  });
+  it('default shape', () => {
+    imgSnapshotTest(
+      `
+mindmap
+  The root
+      `,
+      {}
+    );
+    cy.get('svg');
+  });
+  it('adding children', () => {
+    imgSnapshotTest(
+      `
+mindmap
+  The root
+    child1
+    child2
+      `,
+      {}
+    );
+    cy.get('svg');
+  });
+  it('adding grand children', () => {
+    imgSnapshotTest(
+      `
+mindmap
+  The root
+    child1
+      child2
+      child3
+      `,
+      {}
+    );
+    cy.get('svg');
+  });
+});
diff --git a/cypress/integration/rendering/mindmap.spec.js b/cypress/integration/rendering/mindmap.spec.js
new file mode 100644
index 000000000..f0cc2bc3f
--- /dev/null
+++ b/cypress/integration/rendering/mindmap.spec.js
@@ -0,0 +1,115 @@
+import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
+
+describe('Mindmaps', () => {
+  it('Only a root', () => {
+    imgSnapshotTest(
+      `mindmap
+root
+    `,
+      {}
+    );
+  });
+
+  it('a root with a shape', () => {
+    imgSnapshotTest(
+      `mindmap
+root[root]
+    `,
+      {}
+    );
+  });
+
+  it('a root with wrapping text and a shape', () => {
+    imgSnapshotTest(
+      `mindmap
+root[A root with a long text that wraps to keep the node size in check]
+    `,
+      {}
+    );
+  });
+
+  it('a root with an icon', () => {
+    imgSnapshotTest(
+      `mindmap
+root[root]
+::icon(mdi mdi-fire)
+    `,
+      {}
+    );
+  });
+
+  it('Blang and cloud shape', () => {
+    imgSnapshotTest(
+      `mindmap
+root))bang((
+  ::icon(mdi mdi-fire)
+  a))Another bang((
+  ::icon(mdi mdi-fire)
+  a)A cloud(
+  ::icon(mdi mdi-fire)
+    `,
+      {}
+    );
+  });
+
+  it('Blang and cloud shape with icons', () => {
+    imgSnapshotTest(
+      `mindmap
+root))bang((
+
+  a))Another bang((
+  a)A cloud(
+    `,
+      {}
+    );
+  });
+
+  it('braches', () => {
+    imgSnapshotTest(
+      `mindmap
+root
+  child1
+      grandchild 1
+      grandchild 2
+  child2
+      grandchild 3
+      grandchild 4
+  child3
+      grandchild 5
+      grandchild 6
+    `,
+      {}
+    );
+  });
+
+  it('braches with shapes and labels', () => {
+    imgSnapshotTest(
+      `mindmap
+root
+  child1((Circle))
+      grandchild 1
+      grandchild 2
+  child2(Round rectangle)
+      grandchild 3
+      grandchild 4
+  child3[Square]
+      grandchild 5
+      ::icon(mdi mdi-fire)
+      gc6((grand<br/>child 6))
+      ::icon(mdi mdi-fire)
+    `,
+      {}
+    );
+  });
+  it('text shouhld wrap with icon', () => {
+    imgSnapshotTest(
+      `mindmap
+root
+  Child3(A node with an icon and with a long text that wraps to keep the node size in check)
+    `,
+      {}
+    );
+  });
+
+  /* The end */
+});
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index bb4814305..40e46d835 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -19,6 +19,7 @@
   - [Requirement Diagram](requirementDiagram.md)
   - [Gitgraph (Git) Diagram 🔥](gitgraph.md)
   - [C4C Diagram (Context) Diagram 🦺⚠️](c4c.md)
+  - [Mindmaps 🦺⚠️](mindmap.md)
   - [Other Examples](examples.md)
 
 - ⚙️ Deployment and Configuration
diff --git a/docs/mindmap.md b/docs/mindmap.md
new file mode 100644
index 000000000..f9d732463
--- /dev/null
+++ b/docs/mindmap.md
@@ -0,0 +1,241 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
+
+# Mindmap
+
+**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/mindmap.md)
+
+> Mindmap: This is an experimental diagram for now. The syntax and properties can change in future releases. The syntax is stabel except for the icon integration which is the experimental part.
+
+"A mind map is a diagram used to visually organize information into a hierarchy, showing relationships among pieces of the whole. It is often created around a single concept, drawn as an image in the center of a blank page, to which associated representations of ideas such as images, words and parts of words are added. Major ideas are connected directly to the central concept, and other ideas branch out from those major ideas." Wikipedia
+
+### An example of a mindmap.
+
+```mermaid-example
+mindmap
+  root((mindmap))
+    Origins
+      Long history
+      ::icon(fa fa-book)
+      Popularisation
+        British popular psychology author Tony Buzan
+    Research
+      On effectivness<br/>and eatures
+      On Automatic creation
+        Uses
+            Creative techniques
+            Strategic planning
+            Argument mapping
+    Tools
+      Pen and paper
+      Mermaid
+
+```
+
+```mermaid
+mindmap
+  root((mindmap))
+    Origins
+      Long history
+      ::icon(fa fa-book)
+      Popularisation
+        British popular psychology author Tony Buzan
+    Research
+      On effectivness<br/>and eatures
+      On Automatic creation
+        Uses
+            Creative techniques
+            Strategic planning
+            Argument mapping
+    Tools
+      Pen and paper
+      Mermaid
+
+```
+
+## Syntax
+
+The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy.
+
+In the following example you can see how there are 3 dufferent levels. One with starting at the left of the text and another level with two rows starting at the same column, defining the node A. At the end there is one more level where the text is indented further then the prevoius lines defining the nodes B and C.
+
+    mindmap
+        Root
+            A
+                B
+                C
+
+In summary is is a simple text outline where there are one node at the root level called `Root` which has one child `A`. A in turn has two children `B`and `C`. In the diagram below we can see this rendered as a mindmap.
+
+```mermaid-example
+mindmap
+Root
+    A
+      B
+      C
+```
+
+```mermaid
+mindmap
+Root
+    A
+      B
+      C
+```
+
+In this way we can use a text outline to generate a hierarchical mindmap.
+
+## Different shapes
+
+Mermaids mindmaps can show node using different shapes. When specifying a shape for a node the syntax for the is similar to flowchart nodes, with an id followed by the shape definition and with the text within the shape delimiters. Where possible we try/will try to keep the same shapes as for flowcharts even though they are not all supported from the start.
+
+Mindmap can show the following shapes:
+
+### Square
+
+```mermaid-example
+mindmap
+    id[I am a square]
+```
+
+```mermaid
+mindmap
+    id[I am a square]
+```
+
+### Rounded square
+
+```mermaid-example
+mindmap
+    id(I am a rounded square)
+```
+
+```mermaid
+mindmap
+    id(I am a rounded square)
+```
+
+### Circle
+
+```mermaid-example
+mindmap
+    id((I am a circle))
+```
+
+```mermaid
+mindmap
+    id((I am a circle))
+```
+
+### Bang
+
+```mermaid-example
+mindmap
+    id))I am a bang((
+```
+
+```mermaid
+mindmap
+    id))I am a bang((
+```
+
+### Cloud
+
+```mermaid-example
+mindmap
+    id)I am a cloud(
+```
+
+```mermaid
+mindmap
+    id)I am a cloud(
+```
+
+### Default
+
+```mermaid-example
+mindmap
+    I am the default shape
+```
+
+```mermaid
+mindmap
+    I am the default shape
+```
+
+More shapes will be added, beginning with the shapes available in flowcharts.
+
+# Icons and classes
+
+## icons
+
+As with flowcharts you can add icons to your nodes but with an updated syntax. The styling for the font based icons are added during the integration so that they are available for the web page. _This is not something a diagram author can do but has to be done with the site administrator or the integrator_. Once the icon fonts are in place you add them to the mind map nodes using the `::icon()` syntax. You place the classes for the icon within the parethesis like in the following example where icons for material design and fontwaresome 4. is displayed. The intention is that this approach should be used for all diagrams supporting icons. **Expermental feature:** This wider scope is also the reason Mindmaps are experimental as this syntax and approach could change.
+
+```mermaid-example
+mindmap
+    Root
+        A
+        ::icon(fa fa-book)
+        B(B)
+        ::icon(mdi mdi-skull-outline)
+```
+
+```mermaid
+mindmap
+    Root
+        A
+        ::icon(fa fa-book)
+        B(B)
+        ::icon(mdi mdi-skull-outline)
+```
+
+## Classes
+
+Again the syntax for adding classes is similar to flowcharts and you can add classes using a tripple colon following a numver of css classes separated by space. In the following example one of the nodes has two custom classes attached urgent turning the background red and the text whiet and large increasing the font size:
+
+```mermaid-example
+mindmap
+    Root
+        A[A]
+        :::urgent large
+        B(B)
+        C
+```
+
+```mermaid
+mindmap
+    Root
+        A[A]
+        :::urgent large
+        B(B)
+        C
+```
+
+_These classes needs top be supplied by the site administrator._
+
+## Unclear indentation
+
+The actual indentation does not really matter only compared with the previous rows. If we take the previous example and disrupt it a little we can se how the calculations are performed. Let us start with placing C with a smaller indentation than `B`but larger then `A`.
+
+    mindmap
+        Root
+            A
+                B
+              C
+
+This outline is unclear as `B` clearly is a child of `A` but when we move on to `C` the clarity is lost. `C` is not a child of `B` with a highter indentation nor does ot haver the same indentation as `B`. The only thing that is clear is that the first node with smaller indentation, indicating a parent, is A. Then Mermaid relies on this known truth and compensates for the unclear indentation and selects `A` as a parent of `C` leading till the same diagram with `B` and `C` as sieblings.
+
+```mermaid-example
+mindmap
+Root
+    A
+        B
+      C
+```
+
+```mermaid
+mindmap
+Root
+    A
+        B
+      C
+```
diff --git a/package.json b/package.json
index a020a2116..cacde6635 100644
--- a/package.json
+++ b/package.json
@@ -67,10 +67,12 @@
     "d3": "^7.0.0",
     "dagre": "^0.8.5",
     "dagre-d3": "^0.6.4",
-    "dompurify": "2.4.0",
+    "dompurify": "2.3.10",
+    "fast-clone": "^1.5.13",
     "graphlib": "^2.1.8",
     "khroma": "^2.0.0",
-    "moment-mini": "2.24.0",
+    "moment-mini": "^2.24.0",
+    "non-layered-tidy-tree-layout": "^2.0.2",
     "stylis": "^4.0.10"
   },
   "devDependencies": {
diff --git a/src/config.type.ts b/src/config.type.ts
index 40b2b0b5a..6814a265c 100644
--- a/src/config.type.ts
+++ b/src/config.type.ts
@@ -27,10 +27,12 @@ export interface MermaidConfig {
   er?: ErDiagramConfig;
   pie?: PieDiagramConfig;
   requirement?: RequirementDiagramConfig;
+  mindmap?: MindmapDiagramConfig;
   gitGraph?: GitGraphDiagramConfig;
   c4?: C4DiagramConfig;
   dompurifyConfig?: DOMPurify.Config;
   wrap?: boolean;
+  fontSize?: number;
 }
 
 // TODO: More configs needs to be moved in here
@@ -212,6 +214,11 @@ export interface RequirementDiagramConfig extends BaseDiagramConfig {
   line_height?: number;
 }
 
+export interface MindmapDiagramConfig extends BaseDiagramConfig {
+  useMaxWidth: boolean;
+  padding: number;
+  maxNodeWidth: number;
+}
 export interface PieDiagramConfig extends BaseDiagramConfig {}
 
 export interface ErDiagramConfig extends BaseDiagramConfig {
diff --git a/src/defaultConfig.ts b/src/defaultConfig.ts
index 1c1566467..60d867437 100644
--- a/src/defaultConfig.ts
+++ b/src/defaultConfig.ts
@@ -1823,6 +1823,12 @@ const config: Partial<MermaidConfig> = {
     external_component_queue_bg_color: '#CCCCCC',
     external_component_queue_border_color: '#BFBFBF',
   },
+  mindmap: {
+    useMaxWidth: true,
+    padding: 10,
+    maxNodeWidth: 200,
+  },
+  fontSize: 16,
 };
 
 if (config.class) config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
diff --git a/src/diagram-api/diagram-orchestration.ts b/src/diagram-api/diagram-orchestration.ts
index f8b793ac4..eb4317d7b 100644
--- a/src/diagram-api/diagram-orchestration.ts
+++ b/src/diagram-api/diagram-orchestration.ts
@@ -1,29 +1,28 @@
 import { registerDiagram } from './diagramAPI';
-// 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 * as mindmapDb from '../diagrams/mindmap/mindmapDb';
+import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
+// @ts-ignore
+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';
 // @ts-ignore
 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
-// );
 export const addDiagrams = () => {
+  // Register mindmap and other built-in diagrams
   registerDiagram(
     'gitGraph',
-    { parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer },
+    { parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles },
     gitGraphDetector
   );
+  registerDiagram(
+    'mindmap',
+    { parser: mindmapParser, db: mindmapDb, renderer: mindmapRenderer, styles: mindmapStyles },
+    mindmapDetector
+  );
 };
diff --git a/src/diagram-api/diagramAPI.spec.ts b/src/diagram-api/diagramAPI.spec.ts
index 42c09099a..f72384c11 100644
--- a/src/diagram-api/diagramAPI.spec.ts
+++ b/src/diagram-api/diagramAPI.spec.ts
@@ -19,6 +19,7 @@ describe('DiagramAPI', () => {
         db: {},
         parser: {},
         renderer: {},
+        styles: {},
       },
       (text: string) => text.includes('loki')
     );
diff --git a/src/diagram-api/diagramAPI.ts b/src/diagram-api/diagramAPI.ts
index 47f484070..51807e034 100644
--- a/src/diagram-api/diagramAPI.ts
+++ b/src/diagram-api/diagramAPI.ts
@@ -1,58 +1,75 @@
 import c4Db from '../diagrams/c4/c4Db';
 import c4Renderer from '../diagrams/c4/c4Renderer';
+import c4Styles from '../diagrams/c4/styles';
 // @ts-ignore
 import c4Parser from '../diagrams/c4/parser/c4Diagram';
 import classDb from '../diagrams/class/classDb';
 import classRenderer from '../diagrams/class/classRenderer';
 import classRendererV2 from '../diagrams/class/classRenderer-v2';
+import classStyles from '../diagrams/class/styles';
 // @ts-ignore
 import classParser from '../diagrams/class/parser/classDiagram';
 import erDb from '../diagrams/er/erDb';
 import erRenderer from '../diagrams/er/erRenderer';
 // @ts-ignore
 import erParser from '../diagrams/er/parser/erDiagram';
+import erStyles from '../diagrams/er/styles';
 import flowDb from '../diagrams/flowchart/flowDb';
 import flowRenderer from '../diagrams/flowchart/flowRenderer';
 import flowRendererV2 from '../diagrams/flowchart/flowRenderer-v2';
+import flowStyles from '../diagrams/flowchart/styles';
 // @ts-ignore
 import flowParser from '../diagrams/flowchart/parser/flow';
 import ganttDb from '../diagrams/gantt/ganttDb';
 import ganttRenderer from '../diagrams/gantt/ganttRenderer';
 // @ts-ignore
 import ganttParser from '../diagrams/gantt/parser/gantt';
+import ganttStyles from '../diagrams/gantt/styles';
+
 import infoDb from '../diagrams/info/infoDb';
 import infoRenderer from '../diagrams/info/infoRenderer';
 // @ts-ignore
 import infoParser from '../diagrams/info/parser/info';
+import infoStyles from '../diagrams/info/styles';
 // @ts-ignore
 import pieParser from '../diagrams/pie/parser/pie';
 import pieDb from '../diagrams/pie/pieDb';
 import pieRenderer from '../diagrams/pie/pieRenderer';
+import pieStyles from '../diagrams/pie/styles';
 // @ts-ignore
 import requirementParser from '../diagrams/requirement/parser/requirementDiagram';
 import requirementDb from '../diagrams/requirement/requirementDb';
 import requirementRenderer from '../diagrams/requirement/requirementRenderer';
+import requirementStyles from '../diagrams/requirement/styles';
 // @ts-ignore
 import sequenceParser from '../diagrams/sequence/parser/sequenceDiagram';
 import sequenceDb from '../diagrams/sequence/sequenceDb';
 import sequenceRenderer from '../diagrams/sequence/sequenceRenderer';
+import sequenceStyles from '../diagrams/sequence/styles';
 // @ts-ignore
 import stateParser from '../diagrams/state/parser/stateDiagram';
 import stateDb from '../diagrams/state/stateDb';
 import stateRenderer from '../diagrams/state/stateRenderer';
 import stateRendererV2 from '../diagrams/state/stateRenderer-v2';
+import stateStyles from '../diagrams/state/styles';
 import journeyDb from '../diagrams/user-journey/journeyDb';
 import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
+import journeyStyles from '../diagrams/user-journey/styles';
 // @ts-ignore
 import journeyParser from '../diagrams/user-journey/parser/journey';
 import { addDetector, DiagramDetector } from './detectType';
-import { log } from '../logger';
+import { log as _log } from '../logger';
+import { getConfig as _getConfig } from '../config';
+import { sanitizeText as _sanitizeText } from '../diagrams/common/common';
 import { MermaidConfig } from '../config.type';
+import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox';
+import { addStylesForDiagram } from '../styles';
 
 export interface DiagramDefinition {
   db: any;
   renderer: any;
   parser: any;
+  styles: any;
   init?: (config: MermaidConfig) => void;
 }
 
@@ -64,6 +81,7 @@ const diagrams: Record<string, DiagramDefinition> = {
     init: (cnf) => {
       c4Renderer.setConf(cnf.c4);
     },
+    styles: c4Styles,
   },
   class: {
     db: classDb,
@@ -76,6 +94,7 @@ const diagrams: Record<string, DiagramDefinition> = {
       cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
       classDb.clear();
     },
+    styles: classStyles,
   },
   classDiagram: {
     db: classDb,
@@ -88,11 +107,13 @@ const diagrams: Record<string, DiagramDefinition> = {
       cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
       classDb.clear();
     },
+    styles: classStyles,
   },
   er: {
     db: erDb,
     renderer: erRenderer,
     parser: erParser,
+    styles: erStyles,
   },
   flowchart: {
     db: flowDb,
@@ -107,6 +128,7 @@ const diagrams: Record<string, DiagramDefinition> = {
       flowDb.clear();
       flowDb.setGen('gen-1');
     },
+    styles: flowStyles,
   },
   'flowchart-v2': {
     db: flowDb,
@@ -121,26 +143,31 @@ const diagrams: Record<string, DiagramDefinition> = {
       flowDb.clear();
       flowDb.setGen('gen-2');
     },
+    styles: flowStyles,
   },
   gantt: {
     db: ganttDb,
     renderer: ganttRenderer,
     parser: ganttParser,
+    styles: ganttStyles,
   },
   info: {
     db: infoDb,
     renderer: infoRenderer,
     parser: infoParser,
+    styles: infoStyles,
   },
   pie: {
     db: pieDb,
     renderer: pieRenderer,
     parser: pieParser,
+    styles: pieStyles,
   },
   requirement: {
     db: requirementDb,
     renderer: requirementRenderer,
     parser: requirementParser,
+    styles: requirementStyles,
   },
   sequence: {
     db: sequenceDb,
@@ -159,6 +186,7 @@ const diagrams: Record<string, DiagramDefinition> = {
       sequenceDb.setWrap(cnf.wrap);
       sequenceRenderer.setConf(cnf.sequence);
     },
+    styles: sequenceStyles,
   },
   state: {
     db: stateDb,
@@ -171,6 +199,7 @@ const diagrams: Record<string, DiagramDefinition> = {
       cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
       stateDb.clear();
     },
+    styles: stateStyles,
   },
   stateDiagram: {
     db: stateDb,
@@ -183,6 +212,7 @@ const diagrams: Record<string, DiagramDefinition> = {
       cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
       stateDb.clear();
     },
+    styles: stateStyles,
   },
   journey: {
     db: journeyDb,
@@ -192,6 +222,7 @@ const diagrams: Record<string, DiagramDefinition> = {
       journeyRenderer.setConf(cnf.journey);
       journeyDb.clear();
     },
+    styles: journeyStyles,
   },
 };
 
@@ -205,6 +236,7 @@ export const registerDiagram = (
   }
   diagrams[id] = diagram;
   addDetector(id, detector);
+  addStylesForDiagram(id, diagram.styles);
 };
 
 export const getDiagram = (name: string): DiagramDefinition => {
@@ -213,3 +245,8 @@ export const getDiagram = (name: string): DiagramDefinition => {
   }
   throw new Error(`Diagram ${name} not found.`);
 };
+
+export const log = _log;
+export const getConfig = _getConfig;
+export const sanitizeText = (text: string) => _sanitizeText(text, getConfig());
+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 = /<br\s*\/?>/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: '<br/>' },
+      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/c4/c4Renderer.js b/src/diagrams/c4/c4Renderer.js
index 6af59bb92..5ecc8aea2 100644
--- a/src/diagrams/c4/c4Renderer.js
+++ b/src/diagrams/c4/c4Renderer.js
@@ -6,7 +6,8 @@ import common from '../common/common';
 import c4Db from './c4Db';
 import * as configApi from '../../config';
 import assignWithDepth from '../../assignWithDepth';
-import { wrapLabel, calculateTextWidth, calculateTextHeight, configureSvgSize } from '../../utils';
+import { wrapLabel, calculateTextWidth, calculateTextHeight } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import addSVGAccessibilityFields from '../../accessibility';
 
 let globalBoundaryMaxX = 0,
diff --git a/src/diagrams/class/classRenderer-v2.js b/src/diagrams/class/classRenderer-v2.js
index da3f50b08..a211ab552 100644
--- a/src/diagrams/class/classRenderer-v2.js
+++ b/src/diagrams/class/classRenderer-v2.js
@@ -5,7 +5,8 @@ import { getConfig } from '../../config';
 import { render } from '../../dagre-wrapper/index.js';
 // import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
 import { curveLinear } from 'd3';
-import { interpolateToCurve, getStylesFromArray, setupGraphViewbox } from '../../utils';
+import { interpolateToCurve, getStylesFromArray } from '../../utils';
+import { setupGraphViewbox } from '../../setupGraphViewbox';
 import common from '../common/common';
 import addSVGAccessibilityFields from '../../accessibility';
 
diff --git a/src/diagrams/class/classRenderer.js b/src/diagrams/class/classRenderer.js
index 576b2d66a..9e9859fd6 100644
--- a/src/diagrams/class/classRenderer.js
+++ b/src/diagrams/class/classRenderer.js
@@ -3,7 +3,7 @@ import dagre from 'dagre';
 import graphlib from 'graphlib';
 import { log } from '../../logger';
 import svgDraw from './svgDraw';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import { getConfig } from '../../config';
 import addSVGAccessibilityFields from '../../accessibility';
 
diff --git a/src/diagrams/er/erRenderer.js b/src/diagrams/er/erRenderer.js
index 5b5e4de80..a7601f03f 100644
--- a/src/diagrams/er/erRenderer.js
+++ b/src/diagrams/er/erRenderer.js
@@ -6,7 +6,7 @@ import dagre from 'dagre';
 import { getConfig } from '../../config';
 import { log } from '../../logger';
 import erMarkers from './erMarkers';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import addSVGAccessibilityFields from '../../accessibility';
 import { parseGenericTypes } from '../common/common';
 
diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js
index 7d6e6d096..6b7c4c1bf 100644
--- a/src/diagrams/flowchart/flowRenderer-v2.js
+++ b/src/diagrams/flowchart/flowRenderer-v2.js
@@ -8,7 +8,8 @@ import { render } from '../../dagre-wrapper/index.js';
 import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
 import { log } from '../../logger';
 import common, { evaluate } from '../common/common';
-import { interpolateToCurve, getStylesFromArray, setupGraphViewbox } from '../../utils';
+import { interpolateToCurve, getStylesFromArray } from '../../utils';
+import { setupGraphViewbox } from '../../setupGraphViewbox';
 import addSVGAccessibilityFields from '../../accessibility';
 
 const conf = {};
diff --git a/src/diagrams/flowchart/flowRenderer.js b/src/diagrams/flowchart/flowRenderer.js
index c6e6ebdd6..f715019d8 100644
--- a/src/diagrams/flowchart/flowRenderer.js
+++ b/src/diagrams/flowchart/flowRenderer.js
@@ -5,7 +5,8 @@ import dagreD3 from 'dagre-d3';
 import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
 import { log } from '../../logger';
 import common, { evaluate } from '../common/common';
-import { interpolateToCurve, getStylesFromArray, setupGraphViewbox } from '../../utils';
+import { interpolateToCurve, getStylesFromArray } from '../../utils';
+import { setupGraphViewbox } from '../../setupGraphViewbox';
 import flowChartShapes from './flowChartShapes';
 import addSVGAccessibilityFields from '../../accessibility';
 
diff --git a/src/diagrams/gantt/ganttRenderer.js b/src/diagrams/gantt/ganttRenderer.js
index f0866617f..5a24d6d3f 100644
--- a/src/diagrams/gantt/ganttRenderer.js
+++ b/src/diagrams/gantt/ganttRenderer.js
@@ -13,7 +13,7 @@ import {
 } from 'd3';
 import common from '../common/common';
 import { getConfig } from '../../config';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import addSVGAccessibilityFields from '../../accessibility';
 
 export const setConf = function () {
diff --git a/src/diagrams/git/gitGraphRenderer.js b/src/diagrams/git/gitGraphRenderer.js
index 6eb542ce8..97f8be5d5 100644
--- a/src/diagrams/git/gitGraphRenderer.js
+++ b/src/diagrams/git/gitGraphRenderer.js
@@ -1,5 +1,5 @@
 import { select } from 'd3';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import { log } from '../../logger';
 import { getConfig } from '../../config';
 import addSVGAccessibilityFields from '../../accessibility';
diff --git a/src/diagrams/info/infoDb.js b/src/diagrams/info/infoDb.js
index 5a324fbb4..2a04f1633 100644
--- a/src/diagrams/info/infoDb.js
+++ b/src/diagrams/info/infoDb.js
@@ -1,5 +1,6 @@
 /** Created by knut on 15-01-14. */
 import { log } from '../../logger';
+import { clear } from '../../commonDb';
 
 var message = '';
 var info = false;
@@ -30,5 +31,6 @@ export default {
   getMessage,
   setInfo,
   getInfo,
+  clear,
   // parseError
 };
diff --git a/src/diagrams/mindmap/info.spc.js b/src/diagrams/mindmap/info.spc.js
deleted file mode 100644
index 69a969fb1..000000000
--- a/src/diagrams/mindmap/info.spc.js
+++ /dev/null
@@ -1,14 +0,0 @@
-describe('when parsing an info graph it', function () {
-  var ex;
-  beforeEach(function () {
-    ex = require('./parser/info').parser;
-    ex.yy = require('./infoDb');
-  });
-
-  it('should handle an info definition', function () {
-    var str = `info
-    showInfo`;
-
-    ex.parse(str);
-  });
-});
diff --git a/src/diagrams/mindmap/infoDb.js b/src/diagrams/mindmap/infoDb.js
deleted file mode 100644
index 5a324fbb4..000000000
--- a/src/diagrams/mindmap/infoDb.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/** Created by knut on 15-01-14. */
-import { log } from '../../logger';
-
-var message = '';
-var info = false;
-
-export const setMessage = (txt) => {
-  log.debug('Setting message to: ' + txt);
-  message = txt;
-};
-
-export const getMessage = () => {
-  return message;
-};
-
-export const setInfo = (inf) => {
-  info = inf;
-};
-
-export const getInfo = () => {
-  return info;
-};
-
-// export const parseError = (err, hash) => {
-//   global.mermaidAPI.parseError(err, hash)
-// }
-
-export default {
-  setMessage,
-  getMessage,
-  setInfo,
-  getInfo,
-  // parseError
-};
diff --git a/src/diagrams/mindmap/infoRenderer.js b/src/diagrams/mindmap/infoRenderer.js
deleted file mode 100644
index cbe3c52f8..000000000
--- a/src/diagrams/mindmap/infoRenderer.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/** Created by knut on 14-12-11. */
-import { select } from 'd3';
-import { log } from '../../logger';
-import { getConfig } from '../../config';
-
-/**
- * Draws a an info picture in the tag with id: id based on the graph definition in text.
- *
- * @param {any} text
- * @param {any} id
- * @param {any} version
- * @param diagObj
- */
-export const draw = (text, id, version, diagObj) => {
-  try {
-    // const parser = infoParser.parser;
-    // parser.yy = db;
-    log.debug('Renering info diagram\n' + text);
-
-    const securityLevel = getConfig().securityLevel;
-    // Handle root and Document for when rendering in sanbox mode
-    let sandboxElement;
-    if (securityLevel === 'sandbox') {
-      sandboxElement = select('#i' + id);
-    }
-    const root =
-      securityLevel === 'sandbox'
-        ? select(sandboxElement.nodes()[0].contentDocument.body)
-        : select('body');
-    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');
-
-    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);
-
-    svg.attr('height', 100);
-    svg.attr('width', 400);
-    // svg.attr('viewBox', '0 0 300 150');
-  } catch (e) {
-    log.error('Error while rendering info diagram');
-    log.error(e.message);
-  }
-};
-
-export default {
-  draw,
-};
diff --git a/src/diagrams/mindmap/mindmap.spec.js b/src/diagrams/mindmap/mindmap.spec.js
new file mode 100644
index 000000000..2b88a579d
--- /dev/null
+++ b/src/diagrams/mindmap/mindmap.spec.js
@@ -0,0 +1,327 @@
+import * as mindmapDB from './mindmapDb';
+
+describe('when parsing a mindmap ', function () {
+  let mindmap;
+  beforeEach(function () {
+    mindmap = require('./parser/mindmap').parser;
+    mindmap.yy = require('./mindmapDb');
+    mindmap.yy.clear();
+  });
+  describe('hiearchy', function () {
+    it('should handle a simple root definition', function () {
+      let str = `mindmap
+    root`;
+
+      mindmap.parse(str);
+      // console.log('Time for checks', mindmap.yy.getMindmap().descr);
+      expect(mindmap.yy.getMindmap().descr).toEqual('root');
+    });
+    it('should handle a hierachial mindmap definition', function () {
+      let str = `mindmap
+    root
+      child1
+      child2
+ `;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.descr).toEqual('root');
+      expect(mm.children.length).toEqual(2);
+      expect(mm.children[0].descr).toEqual('child1');
+      expect(mm.children[1].descr).toEqual('child2');
+    });
+
+    it('should handle a simple root definition with a shape and without an id abc123', function () {
+      let str = `mindmap
+    (root)`;
+
+      mindmap.parse(str);
+      // console.log('Time for checks', mindmap.yy.getMindmap().descr);
+      expect(mindmap.yy.getMindmap().descr).toEqual('root');
+    });
+
+    it('should handle a deeper hierachial mindmap definition', function () {
+      let str = `mindmap
+    root
+      child1
+        leaf1
+      child2`;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.descr).toEqual('root');
+      expect(mm.children.length).toEqual(2);
+      expect(mm.children[0].descr).toEqual('child1');
+      expect(mm.children[0].children[0].descr).toEqual('leaf1');
+      expect(mm.children[1].descr).toEqual('child2');
+    });
+    it('Multiple roots are illegal', function () {
+      let str = `mindmap
+    root
+    fakeRoot`;
+
+      try {
+        mindmap.parse(str);
+        // Fail test if above expression doesn't throw anything.
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe(
+          'There can be only one root. No parent could be found for ("fakeRoot")'
+        );
+      }
+    });
+    it('real root in wrong place', function () {
+      let str = `mindmap
+          root
+        fakeRoot
+    realRootWrongPlace`;
+
+      try {
+        mindmap.parse(str);
+        // Fail test if above expression doesn't throw anything.
+        expect(true).toBe(false);
+      } catch (e) {
+        expect(e.message).toBe(
+          'There can be only one root. No parent could be found for ("fakeRoot")'
+        );
+      }
+    });
+  });
+  describe('nodes', function () {
+    it('should handle an id and type for a node definition', function () {
+      let str = `mindmap
+    root[The root]
+      `;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('The root');
+      expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
+    });
+    it('should handle an id and type for a node definition', function () {
+      let str = `mindmap
+    root
+      theId(child1)`;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.descr).toEqual('root');
+      expect(mm.children.length).toEqual(1);
+      const child = mm.children[0];
+      expect(child.descr).toEqual('child1');
+      expect(child.nodeId).toEqual('theId');
+      expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT);
+    });
+    it('should handle an id and type for a node definition', function () {
+      let str = `mindmap
+root
+      theId(child1)`;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.descr).toEqual('root');
+      expect(mm.children.length).toEqual(1);
+      const child = mm.children[0];
+      expect(child.descr).toEqual('child1');
+      expect(child.nodeId).toEqual('theId');
+      expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT);
+    });
+    it('mutiple types (circle)', function () {
+      let str = `mindmap
+ root((the root))
+`;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.descr).toEqual('the root');
+      expect(mm.children.length).toEqual(0);
+      expect(mm.type).toEqual(mindmap.yy.nodeType.CIRCLE);
+    });
+
+    it('mutiple types (cloud)', function () {
+      let str = `mindmap
+ root)the root(
+`;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.descr).toEqual('the root');
+      expect(mm.children.length).toEqual(0);
+      expect(mm.type).toEqual(mindmap.yy.nodeType.CLOUD);
+    });
+    it('mutiple types (bang)', function () {
+      let str = `mindmap
+ root))the root((
+`;
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.descr).toEqual('the root');
+      expect(mm.children.length).toEqual(0);
+      expect(mm.type).toEqual(mindmap.yy.nodeType.BANG);
+    });
+  });
+  describe('decorations', function () {
+    it('should be possible to set an icon for the node', function () {
+      let str = `mindmap
+    root[The root]
+    ::icon(bomb)
+    `;
+      // ::class1 class2
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('The root');
+      expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
+      expect(mm.icon).toEqual('bomb');
+    });
+    it('should be possible to set classes for the node', function () {
+      let str = `mindmap
+    root[The root]
+    :::m-4 p-8
+    `;
+      // ::class1 class2
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('The root');
+      expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
+      expect(mm.class).toEqual('m-4 p-8');
+    });
+    it('should be possible to set both classes and icon for the node', function () {
+      let str = `mindmap
+    root[The root]
+    :::m-4 p-8
+    ::icon(bomb)
+    `;
+      // ::class1 class2
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('The root');
+      expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
+      expect(mm.class).toEqual('m-4 p-8');
+      expect(mm.icon).toEqual('bomb');
+    });
+    it('should be possible to set both classes and icon for the node', function () {
+      let str = `mindmap
+    root[The root]
+    ::icon(bomb)
+    :::m-4 p-8
+    `;
+      // ::class1 class2
+
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('The root');
+      expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
+      expect(mm.class).toEqual('m-4 p-8');
+      expect(mm.icon).toEqual('bomb');
+    });
+  });
+  describe('descriptions', function () {
+    it('should be possible to use node syntax in the descriptions', function () {
+      let str = `mindmap
+    root["String containing []"]
+`;
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('String containing []');
+    });
+    it('should be possible to use node syntax in the descriptions in children', function () {
+      let str = `mindmap
+    root["String containing []"]
+      child1["String containing ()"]
+`;
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('String containing []');
+      expect(mm.children.length).toEqual(1);
+      expect(mm.children[0].descr).toEqual('String containing ()');
+    });
+    it('should be possible to have a child after a class assignment', function () {
+      let str = `mindmap
+  root(Root)
+    Child(Child)
+    :::hot
+      a(a)
+      b[New Stuff]`;
+      mindmap.parse(str);
+      const mm = mindmap.yy.getMindmap();
+      expect(mm.nodeId).toEqual('root');
+      expect(mm.descr).toEqual('Root');
+      expect(mm.children.length).toEqual(1);
+
+      const child = mm.children[0];
+      expect(child.nodeId).toEqual('Child');
+      expect(child.children[0].nodeId).toEqual('a');
+      expect(child.children.length).toEqual(2);
+      expect(child.children[1].nodeId).toEqual('b');
+    });
+  });
+  it('should be possible to have meaningless empty rows in a mindmap abc124', function () {
+    let str = `mindmap
+  root(Root)
+    Child(Child)
+      a(a)
+
+      b[New Stuff]`;
+    mindmap.parse(str);
+    const mm = mindmap.yy.getMindmap();
+    expect(mm.nodeId).toEqual('root');
+    expect(mm.descr).toEqual('Root');
+    expect(mm.children.length).toEqual(1);
+
+    const child = mm.children[0];
+    expect(child.nodeId).toEqual('Child');
+    expect(child.children[0].nodeId).toEqual('a');
+    expect(child.children.length).toEqual(2);
+    expect(child.children[1].nodeId).toEqual('b');
+  });
+  it('should be possible to have comments in a mindmap', function () {
+    let str = `mindmap
+  root(Root)
+    Child(Child)
+      a(a)
+
+      %% This is a comment
+      b[New Stuff]`;
+    mindmap.parse(str);
+    const mm = mindmap.yy.getMindmap();
+    expect(mm.nodeId).toEqual('root');
+    expect(mm.descr).toEqual('Root');
+    expect(mm.children.length).toEqual(1);
+
+    const child = mm.children[0];
+    expect(child.nodeId).toEqual('Child');
+    expect(child.children[0].nodeId).toEqual('a');
+    expect(child.children.length).toEqual(2);
+    expect(child.children[1].nodeId).toEqual('b');
+  });
+
+  it('should be possible to have comments at the end of a line', function () {
+    let str = `mindmap
+  root(Root)
+    Child(Child)
+      a(a) %% This is a comment
+      b[New Stuff]`;
+    mindmap.parse(str);
+    const mm = mindmap.yy.getMindmap();
+    expect(mm.nodeId).toEqual('root');
+    expect(mm.descr).toEqual('Root');
+    expect(mm.children.length).toEqual(1);
+
+    const child = mm.children[0];
+    expect(child.nodeId).toEqual('Child');
+    expect(child.children[0].nodeId).toEqual('a');
+    expect(child.children.length).toEqual(2);
+    expect(child.children[1].nodeId).toEqual('b');
+  });
+});
diff --git a/src/diagrams/mindmap/mindmapDb.js b/src/diagrams/mindmap/mindmapDb.js
new file mode 100644
index 000000000..370b3f7d9
--- /dev/null
+++ b/src/diagrams/mindmap/mindmapDb.js
@@ -0,0 +1,151 @@
+/** Created by knut on 15-01-14. */
+import { sanitizeText, getConfig } from '../../diagram-api/diagramAPI';
+import { log } from '../../logger';
+
+let nodes = [];
+let cnt = 0;
+let elements = {};
+export const clear = () => {
+  nodes = [];
+  cnt = 0;
+  elements = {};
+};
+
+const getParent = function (level) {
+  for (let i = nodes.length - 1; i >= 0; i--) {
+    if (nodes[i].level < level) {
+      return nodes[i];
+    }
+  }
+  // No parent found
+  return null;
+};
+
+export const getMindmap = () => {
+  return nodes.length > 0 ? nodes[0] : null;
+};
+export const addNode = (level, id, descr, type) => {
+  console.info('addNode', level, id, descr, type);
+  const conf = getConfig();
+  const node = {
+    id: cnt++,
+    nodeId: sanitizeText(id),
+    level,
+    descr: sanitizeText(descr),
+    type,
+    children: [],
+    width: getConfig().mindmap.maxNodeWidth,
+  };
+  switch (node.type) {
+    case nodeType.ROUNDED_RECT:
+      node.padding = 2 * conf.mindmap.padding;
+      break;
+    case nodeType.RECT:
+      node.padding = 2 * conf.mindmap.padding;
+      break;
+    default:
+      node.padding = conf.mindmap.padding;
+  }
+  const parent = getParent(level);
+  if (parent) {
+    parent.children.push(node);
+    // Keep all nodes in the list
+    nodes.push(node);
+  } else {
+    if (nodes.length === 0) {
+      // First node, the root
+      nodes.push(node);
+    } else {
+      // Syntax error ... there can only bee one root
+      let error = new Error(
+        'There can be only one root. No parent could be found for ("' + node.descr + '")'
+      );
+      error.hash = {
+        text: 'branch ' + name,
+        token: 'branch ' + name,
+        line: '1',
+        loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
+        expected: ['"checkout ' + name + '"'],
+      };
+      throw error;
+    }
+  }
+};
+
+export const nodeType = {
+  DEFAULT: 0,
+  NO_BORDER: 0,
+  ROUNDED_RECT: 1,
+  RECT: 2,
+  CIRCLE: 3,
+  CLOUD: 4,
+  BANG: 5,
+};
+
+export const getType = (startStr, endStr) => {
+  log.debug('In get type', startStr, endStr);
+  switch (startStr) {
+    case '[':
+      return nodeType.RECT;
+    case '(':
+      return endStr === ')' ? nodeType.ROUNDED_RECT : nodeType.CLOUD;
+    case '((':
+      return nodeType.CIRCLE;
+    case ')':
+      return nodeType.CLOUD;
+    case '))':
+      return nodeType.BANG;
+    default:
+      return nodeType.DEFAULT;
+  }
+};
+
+export const setElementForId = (id, element) => {
+  elements[id] = element;
+};
+
+export const decorateNode = (decoration) => {
+  const node = nodes[nodes.length - 1];
+  if (decoration && decoration.icon) {
+    node.icon = sanitizeText(decoration.icon);
+  }
+  if (decoration && decoration.class) {
+    node.class = sanitizeText(decoration.class);
+  }
+};
+
+export const type2Str = (type) => {
+  switch (type) {
+    case nodeType.DEFAULT:
+      return 'no-border';
+    case nodeType.RECT:
+      return 'rect';
+    case nodeType.ROUNDED_RECT:
+      return 'rounded-rect';
+    case nodeType.CIRCLE:
+      return 'circle';
+    case nodeType.CLOUD:
+      return 'cloud';
+    case nodeType.BANG:
+      return 'bang';
+    default:
+      return 'no-border';
+  }
+};
+
+export const getNodeById = (id) => nodes[id];
+export const getElementById = (id) => elements[id];
+// export default {
+// //   getMindmap,
+//   // addNode,
+//   // clear,
+//   // nodeType,
+//   // getType,
+//   // decorateNode,
+//   // setElementForId,
+//   getElementById: (id) => elements[id],
+//   // getNodeById: (id) => nodes.find((node) => node.id === id),
+//   getNodeById: (id) => nodes[id],
+//   // type2Str,
+//   // parseError
+// };
diff --git a/src/diagrams/mindmap/mindmapDetector.old b/src/diagrams/mindmap/mindmapDetector.old
new file mode 100644
index 000000000..4fe85af03
--- /dev/null
+++ b/src/diagrams/mindmap/mindmapDetector.old
@@ -0,0 +1,8 @@
+const detector = function detect(txt) {
+  if (txt.match(/^\s*mindmap/)) {
+    return 'mindmap';
+  }
+  return null;
+};
+
+export default detector;
diff --git a/src/diagrams/mindmap/mindmapDetector.ts b/src/diagrams/mindmap/mindmapDetector.ts
new file mode 100644
index 000000000..8b45f3681
--- /dev/null
+++ b/src/diagrams/mindmap/mindmapDetector.ts
@@ -0,0 +1,5 @@
+import type { DiagramDetector } from '../../diagram-api/detectType';
+
+export const mindmapDetector: DiagramDetector = (txt) => {
+  return txt.match(/^\s*mindmap/) !== null;
+};
diff --git a/src/diagrams/mindmap/mindmapRenderer.js b/src/diagrams/mindmap/mindmapRenderer.js
new file mode 100644
index 000000000..f3c6011b8
--- /dev/null
+++ b/src/diagrams/mindmap/mindmapRenderer.js
@@ -0,0 +1,275 @@
+/** Created by knut on 14-12-11. */
+import { select } from 'd3';
+import { log, getConfig, setupGraphViewbox } from '../../diagram-api/diagramAPI';
+import svgDraw from './svgDraw';
+import { BoundingBox, Layout, Tree } from 'non-layered-tidy-tree-layout';
+import clone from 'fast-clone';
+import * as db from './mindmapDb';
+
+/**
+ * @param {any} svg The svg element to draw the diagram onto
+ * @param {object} mindmap The maindmap data and hierarchy
+ * @param section
+ * @param {object} conf The configuration object
+ */
+function drawNodes(svg, mindmap, section, conf) {
+  svgDraw.drawNode(svg, mindmap, section, conf);
+  if (mindmap.children) {
+    mindmap.children.forEach((child, index) => {
+      drawNodes(svg, child, section < 0 ? index : section, conf);
+    });
+  }
+}
+
+/**
+ * @param {any} svg The svg element to draw the diagram onto
+ * @param edgesElem
+ * @param mindmap
+ * @param parent
+ * @param depth
+ * @param section
+ * @param conf
+ */
+function drawEdges(edgesElem, mindmap, parent, depth, section, conf) {
+  if (parent) {
+    svgDraw.drawEdge(edgesElem, mindmap, parent, depth, section, conf);
+  }
+  if (mindmap.children) {
+    mindmap.children.forEach((child, index) => {
+      drawEdges(edgesElem, child, mindmap, depth + 1, section < 0 ? index : section, conf);
+    });
+  }
+}
+
+/**
+ * @param mindmap
+ * @param callback
+ */
+function eachNode(mindmap, callback) {
+  callback(mindmap);
+  if (mindmap.children) {
+    mindmap.children.forEach((child) => {
+      eachNode(child, callback);
+    });
+  }
+}
+/** @param {object} mindmap */
+function transpose(mindmap) {
+  eachNode(mindmap, (node) => {
+    const orgWidth = node.width;
+    const orgX = node.x;
+    node.width = node.height;
+    node.height = orgWidth;
+    node.x = node.y;
+    node.y = orgX;
+  });
+  return mindmap;
+}
+/** @param {object} mindmap */
+function bottomToUp(mindmap) {
+  log.debug('bottomToUp', mindmap);
+  eachNode(mindmap.result, (node) => {
+    // node.y = node.y - (node.y - bb.top) * 2 - node.height;
+    node.y = node.y - (node.y - 0) * 2 - node.height;
+  });
+  return mindmap;
+}
+/** @param {object} mindmap The mindmap hierarchy */
+function rightToLeft(mindmap) {
+  eachNode(mindmap.result, (node) => {
+    // node.y = node.y - (node.y - bb.top) * 2 - node.height;
+    node.x = node.x - (node.x - 0) * 2 - node.width;
+  });
+  return mindmap;
+}
+
+/**
+ * @param mindmap
+ * @param dir
+ * @param conf
+ */
+function layout(mindmap, dir, conf) {
+  const bb = new BoundingBox(30, 60);
+
+  const layout = new Layout(bb);
+  switch (dir) {
+    case 'TB':
+      return layout.layout(mindmap);
+    case 'BT':
+      return bottomToUp(layout.layout(mindmap));
+    case 'RL': {
+      transpose(mindmap);
+      let newRes = layout.layout(mindmap);
+      transpose(newRes.result);
+      return rightToLeft(newRes);
+    }
+    case 'LR': {
+      transpose(mindmap);
+      let newRes = layout.layout(mindmap);
+      transpose(newRes.result);
+      return newRes;
+    }
+    default:
+  }
+}
+const dirFromIndex = (index) => {
+  const dirNum = (index + 2) % 4;
+  switch (dirNum) {
+    case 0:
+      return 'LR';
+    case 1:
+      return 'RL';
+    case 2:
+      return 'TB';
+    case 3:
+      return 'BT';
+    default:
+      return 'TB';
+  }
+};
+
+const mergeTrees = (node, trees) => {
+  node.x = trees[0].result.x;
+  node.y = trees[0].result.y;
+  trees.forEach((tree) => {
+    tree.result.children.forEach((child) => {
+      const dx = node.x - tree.result.x;
+      const dy = node.y - tree.result.y;
+      eachNode(child, (childNode) => {
+        const orgNode = db.getNodeById(childNode.id);
+        if (orgNode) {
+          orgNode.x = childNode.x + dx;
+          orgNode.y = childNode.y + dy;
+        }
+      });
+    });
+  });
+  return node;
+};
+
+/**
+ * @param node
+ * @param isRoot
+ * @param parent
+ * @param conf
+ */
+function layoutMindmap(node, conf) {
+  // BoundingBox(gap, bottomPadding)
+  // const bb = new BoundingBox(10, 10);
+  // const layout = new Layout(bb);
+  // // const layout = new HorizontalLayout(bb);
+  if (node.children.length === 0) {
+    return node;
+  }
+  const trees = [];
+  // node.children.forEach((child, index) => {
+  //   const tree = clone(node);
+  //   tree.children = [tree.children[index]];
+  //   trees.push(layout(tree, dirFromIndex(index), conf));
+  // });
+
+  let cnt = 0;
+  // For each direction, create a new tree with the same root, and add a ubset of the children to it.
+  for (let i = 0; i < 4; i++) {
+    // Calculate the number of the children of the root node that will be used in this direction
+    const numChildren =
+      Math.floor(node.children.length / 4) + (node.children.length % 4 > i ? 1 : 0);
+    // Copy the original root node
+    const tree = clone(node);
+    // Setup the new copy with the children to be rendered in this direction
+    tree.children = [];
+    for (let j = 0; j < numChildren; j++) {
+      tree.children.push(node.children[cnt]);
+      cnt++;
+    }
+    if (tree.children.length > 0) {
+      trees.push(layout(tree, dirFromIndex(i), conf));
+    }
+  }
+  // Let each node know the direct of its tree for when we draw the branches.
+  trees.forEach((tree, index) => {
+    tree.result.direction = dirFromIndex(index);
+    eachNode(tree.result, (node) => {
+      node.direction = dirFromIndex(index);
+    });
+  });
+
+  // Merge the trees into a single tree
+  const result = mergeTrees(node, trees);
+  eachNode;
+  return node;
+}
+/**
+ * @param node
+ * @param isRoot
+ * @param conf
+ */
+function positionNodes(node, conf) {
+  svgDraw.positionNode(node, conf);
+  if (node.children) {
+    node.children.forEach((child) => {
+      positionNodes(child, conf);
+    });
+  }
+}
+
+/**
+ * Draws a an info picture in the tag with id: id based on the graph definition in text.
+ *
+ * @param {any} text
+ * @param {any} id
+ * @param {any} version
+ * @param diagObj
+ */
+export const draw = (text, id, version, diagObj) => {
+  const conf = getConfig();
+  try {
+    log.debug('Renering info diagram\n' + text);
+
+    const securityLevel = getConfig().securityLevel;
+    // Handle root and Document for when rendering in sanbox mode
+    let sandboxElement;
+    if (securityLevel === 'sandbox') {
+      sandboxElement = select('#i' + id);
+    }
+    const root =
+      securityLevel === 'sandbox'
+        ? select(sandboxElement.nodes()[0].contentDocument.body)
+        : select('body');
+    const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
+
+    // Parse the graph definition
+
+    const svg = root.select('#' + id);
+
+    const g = svg.append('g');
+    const mm = diagObj.db.getMindmap();
+
+    // 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 edgesElem = svg.append('g');
+    edgesElem.attr('class', 'mindmap-edges');
+    const nodesElem = svg.append('g');
+    nodesElem.attr('class', 'mindmap-nodes');
+    drawNodes(nodesElem, mm, -1, conf);
+
+    // Next step is to layout the mindmap, giving each node a position
+
+    const positionedMindmap = layoutMindmap(mm, conf);
+
+    // After this we can draw, first the edges and the then nodes with the correct position
+    drawEdges(edgesElem, positionedMindmap, null, 0, -1, conf);
+    positionNodes(positionedMindmap, conf);
+
+    // Setup the view box and size of the svg element
+    setupGraphViewbox(undefined, svg, conf.mindmap.padding, conf.mindmap.useMaxWidth);
+  } catch (e) {
+    log.error('Error while rendering info diagram');
+    log.error(e.message);
+  }
+};
+
+export default {
+  draw,
+};
diff --git a/src/diagrams/mindmap/parser/mindamap.jison b/src/diagrams/mindmap/parser/mindamap.jison
deleted file mode 100644
index 473b63fcf..000000000
--- a/src/diagrams/mindmap/parser/mindamap.jison
+++ /dev/null
@@ -1,48 +0,0 @@
-/** mermaid
- *  https://knsv.github.io/mermaid
- *  (c) 2015 Knut Sveidqvist
- *  MIT license.
- */
-%lex
-
-%options case-insensitive
-
-%{
-	// Pre-lexer code can go here
-%}
-
-%%
-
-"info"		      return 'info'    ;
-[\s\n\r]+         return 'NL'      ;
-[\s]+ 		      return 'space';
-"showInfo"		  return 'showInfo';
-<<EOF>>           return 'EOF'     ;
-.                 return 'TXT' ;
-
-/lex
-
-%start start
-
-%% /* language grammar */
-
-start
-// %{	: info document 'EOF' { return yy; } }
-	: info document 'EOF' { return yy; }
-	;
-
-document
-	: /* empty */
-	| document line
-	;
-
-line
-	: statement { }
-	| 'NL'
-	;
-
-statement
-	:  showInfo   { yy.setInfo(true);  }
-	;
-
-%%
diff --git a/src/diagrams/mindmap/parser/mindmap.jison b/src/diagrams/mindmap/parser/mindmap.jison
new file mode 100644
index 000000000..d84c09495
--- /dev/null
+++ b/src/diagrams/mindmap/parser/mindmap.jison
@@ -0,0 +1,103 @@
+/** mermaid
+ *  https://knsv.github.io/mermaid
+ *  (c) 2015 Knut Sveidqvist
+ *  MIT license.
+ */
+%lex
+
+%options case-insensitive
+
+%{
+	// Pre-lexer code can go here
+%}
+%x NODE
+%x NSTR
+%x ICON
+%x CLASS
+
+%%
+
+\s*\%\%.*\n {console.log('Found comment',yytext);}
+// \%\%[^\n]*\n                             /* skip comments */
+"mindmap"		       return 'MINDMAP';
+":::"              { this.begin('CLASS'); }
+<CLASS>.+			     { this.popState();return 'CLASS'; }
+<CLASS>\n				   { this.popState();}
+[\n\s]*"::icon("   { this.begin('ICON'); }
+[\n]+             /* return 'NL'; */
+<ICON>[^\)]+			 { return 'ICON'; }
+<ICON>\)				   {this.popState();}
+"-)"               { console.log('Exploding node'); this.begin('NODE');return 'NODE_DSTART'; }
+"(-"               { console.log('Cloud'); this.begin('NODE');return 'NODE_DSTART'; }
+"))"               { console.log('Explosion Bang'); this.begin('NODE');return 'NODE_DSTART'; }
+")"               { console.log('Cloud Bang'); this.begin('NODE');return 'NODE_DSTART'; }
+"(("               { this.begin('NODE');return 'NODE_DSTART'; }
+"("                { this.begin('NODE');return 'NODE_DSTART'; }
+"["                { this.begin('NODE');return 'NODE_DSTART'; }
+[\s]+              return 'SPACELIST'                 /* skip all whitespace */    ;
+// !(-\()            return 'NODE_ID';
+[^\(\[\n\-\)]+         return 'NODE_ID';
+<<EOF>>            return 'EOF';
+<NODE>["]          { console.log('Starting NSTR');this.begin("NSTR");}
+<NSTR>[^"]+        { console.log('description:', yytext); return "NODE_DESCR";}
+<NSTR>["]          {this.popState();}
+<NODE>[\)]\)         {this.popState();console.log('node end ))');return "NODE_DEND";}
+<NODE>[\)]         {this.popState();console.log('node end )');return "NODE_DEND";}
+<NODE>[\]]         {this.popState();console.log('node end ...');return "NODE_DEND";}
+<NODE>"(-"         {this.popState();console.log('node end (-');return "NODE_DEND";}
+<NODE>"-)"         {this.popState();console.log('node end (-');return "NODE_DEND";}
+<NODE>"(("         {this.popState();console.log('node end ((');return "NODE_DEND";}
+<NODE>"("         {this.popState();console.log('node end ((');return "NODE_DEND";}
+<NODE>[^\)\]\(]+     { console.log('Long description:', yytext);   return 'NODE_DESCR';}
+<NODE>.+(?!\(\()     { console.log('Long description:', yytext);   return 'NODE_DESCR';}
+// [\[]               return 'NODE_START';
+// .+                 return 'TXT' ;
+
+/lex
+
+%start start
+
+%% /* language grammar */
+
+start
+// %{	: info document 'EOF' { return yy; } }
+	: MINDMAP document  { return yy; }
+  |	SPACELIST MINDMAP document  { return yy; }
+	;
+
+document
+	: document line
+	| line
+	;
+
+line
+	: statement { }
+	;
+
+statement
+	: SPACELIST node      { yy.addNode($1.length, $2.id, $2.descr, $2.type);  }
+	| SPACELIST ICON       { yy.decorateNode({icon: $2}); }
+	| SPACELIST EOF
+	| SPACELIST NL
+	| node					{ console.log($1.id);yy.addNode(0, $1.id, $1.descr, $1.type);  }
+	| ICON                 { yy.decorateNode({icon: $1}); }
+	| SPACELIST CLASS       { yy.decorateNode({class: $2}); }
+	| CLASS                 { yy.decorateNode({class: $1}); }
+	| EOF
+	;
+node
+  :nodeWithId
+  |nodeWithoutId
+  ;
+
+nodeWithoutId
+  :   NODE_DSTART NODE_DESCR NODE_DEND
+	      { console.log("node found ..", $1); $$ = { id: $2, descr: $2, type: yy.getType($1, $3) }; }
+  ;
+
+nodeWithId
+	:  NODE_ID             { $$ = { id: $1, descr: $1, type: yy.nodeType.DEFAULT }; }
+	|  NODE_ID NODE_DSTART NODE_DESCR NODE_DEND
+	                       { console.log("node found ..", $1); $$ = { id: $1, descr: $3, type: yy.getType($2, $4) }; }
+	;
+%%
diff --git a/src/diagrams/mindmap/styles.js b/src/diagrams/mindmap/styles.js
index 0b0729813..76d6a9c1b 100644
--- a/src/diagrams/mindmap/styles.js
+++ b/src/diagrams/mindmap/styles.js
@@ -1,3 +1,76 @@
-const getStyles = () => ``;
+import { darken, lighten, adjust, invert, isDark } from 'khroma';
 
+const genSections = (options) => {
+  let sections = '';
+
+  for (let i = 0; i < 8; i++) {
+    options['lineColor' + i] = options['lineColor' + i] || options['gitInv' + i];
+    if (isDark(options['lineColor' + i])) {
+      options['lineColor' + i] = lighten(options['lineColor' + i], 20);
+    } else {
+      options['lineColor' + i] = darken(options['lineColor' + i], 20);
+    }
+  }
+
+  for (let i = 0; i < 8; i++) {
+    const sw = '' + (17 - 3 * i);
+    sections += `
+    .section-${i - 1} rect, .section-${i - 1} path, .section-${i - 1} circle, .section-${
+      i - 1
+    } path  {
+      fill: ${options['git' + i]};
+    }
+    .section-${i - 1} text {
+     fill: ${options['gitBranchLabel' + i]};
+    //  fill: ${options['gitInv' + i]};
+    }
+    .node-icon-${i - 1} {
+      font-size: 40px;
+      color: ${options['gitBranchLabel' + i]};
+      // color: ${options['gitInv' + i]};
+    }
+    .section-edge-${i - 1}{
+      stroke: ${options['git' + i]};
+    }
+    .edge-depth-${i - 1}{
+      stroke-width: ${sw};
+    }
+    .section-${i - 1} line {
+      stroke: ${options['lineColor' + i]} ;
+      stroke-width: 3;
+    }
+
+    .disabled, .disabled circle, .disabled text {
+      fill: lightgray;
+    }
+    .disabled text {
+      fill: #efefef;
+    }
+    `;
+  }
+  return sections;
+};
+
+const getStyles = (options) =>
+  `
+  .edge {
+    stroke-width: 3;
+  }
+  ${genSections(options)}
+  .section-root rect, .section-root path, .section-root circle  {
+    fill: ${options.git0};
+  }
+  .section-root text {
+    fill: ${options.gitBranchLabel0};
+  }
+  .icon-container {
+    height:100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  .edge {
+    fill: none;
+  }
+`;
 export default getStyles;
diff --git a/src/diagrams/mindmap/svgDraw.js b/src/diagrams/mindmap/svgDraw.js
new file mode 100644
index 000000000..511c46e20
--- /dev/null
+++ b/src/diagrams/mindmap/svgDraw.js
@@ -0,0 +1,322 @@
+const lineBreakRegex = /<br\s*\/?>/gi;
+import { select } from 'd3';
+import * as db from './mindmapDb';
+
+/**
+ * @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+|<br>)/)
+        .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 === '<br>') {
+        line.pop();
+        tspan.text(line.join(' ').trim());
+        if (word === '<br>') {
+          line = [''];
+        } else {
+          line = [word];
+        }
+
+        tspan = text
+          .append('tspan')
+          .attr('x', 0)
+          .attr('y', y)
+          .attr('dy', lineHeight + 'em')
+          .text(word);
+      }
+    }
+  });
+}
+
+const defaultBkg = function (elem, node, section, conf) {
+  const rd = 5;
+  const r = elem
+    .append('path')
+    .attr('id', 'node-' + node.id)
+    .attr('class', 'node-bkg node-' + db.type2Str(node.type))
+    .attr(
+      'd',
+      `M0 ${node.height - rd} v${-node.height + 2 * rd} q0,-5 5,-5 h${
+        node.width - 2 * rd
+      } q5,0 5,5 v${node.height - rd} H0 Z`
+    );
+
+  elem
+    .append('line')
+    .attr('class', 'node-line-' + section)
+    .attr('x1', 0)
+    .attr('y1', node.height)
+    .attr('x2', node.width)
+    .attr('y2', node.height);
+};
+const rectBkg = function (elem, node, section, conf) {
+  const r = elem
+    .append('rect')
+    .attr('id', 'node-' + node.id)
+    .attr('class', 'node-bkg node-' + db.type2Str(node.type))
+    .attr('height', node.height)
+    .attr('width', node.width);
+};
+const cloudBkg = function (elem, node, section, conf) {
+  const rd = 5;
+  const r = elem;
+  const w = node.width;
+  const h = node.height;
+  const r0 = 0.1 * w;
+  const r1 = 0.15 * w;
+  const r2 = 0.25 * w;
+  const r3 = 0.35 * w;
+  const r4 = 0.2 * w;
+  const p = elem
+    .append('path')
+    .attr('id', 'node-' + node.id)
+    .attr('class', 'node-bkg node-' + db.type2Str(node.type))
+    .attr(
+      'd',
+      `M0 0 a${r1},${r1} 0 0,1 ${w * 0.25},${-1 * w * 0.1}
+      a${r3},${r3} 1 0,1 ${w * 0.4},${-1 * w * 0.1}
+      a${r2},${r2} 1 0,1 ${w * 0.35},${1 * w * 0.2}
+
+      a${r1},${r1} 1 0,1 ${w * 0.15},${1 * h * 0.35}
+      a${r4},${r4} 1 0,1 ${-1 * w * 0.15},${1 * h * 0.65}
+
+      a${r2},${r1} 1 0,1 ${-1 * w * 0.25},${w * 0.15}
+      a${r3},${r3} 1 0,1 ${-1 * w * 0.5},${0}
+      a${r1},${r1} 1 0,1 ${-1 * w * 0.25},${-1 * w * 0.15}
+
+      a${r1},${r1} 1 0,1 ${-1 * w * 0.1},${-1 * h * 0.35}
+      a${r4},${r4} 1 0,1 ${w * 0.1},${-1 * h * 0.65}
+
+    H0 V0 Z`
+    );
+};
+const bangBkg = function (elem, node, section, conf) {
+  const rd = 5;
+  const w = node.width;
+  const h = node.height;
+  const r = 0.15 * w;
+  const p = elem
+    .append('path')
+    .attr('id', 'node-' + node.id)
+    .attr('class', 'node-bkg node-' + db.type2Str(node.type))
+    .attr(
+      'd',
+      `M0 0 a${r},${r} 1 0,0 ${w * 0.25},${-1 * h * 0.1}
+      a${r},${r} 1 0,0 ${w * 0.25},${0}
+      a${r},${r} 1 0,0 ${w * 0.25},${0}
+      a${r},${r} 1 0,0 ${w * 0.25},${1 * h * 0.1}
+
+      a${r},${r} 1 0,0 ${w * 0.15},${1 * h * 0.33}
+      a${r * 0.8},${r * 0.8} 1 0,0 ${0},${1 * h * 0.34}
+      a${r},${r} 1 0,0 ${-1 * w * 0.15},${1 * h * 0.33}
+
+      a${r},${r} 1 0,0 ${-1 * w * 0.25},${h * 0.15}
+      a${r},${r} 1 0,0 ${-1 * w * 0.25},${0}
+      a${r},${r} 1 0,0 ${-1 * w * 0.25},${0}
+      a${r},${r} 1 0,0 ${-1 * w * 0.25},${-1 * h * 0.15}
+
+      a${r},${r} 1 0,0 ${-1 * w * 0.1},${-1 * h * 0.33}
+      a${r * 0.8},${r * 0.8} 1 0,0 ${0},${-1 * h * 0.34}
+      a${r},${r} 1 0,0 ${w * 0.1},${-1 * h * 0.33}
+
+    H0 V0 Z`
+    );
+};
+const circleBkg = function (elem, node, section, conf) {
+  const r = elem
+    .append('circle')
+    .attr('id', 'node-' + node.id)
+    .attr('class', 'node-bkg node-' + db.type2Str(node.type))
+    .attr('r', node.width / 2);
+  // .attr('width', node.width);
+};
+const roundedRectBkg = function (elem, node, section, conf) {
+  const r = elem
+    .append('rect')
+    .attr('id', 'node-' + node.id)
+    .attr('class', 'node-bkg node-' + db.type2Str(node.type))
+    .attr('height', node.height)
+    .attr('rx', node.padding)
+    .attr('ry', node.padding)
+    .attr('width', node.width);
+};
+
+/**
+ * @param {object} elem The D3 dom element in which the node is to be added
+ * @param {object} node The node to be added
+ * @param section
+ * @param {object} conf The configuration object
+ * @returns {number} The height nodes dom element
+ */
+export const drawNode = function (elem, node, section, conf) {
+  const nodeElem = elem.append('g');
+  nodeElem.attr(
+    'class',
+    (node.class ? node.class + ' ' : '') +
+      'mindmap-node ' +
+      (section === -1 ? 'section-root' : 'section-' + section)
+  );
+  const bkgElem = nodeElem.append('g');
+
+  // Create the wrapped text element
+  const textElem = nodeElem.append('g');
+  const txt = textElem
+    .append('text')
+    .text(node.descr)
+    .attr('dy', '1em')
+    // .attr('dy', '0')
+    .attr('alignment-baseline', 'middle')
+    .attr('dominant-baseline', 'middle')
+    .attr('text-anchor', 'middle')
+    .call(wrap, node.width);
+  const bbox = txt.node().getBBox();
+  const fontSize = conf.fontSize.replace ? conf.fontSize.replace('px', '') : conf.fontSize;
+  node.height = bbox.height + fontSize * 1.1 * 0.5 + node.padding;
+  node.width = bbox.width + 2 * node.padding;
+  if (node.icon) {
+    if (node.type === db.nodeType.CIRCLE) {
+      node.height += 50;
+      const orgWidth = node.width;
+      node.width += 50;
+      // node.width = Math.max(orgWidth, 100);
+      const widthDiff = Math.abs(node.width - orgWidth);
+      const icon = nodeElem
+        .append('foreignObject')
+        .attr('height', '50px')
+        .attr('width', node.width)
+        .attr('style', 'text-align: center;');
+      // .attr('x', 0)
+      // .attr('y', 0)
+      // .attr('class', 'node-icon ' + node.icon);
+      icon
+        .append('div')
+        .attr('class', 'icon-container')
+        .append('i')
+        .attr('class', 'node-icon-' + section + ' ' + node.icon);
+      textElem.attr(
+        'transform',
+        'translate(' + node.width / 2 + ', ' + (node.height / 2 - 1.5 * node.padding) + ')'
+      );
+    } else {
+      node.width += 50;
+      const orgHeight = node.height;
+      node.height = Math.max(orgHeight, 60);
+      const heightDiff = Math.abs(node.height - orgHeight);
+      const icon = nodeElem
+        .append('foreignObject')
+        .attr('width', '60px')
+        .attr('height', node.height)
+        .attr('style', 'text-align: center;margin-top:' + heightDiff / 2 + 'px;');
+      // .attr('x', 0)
+      // .attr('y', 0)
+      // .attr('class', 'node-icon ' + node.icon);
+      icon
+        .append('div')
+        .attr('class', 'icon-container')
+        .append('i')
+        .attr('class', 'node-icon-' + section + ' ' + node.icon);
+      textElem.attr(
+        'transform',
+        'translate(' + (25 + node.width / 2) + ', ' + (heightDiff / 2 + node.padding / 2) + ')'
+      );
+    }
+  } else {
+    textElem.attr('transform', 'translate(' + node.width / 2 + ', ' + node.padding / 2 + ')');
+  }
+
+  switch (node.type) {
+    case db.nodeType.DEFAULT:
+      defaultBkg(bkgElem, node, section, conf);
+      break;
+    case db.nodeType.ROUNDED_RECT:
+      roundedRectBkg(bkgElem, node, section, conf);
+      break;
+    case db.nodeType.RECT:
+      rectBkg(bkgElem, node, section, conf);
+      break;
+    case db.nodeType.CIRCLE:
+      bkgElem.attr('transform', 'translate(' + node.width / 2 + ', ' + +node.height / 2 + ')');
+      circleBkg(bkgElem, node, section, conf);
+      break;
+    case db.nodeType.CLOUD:
+      // bkgElem.attr('transform', 'translate(' + node.width / 2 + ', ' + +node.height / 2 + ')');
+      cloudBkg(bkgElem, node, section, conf);
+      break;
+    case db.nodeType.BANG:
+      // bkgElem.attr('transform', 'translate(' + node.width / 2 + ', ' + +node.height / 2 + ')');
+      bangBkg(bkgElem, node, section, conf);
+      break;
+    default:
+    // defaultBkg(bkgElem, node, section, conf);
+  }
+
+  // Position the node to its coordinate
+  if (typeof node.x !== 'undefined' && typeof node.y !== 'undefined') {
+    nodeElem.attr('transform', 'translate(' + node.x + ',' + node.y + ')');
+  }
+  db.setElementForId(node.id, nodeElem);
+  return node.height;
+};
+
+export const drawEdge = function drawEdge(edgesElem, mindmap, parent, depth, section, conf) {
+  // edgesElem
+  //   .append('line')
+  //   .attr('x1', parent.x + parent.width / 2)
+  //   .attr('y1', parent.y + parent.height / 2)
+  //   .attr('x2', mindmap.x + mindmap.width / 2)
+  //   .attr('y2', mindmap.y + mindmap.height / 2)
+  //   .attr('class', 'edge section-edge-' + section + ' edge-depth-' + depth);
+
+  //<path d="M100,250 Q250,100 400,250 T700,250" />
+
+  const sx = parent.x + parent.width / 2;
+  const sy = parent.y + parent.height / 2;
+  const ex = mindmap.x + mindmap.width / 2;
+  const ey = mindmap.y + mindmap.height / 2;
+  const mx = ex > sx ? sx + Math.abs(sx - ex) / 2 : sx - Math.abs(sx - ex) / 2;
+  const my = ey > sy ? sy + Math.abs(sy - ey) / 2 : sy - Math.abs(sy - ey) / 2;
+  const qx = ex > sx ? Math.abs(sx - mx) / 2 + sx : -Math.abs(sx - mx) / 2 + sx;
+  const qy = ey > sy ? Math.abs(sy - my) / 2 + sy : -Math.abs(sy - my) / 2 + sy;
+
+  edgesElem
+    .append('path')
+    .attr(
+      'd',
+      parent.direction === 'TB' || parent.direction === 'BT'
+        ? `M${sx},${sy} Q${sx},${qy} ${mx},${my} T${ex},${ey}`
+        : `M${sx},${sy} Q${qx},${sy} ${mx},${my} T${ex},${ey}`
+    )
+    .attr('class', 'edge section-edge-' + section + ' edge-depth-' + depth);
+};
+
+export const positionNode = function (node, conf) {
+  const nodeElem = db.getElementById(node.id);
+
+  const x = node.x || 0;
+  const y = node.y || 0;
+  // Position the node to its coordinate
+  nodeElem.attr('transform', 'translate(' + x + ',' + y + ')');
+};
+
+export default { drawNode, positionNode, drawEdge };
diff --git a/src/diagrams/pie/pieRenderer.js b/src/diagrams/pie/pieRenderer.js
index b5ffc9de3..f8e21bc9d 100644
--- a/src/diagrams/pie/pieRenderer.js
+++ b/src/diagrams/pie/pieRenderer.js
@@ -1,7 +1,7 @@
 /** Created by AshishJ on 11-09-2019. */
 import { select, scaleOrdinal, pie as d3pie, arc } from 'd3';
 import { log } from '../../logger';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import * as configApi from '../../config';
 import addSVGAccessibilityFields from '../../accessibility';
 
diff --git a/src/diagrams/requirement/requirementRenderer.js b/src/diagrams/requirement/requirementRenderer.js
index e07612e0e..7a43edaee 100644
--- a/src/diagrams/requirement/requirementRenderer.js
+++ b/src/diagrams/requirement/requirementRenderer.js
@@ -2,7 +2,7 @@ import { line, select } from 'd3';
 import dagre from 'dagre';
 import graphlib from 'graphlib';
 import { log } from '../../logger';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import common from '../common/common';
 import markers from './requirementMarkers';
 import { getConfig } from '../../config';
diff --git a/src/diagrams/sequence/sequenceRenderer.js b/src/diagrams/sequence/sequenceRenderer.js
index c3ea1bcfd..7bdc5958f 100644
--- a/src/diagrams/sequence/sequenceRenderer.js
+++ b/src/diagrams/sequence/sequenceRenderer.js
@@ -6,7 +6,8 @@ import common from '../common/common';
 // import sequenceDb from './sequenceDb';
 import * as configApi from '../../config';
 import assignWithDepth from '../../assignWithDepth';
-import utils, { configureSvgSize } from '../../utils';
+import utils from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import addSVGAccessibilityFields from '../../accessibility';
 
 let conf = {};
diff --git a/src/diagrams/state/stateRenderer-v2.js b/src/diagrams/state/stateRenderer-v2.js
index 37dbf2e0a..4452f9491 100644
--- a/src/diagrams/state/stateRenderer-v2.js
+++ b/src/diagrams/state/stateRenderer-v2.js
@@ -3,7 +3,7 @@ import { select } from 'd3';
 import { getConfig } from '../../config';
 import { render } from '../../dagre-wrapper/index.js';
 import { log } from '../../logger';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import common from '../common/common';
 import addSVGAccessibilityFields from '../../accessibility';
 
diff --git a/src/diagrams/state/stateRenderer.js b/src/diagrams/state/stateRenderer.js
index 53e89da3b..363ca23f7 100644
--- a/src/diagrams/state/stateRenderer.js
+++ b/src/diagrams/state/stateRenderer.js
@@ -5,7 +5,7 @@ import { log } from '../../logger';
 import common from '../common/common';
 import { drawState, addTitleAndBox, drawEdge } from './shapes';
 import { getConfig } from '../../config';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import addSVGAccessibilityFields from '../../accessibility';
 
 // TODO Move conf object to main conf in mermaidAPI
diff --git a/src/diagrams/user-journey/journeyRenderer.js b/src/diagrams/user-journey/journeyRenderer.js
index 0e3f94f34..f30a2b1b0 100644
--- a/src/diagrams/user-journey/journeyRenderer.js
+++ b/src/diagrams/user-journey/journeyRenderer.js
@@ -1,7 +1,7 @@
 import { select } from 'd3';
 import svgDraw from './svgDraw';
 import { getConfig } from '../../config';
-import { configureSvgSize } from '../../utils';
+import { configureSvgSize } from '../../setupGraphViewbox';
 import addSVGAccessibilityFields from '../../accessibility';
 
 export const setConf = function (cnf) {
diff --git a/src/docs/_sidebar.md b/src/docs/_sidebar.md
index 54ef50afb..f89f30318 100644
--- a/src/docs/_sidebar.md
+++ b/src/docs/_sidebar.md
@@ -17,6 +17,7 @@
   - [Requirement Diagram](requirementDiagram.md)
   - [Gitgraph (Git) Diagram 🔥](gitgraph.md)
   - [C4C Diagram (Context) Diagram 🦺⚠️](c4c.md)
+  - [Mindmaps 🦺⚠️](mindmap.md)
   - [Other Examples](examples.md)
 
 - ⚙️ Deployment and Configuration
diff --git a/src/docs/mindmap.md b/src/docs/mindmap.md
new file mode 100644
index 000000000..141808514
--- /dev/null
+++ b/src/docs/mindmap.md
@@ -0,0 +1,158 @@
+# Mindmap
+
+**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/mindmap.md)
+
+> Mindmap: This is an experimental diagram for now. The syntax and properties can change in future releases. The syntax is stabel except for the icon integration which is the experimental part.
+
+"A mind map is a diagram used to visually organize information into a hierarchy, showing relationships among pieces of the whole. It is often created around a single concept, drawn as an image in the center of a blank page, to which associated representations of ideas such as images, words and parts of words are added. Major ideas are connected directly to the central concept, and other ideas branch out from those major ideas." Wikipedia
+
+### An example of a mindmap.
+
+```mermaid
+mindmap
+  root((mindmap))
+    Origins
+      Long history
+      ::icon(fa fa-book)
+      Popularisation
+        British popular psychology author Tony Buzan
+    Research
+      On effectivness<br/>and eatures
+      On Automatic creation
+        Uses
+            Creative techniques
+            Strategic planning
+            Argument mapping
+    Tools
+      Pen and paper
+      Mermaid
+
+```
+
+## Syntax
+
+The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy.
+
+In the following example you can see how there are 3 dufferent levels. One with starting at the left of the text and another level with two rows starting at the same column, defining the node A. At the end there is one more level where the text is indented further then the prevoius lines defining the nodes B and C.
+
+```
+mindmap
+    Root
+        A
+            B
+            C
+```
+
+In summary is is a simple text outline where there are one node at the root level called `Root` which has one child `A`. A in turn has two children `B`and `C`. In the diagram below we can see this rendered as a mindmap.
+
+```mermaid
+mindmap
+Root
+    A
+      B
+      C
+```
+
+In this way we can use a text outline to generate a hierarchical mindmap.
+
+## Different shapes
+
+Mermaids mindmaps can show node using different shapes. When specifying a shape for a node the syntax for the is similar to flowchart nodes, with an id followed by the shape definition and with the text within the shape delimiters. Where possible we try/will try to keep the same shapes as for flowcharts even though they are not all supported from the start.
+
+Mindmap can show the following shapes:
+
+### Square
+
+```mermaid-example
+mindmap
+    id[I am a square]
+```
+
+### Rounded square
+
+```mermaid-example
+mindmap
+    id(I am a rounded square)
+```
+
+### Circle
+
+```mermaid-example
+mindmap
+    id((I am a circle))
+```
+
+### Bang
+
+```mermaid-example
+mindmap
+    id))I am a bang((
+```
+
+### Cloud
+
+```mermaid-example
+mindmap
+    id)I am a cloud(
+```
+
+### Default
+
+```mermaid-example
+mindmap
+    I am the default shape
+```
+
+More shapes will be added, beginning with the shapes available in flowcharts.
+
+# Icons and classes
+
+## icons
+
+As with flowcharts you can add icons to your nodes but with an updated syntax. The styling for the font based icons are added during the integration so that they are available for the web page. _This is not something a diagram author can do but has to be done with the site administrator or the integrator_. Once the icon fonts are in place you add them to the mind map nodes using the `::icon()` syntax. You place the classes for the icon within the parethesis like in the following example where icons for material design and fontwaresome 4. is displayed. The intention is that this approach should be used for all diagrams supporting icons. **Expermental feature:** This wider scope is also the reason Mindmaps are experimental as this syntax and approach could change.
+
+```mermaid-example
+mindmap
+    Root
+        A
+        ::icon(fa fa-book)
+        B(B)
+        ::icon(mdi mdi-skull-outline)
+```
+
+## Classes
+
+Again the syntax for adding classes is similar to flowcharts and you can add classes using a tripple colon following a numver of css classes separated by space. In the following example one of the nodes has two custom classes attached urgent turning the background red and the text whiet and large increasing the font size:
+
+```mermaid-example
+mindmap
+    Root
+        A[A]
+        :::urgent large
+        B(B)
+        C
+```
+
+_These classes needs top be supplied by the site administrator._
+
+## Unclear indentation
+
+The actual indentation does not really matter only compared with the previous rows. If we take the previous example and disrupt it a little we can se how the calculations are performed. Let us start with placing C with a smaller indentation than `B`but larger then `A`.
+
+```
+mindmap
+    Root
+        A
+            B
+          C
+```
+
+This outline is unclear as `B` clearly is a child of `A` but when we move on to `C` the clarity is lost. `C` is not a child of `B` with a highter indentation nor does ot haver the same indentation as `B`. The only thing that is clear is that the first node with smaller indentation, indicating a parent, is A. Then Mermaid relies on this known truth and compensates for the unclear indentation and selects `A` as a parent of `C` leading till the same diagram with `B` and `C` as sieblings.
+
+```mermaid
+mindmap
+Root
+    A
+        B
+      C
+```
diff --git a/src/mermaid.ts b/src/mermaid.ts
index e82597152..48c2f8790 100644
--- a/src/mermaid.ts
+++ b/src/mermaid.ts
@@ -30,6 +30,9 @@ import { isDetailedError } from './utils';
  * ```
  *
  * Renders the mermaid diagrams
+ * @param config
+ * @param nodes
+ * @param callback
  */
 const init = function (
   config?: MermaidConfig,
@@ -124,7 +127,7 @@ const initThrowsErrors = function (
         element
       );
     } catch (error) {
-      log.warn('Catching Error (bootstrap)');
+      log.warn('Catching Error (bootstrap)', error);
       // @ts-ignore
       // TODO: We should be throwing an error object.
       throw { error, message: error.str };
diff --git a/src/setupGraphViewbox.js b/src/setupGraphViewbox.js
new file mode 100644
index 000000000..79dcbfd5c
--- /dev/null
+++ b/src/setupGraphViewbox.js
@@ -0,0 +1,85 @@
+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();
+  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, 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;
+
+  log.info(`SVG bounds: ${sWidth}x${sHeight}`, svgBounds);
+
+  let width = 0;
+  let height = 0;
+  log.info(`Graph bounds: ${width}x${height}`, graph);
+
+  // let tx = 0;
+  // let ty = 0;
+  // 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;
+  // }
+
+  // width =
+  log.info(`Calculated bounds: ${width}x${height}`);
+  configureSvgSize(svgElem, height, width, useMaxWidth);
+
+  // Ensure the viewBox includes the whole svgBounds area with extra space for padding
+  // const vBox = `0 0 ${width} ${height}`;
+  const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${
+    svgBounds.width + 2 * padding
+  } ${svgBounds.height + 2 * padding}`;
+
+  svgElem.attr('viewBox', vBox);
+};
diff --git a/src/setupGraphViewbox.spec.js b/src/setupGraphViewbox.spec.js
new file mode 100644
index 000000000..6b5c3e210
--- /dev/null
+++ b/src/setupGraphViewbox.spec.js
@@ -0,0 +1,20 @@
+import utils from './utils';
+import assignWithDepth from './assignWithDepth';
+import { detectType } from './diagram-api/detectType';
+import { addDiagrams } from './diagram-api/diagram-orchestration';
+import { calculateSvgSizeAttrs } from './setupGraphViewbox';
+addDiagrams();
+
+describe('when calculating SVG size', function () {
+  it('should return width 100% when useMaxWidth is true', function () {
+    const attrs = calculateSvgSizeAttrs(100, 200, true);
+    // expect(attrs.get('height')).toEqual(100);
+    expect(attrs.get('style')).toEqual('max-width: 200px;');
+    expect(attrs.get('width')).toEqual('100%');
+  });
+  it('should return absolute width when useMaxWidth is false', function () {
+    const attrs = calculateSvgSizeAttrs(100, 200, false);
+    // expect(attrs.get('height')).toEqual(100);
+    expect(attrs.get('width')).toEqual(200);
+  });
+});
diff --git a/src/styles.ts b/src/styles.ts
index 29ebb4fe4..b0201f649 100644
--- a/src/styles.ts
+++ b/src/styles.ts
@@ -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';
@@ -24,7 +24,7 @@ const themes = {
   class: classDiagram,
   stateDiagram,
   state: stateDiagram,
-  gitGraph,
+  // gitGraph,
   info,
   pie,
   er,
@@ -103,4 +103,9 @@ const getStyles = (
 `;
 };
 
+export const addStylesForDiagram = (type: string, diagramTheme: any) => {
+  // @ts-ignore
+  themes[type] = diagramTheme;
+};
+
 export default getStyles;
diff --git a/src/utils.spec.js b/src/utils.spec.js
index 37f004a7e..ebaa1415c 100644
--- a/src/utils.spec.js
+++ b/src/utils.spec.js
@@ -2,7 +2,6 @@ import utils from './utils';
 import assignWithDepth from './assignWithDepth';
 import { detectType } from './diagram-api/detectType';
 import { addDiagrams } from './diagram-api/diagram-orchestration';
-
 addDiagrams();
 
 describe('when assignWithDepth: should merge objects within objects', function () {
@@ -291,19 +290,6 @@ describe('when formatting urls', function () {
     expect(result).toEqual('about:blank');
   });
 });
-describe('when calculating SVG size', function () {
-  it('should return width 100% when useMaxWidth is true', function () {
-    const attrs = utils.calculateSvgSizeAttrs(100, 200, true);
-    // expect(attrs.get('height')).toEqual(100);
-    expect(attrs.get('style')).toEqual('max-width: 200px;');
-    expect(attrs.get('width')).toEqual('100%');
-  });
-  it('should return absolute width when useMaxWidth is false', function () {
-    const attrs = utils.calculateSvgSizeAttrs(100, 200, false);
-    // expect(attrs.get('height')).toEqual(100);
-    expect(attrs.get('width')).toEqual(200);
-  });
-});
 
 describe('when initializing the id generator', function () {
   it('should return a random number generator based on Date', function (done) {
diff --git a/src/utils.ts b/src/utils.ts
index 78d083c9a..f88327367 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -735,92 +735,6 @@ const d3Attrs = function (d3Elem, attrs) {
   }
 };
 
-/**
- * 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 {boolean} useMaxWidth Whether or not to use max-width and set width to 100%
- */
-export const configureSvgSize = function (svgElem, height, width, useMaxWidth) {
-  const attrs = calculateSvgSizeAttrs(height, 1 * 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;
-
-  log.info(`SVG bounds: ${sWidth}x${sHeight}`, svgBounds);
-
-  let width = graph._label.width;
-  let height = graph._label.height;
-  log.info(`Graph bounds: ${width}x${height}`, graph);
-
-  // let tx = 0;
-  // let ty = 0;
-  // 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;
-  // }
-
-  // width =
-  log.info(`Calculated bounds: ${width}x${height}`);
-  configureSvgSize(svgElem, height, width, useMaxWidth);
-
-  // Ensure the viewBox includes the whole svgBounds area with extra space for padding
-  // const vBox = `0 0 ${width} ${height}`;
-  const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${
-    svgBounds.width + 2 * padding
-  } ${svgBounds.height + 2 * padding}`;
-  log.info(
-    'Graph.label',
-    graph._label,
-    'swidth',
-    sWidth,
-    'sheight',
-    sHeight,
-    'width',
-    width,
-    'height',
-    height,
-
-    'vBox',
-    vBox
-  );
-  svgElem.attr('viewBox', vBox);
-  // svgElem.select('g').attr('transform', `translate(${tx}, ${ty})`);
-};
-
 export const initIdGenerator = class iterator {
   constructor(deterministic, seed) {
     this.deterministic = deterministic;
@@ -969,9 +883,6 @@ export default {
   calculateTextHeight,
   calculateTextWidth,
   calculateTextDimensions,
-  calculateSvgSizeAttrs,
-  configureSvgSize,
-  setupGraphViewbox,
   detectInit,
   detectDirective,
   isSubstringInArray,
diff --git a/yarn.lock b/yarn.lock
index 3946ac130..2834342ca 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2055,18 +2055,6 @@
     "@types/yargs" "^17.0.8"
     chalk "^4.0.0"
 
-"@jest/types@^29.0.1", "@jest/types@^29.0.2":
-  version "29.0.2"
-  resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.0.2.tgz#5a5391fa7f7f41bf4b201d6d2da30e874f95b6c1"
-  integrity sha512-5WNMesBLmlkt1+fVkoCjHa0X3i3q8zc4QLTDkdHgCa2gyPZc7rdlZBWgVLqwS1860ZW5xJuCDwAzqbGaXIr/ew==
-  dependencies:
-    "@jest/schemas" "^29.0.0"
-    "@types/istanbul-lib-coverage" "^2.0.0"
-    "@types/istanbul-reports" "^3.0.0"
-    "@types/node" "*"
-    "@types/yargs" "^17.0.8"
-    chalk "^4.0.0"
-
 "@jest/types@^29.0.2":
   version "29.0.2"
   resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.0.2.tgz#5a5391fa7f7f41bf4b201d6d2da30e874f95b6c1"
@@ -5422,10 +5410,10 @@ domhandler@^5.0.1, domhandler@^5.0.2:
   dependencies:
     domelementtype "^2.3.0"
 
-dompurify@2.4.0:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.0.tgz#c9c88390f024c2823332615c9e20a453cf3825dd"
-  integrity sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==
+dompurify@2.3.10:
+  version "2.3.10"
+  resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.10.tgz#901f7390ffe16a91a5a556b94043314cd4850385"
+  integrity sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g==
 
 domutils@^3.0.1:
   version "3.0.1"
@@ -6055,6 +6043,11 @@ extsprintf@^1.2.0:
   resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
   integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
 
+fast-clone@^1.5.13:
+  version "1.5.13"
+  resolved "https://registry.yarnpkg.com/fast-clone/-/fast-clone-1.5.13.tgz#7fe17542ae1c872e71bf80d177d00c11f51c2ea7"
+  integrity sha512-0ez7coyFBQFjZtId+RJqJ+EQs61w9xARfqjqK0AD9vIUkSxWD4HvPt80+5evebZ1tTnv1GYKrPTipx7kOW5ipA==
+
 fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
   version "3.1.3"
   resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -7937,18 +7930,6 @@ jest-util@^28.0.0, jest-util@^28.1.3:
     graceful-fs "^4.2.9"
     picomatch "^2.2.3"
 
-jest-util@^29.0.1, jest-util@^29.0.2:
-  version "29.0.2"
-  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.0.2.tgz#c75c5cab7f3b410782f9570a60c5558b5dfb6e3a"
-  integrity sha512-ozk8ruEEEACxqpz0hN9UOgtPZS0aN+NffwQduR5dVlhN+eN47vxurtvgZkYZYMpYrsmlAEx1XabkB3BnN0GfKQ==
-  dependencies:
-    "@jest/types" "^29.0.2"
-    "@types/node" "*"
-    chalk "^4.0.0"
-    ci-info "^3.2.0"
-    graceful-fs "^4.2.9"
-    picomatch "^2.2.3"
-
 jest-util@^29.0.2:
   version "29.0.2"
   resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.0.2.tgz#c75c5cab7f3b410782f9570a60c5558b5dfb6e3a"
@@ -9145,10 +9126,10 @@ module-deps-sortable@^5.0.3:
     through2 "^2.0.0"
     xtend "^4.0.0"
 
-moment-mini@2.24.0:
-  version "2.24.0"
-  resolved "https://registry.yarnpkg.com/moment-mini/-/moment-mini-2.24.0.tgz#fa68d98f7fe93ae65bf1262f6abb5fb6983d8d18"
-  integrity sha512-9ARkWHBs+6YJIvrIp0Ik5tyTTtP9PoV0Ssu2Ocq5y9v8+NOOpWiRshAp8c4rZVWTOe+157on/5G+zj5pwIQFEQ==
+moment-mini@^2.24.0:
+  version "2.29.4"
+  resolved "https://registry.yarnpkg.com/moment-mini/-/moment-mini-2.29.4.tgz#cbbcdc58ce1b267506f28ea6668dbe060a32758f"
+  integrity sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==
 
 moment@^2.23.0:
   version "2.29.4"
@@ -9263,6 +9244,11 @@ nomnom@1.5.2:
     chalk "~0.4.0"
     underscore "~1.6.0"
 
+non-layered-tidy-tree-layout@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz#57d35d13c356643fc296a55fb11ac15e74da7804"
+  integrity sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==
+
 normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
   version "2.5.0"
   resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
