This commit is contained in:
Knut Sveidqvist 2016-10-30 16:13:11 +01:00
commit 09558e6e9a
23 changed files with 538 additions and 91 deletions

View File

@ -12,26 +12,29 @@ This is why mermaid was born, a simple markdown-like script language for generat
The code below would render the following image
<table>
<tr><th>Code</th><th>Rendered diagram</th></tr>
<tr><td>
<pre>
<code>
<tr><th>Code</th><th>Rendered diagram</th></tr>
<tr>
<td>
<pre>
<code>
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
<code>
</pre>
</td>
<td>
<img src='http://www.sveido.com/mermaid/img/ex1.png' alt='Example 1'>
</td>
</tr>
<tr>
<td>
<pre>
<code>
</code>
</pre>
</td>
<td>
<p align="center">
<img src='http://www.sveido.com/mermaid/img/ex1.png' alt='Example 1'>
</p>
</td>
</tr>
<tr>
<td>
<pre>
<code>
sequenceDiagram
participant Alice
participant Bob
@ -43,13 +46,38 @@ sequenceDiagram
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
</code>
</pre>
</td>
<td>
<img src='http://www.sveido.com/mermaid/img/seq1.png' alt='Example 2'>
</td>
</tr>
</code>
</pre>
</td>
<td>
<img src='http://www.sveido.com/mermaid/img/seq1.png' alt='Example 2'>
</td>
</tr>
<tr>
<td>
<pre>
<code>
classDiagram
Class01 <|-- AveryLongClass : Cool
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
</code>
</pre>
</td>
<td>
<img src='./docs/img/class-diagram.png' alt='Example 3'>
</td>
</tr>
</table>
## Further reading

View File

@ -86,6 +86,7 @@ Mermaid is supported in a number of publishing systems and editors. Please repor
* [Plugin for atom](https://atom.io/packages/atom-mermaid)
* [Markdown Plus](http://mdp.tylingsoft.com/)
* [Vim Plugin](https://github.com/kannokanno/previm)
* [Sphinx extension](https://github.com/mgaitan/sphinxcontrib-mermaid)
# Online live editor

View File

@ -190,7 +190,7 @@ else
end
```
or if there is sequence that is optionat (if without else).
or if there is sequence that is optional (if without else).
```
opt Describing text

View File

@ -77,7 +77,7 @@ Would end up like this:
```
An id is also added to mermaid tags without id.
###Labels out of bounds
### Labels out of bounds
If you use dynamically loaded fonts that are loaded through CSS, such as Google fonts, mermaid should wait for the
whole page to have been loaded (dom + assets, particularly the fonts file).

BIN
docs/img/class-diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -29,7 +29,7 @@ function cli(options) {
, css: 't'
, width: 'w'
}
, 'boolean': ['help', 'png', 'svg']
, 'boolean': ['help', 'png', 'svg', 'verbose']
, 'string': ['outputDir']
}
@ -94,25 +94,38 @@ cli.prototype.parse = function(argv, next) {
else {
options.png = true
}
if (options.sequenceConfig) {
options.sequenceConfig = checkConfig(options.sequenceConfig)
try {
fs.accessSync(options.sequenceConfig, fs.R_OK)
} catch (err) {
this.errors.push(err)
}
} else {
options.sequenceConfig = null
}
if (options.ganttConfig) {
options.ganttConfig = checkConfig(options.ganttConfig)
try {
fs.accessSync(options.ganttConfig, fs.R_OK)
} catch (err) {
this.errors.push(err)
}
} else {
options.ganttConfig = null
}
if (options.css) {
try {
options.css = fs.readFileSync(options.css, 'utf8')
fs.accessSync(options.css, fs.R_OK)
} catch (err) {
this.errors.push(err)
}
} else {
options.css = fs.readFileSync(path.join(__dirname, '..', 'dist', 'mermaid.css'))
options.css = path.join(__dirname, '..', 'dist', 'mermaid.css')
}
// set svg/png flags appropriately
@ -136,17 +149,6 @@ cli.prototype.parse = function(argv, next) {
}
}
function checkConfig(configPath) {
try {
var text = fs.readFileSync(configPath, 'utf8');
JSON.parse(text)
return text
} catch (e) {
console.log(e);
return null;
}
}
function createCheckPhantom(_phantomPath) {
var phantomPath = _phantomPath
, phantomVersion

View File

@ -18,7 +18,7 @@ function processMermaid(files, _options, _next) {
, outputDir
, options.png
, options.svg
, options.css || ''
, options.css
, options.sequenceConfig
, options.ganttConfig
, options.verbose

View File

@ -28,7 +28,6 @@ var system = require('system')
, fs = require('fs')
, webpage = require('webpage')
var page = webpage.create()
, files = system.args.slice(9, system.args.length)
, width = system.args[8]
@ -40,21 +39,15 @@ var options = {
outputDir: system.args[1]
, png: system.args[2] === 'true' ? true : false
, svg: system.args[3] === 'true' ? true : false
, css: system.args[4] !== '' ? system.args[4] : '* { margin: 0; padding: 0; }'
, sequenceConfig: system.args[5]
, ganttConfig: system.args[6]
, css: fs.read(system.args[4])
, sequenceConfig: system.args[5] !== 'null' ? JSON.parse(fs.read(system.args[5])) : '{}'
, ganttConfig: system.args[6] !== 'null' ? fs.read(system.args[6]) : '{}'
, verbose: system.args[7] === 'true' ? true : false
, width: width
}
, log = logger(options.verbose)
// If no css is suuplied make sure a fixed witdth is given to the gant renderer
if(system.args[3] !== ''){
if(typeof options.ganttConfig === 'undefined'){
options.ganttConfig = {};
}
options.ganttConfig.useWidth = 1200;
}
options.sequenceConfig.useMaxWidth = false;
page.content = [
'<html>'
@ -218,7 +211,7 @@ function resolveForeignObjects(element) {
function executeInPage(data) {
var xmlSerializer = new XMLSerializer()
, contents = data.contents
, sequenceConfig = data.sequenceConfig
, sequenceConfig = JSON.stringify(data.sequenceConfig)
, ganttConfig = data.ganttConfig
, toRemove
, el
@ -229,7 +222,7 @@ function executeInPage(data) {
, width
, height
, confWidth = data.confWidth
toRemove = document.getElementsByClassName('mermaid')
if (toRemove && toRemove.length) {
for (var i = 0, len = toRemove.length; i < len; i++) {
@ -242,41 +235,24 @@ function executeInPage(data) {
elContent = document.createTextNode(contents)
el.appendChild(elContent)
//el.innerText = '<b>hello</b>\uD800' //contents;
document.body.appendChild(el)
mermaid.initialize({
sequenceDiagram:{useMaxWidth:false},
flowchart:{useMaxWidth:false},
logLevel:1
});
var config = {
sequenceDiagram: sequenceConfig,
flowchart: {useMaxWidth: false},
logLevel: 1
};
mermaid.initialize(config);
//console.log('after initialize',sequenceConfig);
if(typeof sequenceConfig !== undefined && sequenceConfig !== 'undefined'){
//sc = document.createElement("script")
//scContent = document.createTextNode('mermaid.sequenceConfig = JSON.parse(' + JSON.stringify(sequenceConfig) + ');')
//sc.appendChild(scContent)
sc = document.createElement("script")
scContent = document.createTextNode('mermaid.ganttConfig = ' + ganttConfig + ';')
sc.appendChild(scContent)
//document.body.appendChild(sc)
mermaid.initialize({
sequenceDiagram:JSON.parse(sequenceConfig)
});
}
//console.log('after initialize 2');
if(typeof ganttConfig !== undefined && ganttConfig !== 'undefined'){
sc = document.createElement("script")
scContent = document.createTextNode('mermaid.ganttConfig = JSON.parse(' + JSON.stringify(ganttConfig) + ');')
sc.appendChild(scContent)
document.body.appendChild(sc)
}else{
sc = document.createElement("script")
scContent = document.createTextNode('mermaid.ganttConfig = {useWidth:1200};')
sc.appendChild(scContent)
document.body.appendChild(sc)
}
document.body.appendChild(sc)
mermaid.init();

View File

@ -425,6 +425,25 @@ exports.draw = function (text, id,isDot) {
dagreD3.util.applyStyle(path, edge[type + 'Style']);
};
// Override normal arrowhead defined in d3. Remove style & add class to allow css styling.
render.arrows().normal = function normal(parent, id, edge, type) {
var marker = parent.append("marker")
.attr("id", id)
.attr("viewBox", "0 0 10 10")
.attr("refX", 9)
.attr("refY", 5)
.attr("markerUnits", "strokeWidth")
.attr("markerWidth", 8)
.attr("markerHeight", 6)
.attr("orient", "auto")
var path = marker.append("path")
.attr("d", "M 0 0 L 10 5 L 0 10 z")
.attr("class", "arrowheadPath")
.style("stroke-width", 1)
.style("stroke-dasharray", "1,0");
};
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select('#' + id);
//svgGroup = d3.select('#' + id + ' g');

View File

@ -9,6 +9,11 @@
stroke-width: 1px;
}
.arrowheadPath {
fill: @arrowheadColor;
}
.edgePath .path {
stroke: @lineColor;
}

View File

@ -5,6 +5,7 @@
@lineColor: @mainContrastColor;
@border1: #81B1DB;
@border2: rgba(255, 255, 255, 0.25);
@arrowheadColor: @mainContrastColor;
/* Flowchart variables */

View File

@ -9,6 +9,10 @@
stroke-width: 1px;
}
.arrowheadPath {
fill: @arrowheadColor;
}
.edgePath .path {
stroke: @lineColor;
}

View File

@ -3,6 +3,7 @@
@lineColor: #333333;
@border1:#CCCCFF;
@border2:#aaaa33;
@arrowheadColor: #333333;
/* Flowchart variables */
@nodeBkg:@mainBkg;

View File

@ -12,6 +12,10 @@ color:#333
stroke-width: 1px;
}
.arrowheadPath {
fill: @arrowheadColor;
}
.edgePath .path {
stroke: @lineColor;
stroke-width: 1.5px;

View File

@ -4,6 +4,7 @@
@lineColor: green;
@border1: #13540c;
@border2: #6eaa49;
@arrowheadColor: green;
/* Flowchart variables */
@nodeBkg:@mainBkg;

View File

@ -0,0 +1,69 @@
g.classGroup text {
fill: @nodeBorder;
stroke:none;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
}
g.classGroup rect {
fill:@nodeBkg;
stroke: @nodeBorder;
}
g.classGroup line {
stroke: @nodeBorder;
stroke-width:1;
}
svg .classLabel .box {
stroke: none;
stroke-width:0;
fill: @nodeBkg;
opacity: 0.5;
}
svg .classLabel .label {
fill: @nodeBorder;
}
.relation {
stroke: @nodeBorder;
stroke-width: 1;
fill:none;
}
.composition{
fill : @nodeBorder;
stroke: @nodeBorder;
stroke-width:1;
}
#compositionStart {
.composition;
}
#compositionEnd {
.composition;
}
.aggregation{
fill : @nodeBkg;
stroke: @nodeBorder;
stroke-width:1;
}
#aggregationStart {
.aggregation;
}
#aggregationEnd {
.aggregation;
}
#dependencyStart {
.composition;
}
#dependencyEnd {
.composition;
}
#extensionStart {
.composition;
}
#extensionEnd {
.composition;
}

View File

@ -0,0 +1,30 @@
.mermaid .label { color: @text }
.node rect,
.node circle,
.node ellipse,
.node polygon {
fill: @mainBkg;
stroke: @nodeBorder;
stroke-width: 1px;
}
.edgePath .path {
stroke: @lineColor;
stroke-width: 1.5px;
}
.edgeLabel {
background-color: @edgeLabelBackground;
}
.cluster rect {
fill: @secondBkg !important;
rx: 4 !important;
stroke: @clusterBorder !important;
stroke-width: 1px !important;
}
.cluster text {
fill: @titleColor;
}

135
src/less/neutral/gantt.less Normal file
View File

@ -0,0 +1,135 @@
/** Section styling */
.section {
stroke: none;
opacity:0.2;
}
.section0{
fill: @sectionBkgColor;
}
.section2 {
fill: @sectionBkgColor2;
}
.section1,.section3 {
fill: @altSectionBkgColor;
opacity: 0.2;
}
.sectionTitle0 { fill: @titleColor;}
.sectionTitle1 { fill: @titleColor;}
.sectionTitle2 { fill: @titleColor;}
.sectionTitle3 { fill: @titleColor;}
.sectionTitle {
text-anchor: start;
font-size: 11px;
text-height: 14px;
}
/* Grid and axis */
.grid .tick {
stroke: @gridColor;
opacity: 0.3;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
/* Today line */
.today {
fill: none;
stroke: @todayLineColor;
stroke-width: 2px;
}
/* Task styling */
/* Default task */
.task {
stroke-width: 2;
}
.taskText {
text-anchor: middle;
font-size: 11px;
}
.taskTextOutsideRight {
fill: @taskTextDarkColor;
text-anchor: start;
font-size: 11px;
}
.taskTextOutsideLeft {
fill: @taskTextDarkColor;
text-anchor: end;
font-size: 11px;
}
/* Specific task settings for the sections*/
.taskText0, .taskText1, .taskText2, .taskText3 {
fill: @taskTextColor;
}
.task0, .task1, .task2, .task3 {
fill: @taskBkgColor;
stroke: @taskBorderColor;
}
.taskTextOutside0,.taskTextOutside2, {
fill: @taskTextOutsideColor;
}
.taskTextOutside1, .taskTextOutside3 {
fill: @taskTextOutsideColor;
}
/* Active task */
.active0, .active1, .active2, .active3 {
fill: @activeTaskBkgColor;
stroke: @activeTaskBorderColor;
}
.activeText0, .activeText1, .activeText2, .activeText3 {
fill: @taskTextDarkColor !important;
}
/* Completed task */
.done0, .done1, .done2, .done3 {
stroke: @doneTaskBorderColor;
fill: @doneTaskBkgColor;
stroke-width: 2;
}
.doneText0, .doneText1, .doneText2, .doneText3 {
fill: @taskTextDarkColor !important;
}
/* Tasks on the critical line */
.crit0, .crit1, .crit2, .crit3 {
stroke:@critBorderColor;
fill: @critBkgColor;
stroke-width: 2;
}
.activeCrit0, .activeCrit1, .activeCrit2, .activeCrit3 {
stroke: @critBorderColor;
fill: @activeTaskBkgColor;
stroke-width: 2;
}
.doneCrit0, .doneCrit1, .doneCrit2, .doneCrit3 {
stroke: @critBorderColor;
fill: @doneTaskBkgColor;
stroke-width: 2;
cursor: pointer;
//shape-rendering: crispEdges;
}
.doneCritText0, .doneCritText1, .doneCritText2, .doneCritText3 {
fill: @taskTextDarkColor !important;
}
.activeCritText0, .activeCritText1, .activeCritText2, .activeCritText3 {
fill: @taskTextDarkColor !important;
}
.titleText {
text-anchor: middle;
font-size: 18px;
fill: @taskTextDarkColor;
}

View File

@ -0,0 +1,24 @@
@import "variables";
@import "flow";
@import "sequenceDiagram";
@import "gantt";
@import "classDiagram";
.node text {
font-family: Arial, Helvetica, sans-serif;
font-size:14px;
}
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
background: @secondBkg;
border: 1px solid @border2;
border-radius: 2px;
pointer-events: none;
z-index:100;
}

View File

@ -0,0 +1,75 @@
.actor {
stroke: @actorBorder;
fill: @actorBkg;
}
text.actor {
fill: @actorTextColor;
stroke: none;
}
.actor-line {
stroke: @actorLineColor;
}
.messageLine0 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: @signalColor;
}
.messageLine1 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
stroke: @signalColor;
}
#arrowhead {
fill: @signalColor;
}
#crosshead path {
fill: @signalColor !important;
stroke: @signalColor !important;
}
.messageText {
fill: @signalTextColor;
stroke: none;
}
.labelBox {
stroke: @labelBoxBorderColor;
fill: @labelBoxBkgColor;
}
.labelText {
fill: @labelTextColor;
stroke: none;
}
.loopText {
fill: @labelTextColor;
stroke: none;
}
.loopLine {
stroke-width: 2;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: @labelBoxBorderColor;
}
.note {
//stroke: #decc93;
stroke: @noteBorderColor;
fill: @noteBkgColor;
}
.noteText {
fill: black;
stroke: none;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
}

View File

@ -0,0 +1,66 @@
@mainBkg: #eee;
@secondBkg: lighten(@contrast, 55%);
@lineColor: #666;
@border1: #999;
@border2: @contrast;
@note: #ffa;
@text: #333;
@contrast: #26a;
@critical: #d42;
@done: #bbb;
/* Flowchart variables */
@nodeBkg: @mainBkg;
@nodeBorder: @border1;
@clusterBkg: @secondBkg;
@clusterBorder: @border2;
@defaultLinkColor: @lineColor;
@titleColor: @text;
@edgeLabelBackground: white;
/* Sequence Diagram variables */
@actorBorder: @border1;
@actorBkg: @mainBkg;
@actorTextColor: @text;
@actorLineColor: @lineColor;
@signalColor: @text;
@signalTextColor: @text;
@labelBoxBkgColor: @contrast;
@labelBoxBorderColor: @contrast;
@labelTextColor: white;
@noteBorderColor: darken(@note, 60%);
@noteBkgColor: @note;
/* Gantt chart variables */
@sectionBkgColor: lighten(@contrast, 30%);
@altSectionBkgColor: white;
@sectionBkgColor2: lighten(@contrast, 30%);
@taskBorderColor: darken(@contrast, 10%);
@taskBkgColor: @contrast;
@taskTextColor: @taskTextLightColor;
@taskTextOutsideColor: @taskTextDarkColor;
@activeTaskBorderColor: @taskBorderColor;
@activeTaskBkgColor: @mainBkg;
@gridColor: lighten(@border1, 30%);
@doneTaskBkgColor: @done;
@doneTaskBorderColor: @lineColor;
@critBorderColor: darken(@critBkgColor, 10%);
@critBkgColor: @critical;
@taskTextLightColor: white;
@taskTextDarkColor: @text;
@todayLineColor: @critBkgColor;

View File

@ -71,7 +71,7 @@ var config = {
startOnLoad: true,
/**
* **arrowMarkerAbsolute** - This options controls whether or arrow markers in html code will be absolute pats or
* **arrowMarkerAbsolute** - This options controls whether or arrow markers in html code will be absolute paths or
* an anchor, #. This matters if you are using base tag settings.
*/
arrowMarkerAbsolute: false,

View File

@ -24,12 +24,18 @@ var singleFile = {
, outputDir: path.join(process.cwd(),'test/tmp2/')
, phantomPath: path.join(process.cwd(),phantomCmd)
, width : 1200
, css: path.join(__dirname, '..', 'dist', 'mermaid.css')
, sequenceConfig: null
, ganttConfig: null
}
, multiFile = {
files: [path.join('test','fixtures','test.mermaid'), path.join('test','fixtures','test2.mermaid')]
, outputDir: 'test/tmp2/'
, phantomPath: path.join(process.cwd(),phantomCmd)
, width : 1200
, css: path.join(__dirname, '..', 'dist', 'mermaid.css')
, sequenceConfig: null
, ganttConfig: null
}
@ -40,7 +46,7 @@ test('output of single png', function(t) {
opt = clone(singleFile)
opt.png = true
mermaid.process(opt.files, opt, function(code) {
t.equal(code, 0, 'has clean exit code')
@ -113,7 +119,7 @@ test('output including CSS', function(t) {
one = fs.statSync(filename)
//console.log('one: '+opt.files[0]);
opt2.css = fs.readFileSync(path.join('test','fixtures','test.css'), 'utf8')
opt2.css = path.join('test','fixtures','test.css')
//console.log(opt2.css);
console.log('Generating #2');