This project is heavily inspired by dundalek's markmap.

Introduction

What is markmap?

Markmap is a combination of markdown and mindmap. It parses markdown content and extract its intrinsic hierarchical structure and renders an interactive mindmap, aka markmap.

The easiest way to use it is to load your markdown content to the try it out 👉 page and see your markmap on the right.

You can also try it in:

Projects

markmap-lib

NPM

Transform Markdown to data used by markmap.

Installation

$ yarn add markmap-lib

Usage

Parse markdown and create a node tree, return the root node and a features object containing the active features during parsing.

Transform Markdown to markmap data:

import { Transformer } from 'markmap-lib';

const transformer = new Transformer();

// 1. transform markdown
const { root, features } = transformer.transform(markdown);

// 2. get assets
// either get assets required by used features
const { styles, scripts } = transformer.getUsedAssets(features);
// or get all possible assets that could be used later
const { styles, scripts } = transformer.getAssets(features);

Now we have the data for rendering. See markmap-view 👇 for how to use them.

markmap-view

NPM

Render a markmap from transformed data.

Installation

$ yarn add markmap-view

Usage

Create an SVG element with explicit width and height:

<script src="https://cdn.jsdelivr.net/npm/d3@6"></script>
<script src="https://cdn.jsdelivr.net/npm/markmap-view"></script>

<svg id="markmap" style="width: 800px; height: 800px"></svg>

We got { root } from transforming, and possible extraneous assets { styles, scripts }.

Now we can render a markmap to the SVG element:

// load with <script>
const { markmap } = window;
// or with ESM
import * as markmap from 'markmap-view';

const { Markmap, loadCSS, loadJS } = markmap;

// 1. load assets
if (styles) loadCSS(styles);
if (scripts) loadJS(scripts, { getMarkmap: () => markmap });

// 2. create markmap
// `options` is optional, i.e. `undefined` can be passed here
Markmap.create('#markmap', options, root);

The first argument of Markmap.create can also be an actual SVG element, for example:

const svgEl = document.querySelector('#markmap');
Markmap.create(svgEl, options, data);

markmap-cli

NPM

Use markmap command-line in a local terminal.

Usage

$ npx markmap-cli markmap.md

You can also install it globally:

$ yarn global add markmap-cli
$ markmap markmap.md

There is a watch mode so that you could edit the Markdown file and get updates on the fly:

$ markmap -w markmap.md

coc-markmap

NPM

Installation

Make sure coc.nvim is started.

Then install with the Vim command:

:CocInstall coc-markmap

Usage

Open a Markdown file in Vim / Neovim, and execute:

:CocCommand markmap.create

An HTML file with the same basename as the Markdown file will be created and opened in your default browser.

Visualization of selected text is also supported.

Migration notes

0.10.x -> 0.11.x

There is a transformer instance now:

- import { transform, getUsedAssets, getAssets, fillTemplate } from 'markmap-lib';
+ import { Transformer, fillTemplate } from 'markmap-lib';

+ const transformer = new Transformer();

- const { root, features } = transform(markdown);
+ const { root, features } = transformer.transform(markdown);

- const { styles, scripts } = getUsedAssets(features);
+ const { styles, scripts } = transformer.getUsedAssets(features);
  // or
- const { styles, scripts } = getAssets();
+ const { styles, scripts } = transformer.getAssets();

0.9.x -> 0.10.x

The entrance has changed:

- import { transform, getUsedAssets, getAssets } from 'markmap-lib/dist/transform';
- import { fillTemplate } from 'markmap-lib/dist/template';
+ import { transform, getUsedAssets, getAssets, fillTemplate } from 'markmap-lib';

- import * as markmap from 'markmap-lib/dist/view';
- import { Markmap, loadCSS, loadJS } from 'markmap-lib/dist/view';
+ import * as markmap from 'markmap-view';
+ import { Markmap, loadCSS, loadJS } from 'markmap-view';

0.8.x -> 0.9.x

In 0.9.x the plugins at rendering time are removed in favor of the transforming plugins. As a result, the generated markmap can be loaded faster with less overhead and hopefully without flash of untranspiled code. The transforming plugins are enabled on demand, i.e. when the markdown content is detected to have the feature included.

So the changes are:

Transforming

We get both the root node and a map of used features. Then we get the assets list for future usage.

- import { transform } from 'markmap-lib/dist/transform';
+ import { transform, getUsedAssets, getAssets } from 'markmap-lib/dist/transform';

- const root = transform(markdown);
+ const { root, features } = transform(markdown);

+ const assets = getUsedAssets(features);
+ // or just get all possible assets if the content may change in the future
+ const assets = getAssets();

Filling the template

We need to inject the extraneous assets required by plugins to the output.

  import { fillTemplate } from 'markmap-lib/dist/template';

- const html = fillTemplate(root);
+ const html = fillTemplate(root, assets);

Render

We don't need to load the view plugins any more, but we'll have to include the assets if plugin features are used.

- import { Markmap, loadPlugins } from 'markmap-lib/dist/view';
+ import * as markmap from 'markmap-lib/dist/view';
+ import { Markmap, loadCSS, loadJS } from 'markmap-lib/dist/view';

+ const { styles, scripts } = assets;
+ if (styles) loadCSS(styles);
+ if (scripts) loadJS(scripts, { getMarkmap: () => markmap });

- loadPlugins([
-   'mathJax',
-   'prism',
- ])
- .then(() => {
    Markmap.create('#markmap', null, data);
- });

Note that the scripts may want to access markmap module, so we should export a getMarkmap method to loadScript. However this can be omitted if your markmap library is loaded from CDN and can be accessed via window.markmap.

+ <script src="https://cdn.jsdelivr.net/npm/markmap-lib/dist/browser/view.min.js"></script>
  console.log(window.markmap); // -> the markmap object
- if (scripts) loadJS(scripts, { getMarkmap: () => markmap });
+ if (scripts) loadJS(scripts);