diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20d6cbf30..842414531 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -So you whant to help? That's great! +So you want to help? That's great! ![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif) diff --git a/src/config.js b/src/config.js index 0b5df6e0c..6d73e7853 100644 --- a/src/config.js +++ b/src/config.js @@ -25,3 +25,12 @@ export const setConfig = conf => { setConf(conf); }; export const getConfig = () => config; + +const configApi = { + setConfig, + getConfig + // get conf() { + // return config; + // } +}; +export default configApi; diff --git a/src/diagrams/state/shapes.js b/src/diagrams/state/shapes.js index bed40cf47..8430e8a6a 100644 --- a/src/diagrams/state/shapes.js +++ b/src/diagrams/state/shapes.js @@ -2,14 +2,9 @@ import * as d3 from 'd3'; import idCache from './id-cache.js'; import stateDb from './stateDb'; import utils from '../../utils'; +import { getConfig, conf } from '../../config'; -// TODO Move conf object to main conf in mermaidAPI -const conf = { - dividerMargin: 10, - padding: 5, - textHeight: 10, - noteMargin: 10 -}; +// let conf; /** * Draws a start state as a black circle @@ -19,9 +14,9 @@ export const drawStartState = g => .append('circle') .style('stroke', 'black') .style('fill', 'black') - .attr('r', 5) - .attr('cx', conf.padding + 5) - .attr('cy', conf.padding + 5); + .attr('r', getConfig().state.sizeUnit) + .attr('cx', getConfig().state.padding + getConfig().state.sizeUnit) + .attr('cy', getConfig().state.padding + getConfig().state.sizeUnit); /** * Draws a start state as a black circle @@ -31,9 +26,9 @@ export const drawDivider = g => .append('line') .style('stroke', 'grey') .style('stroke-dasharray', '3') - .attr('x1', 10) + .attr('x1', getConfig().state.textHeight) .attr('class', 'divider') - .attr('x2', 20) + .attr('x2', getConfig().state.textHeight * 2) .attr('y1', 0) .attr('y2', 0); @@ -43,18 +38,18 @@ export const drawDivider = g => export const drawSimpleState = (g, stateDef) => { const state = g .append('text') - .attr('x', 2 * conf.padding) - .attr('y', conf.textHeight + 2 * conf.padding) - .attr('font-size', 24) + .attr('x', 2 * getConfig().state.padding) + .attr('y', getConfig().state.textHeight + 2 * getConfig().state.padding) + .attr('font-size', getConfig().state.fontSize) .text(stateDef.id); const classBox = state.node().getBBox(); g.insert('rect', ':first-child') - .attr('x', conf.padding) - .attr('y', conf.padding) - .attr('width', classBox.width + 2 * conf.padding) - .attr('height', classBox.height + 2 * conf.padding) - .attr('rx', '5'); + .attr('x', getConfig().state.padding) + .attr('y', getConfig().state.padding) + .attr('width', classBox.width + 2 * getConfig().state.padding) + .attr('height', classBox.height + 2 * getConfig().state.padding) + .attr('rx', getConfig().state.radius); return state; }; @@ -68,17 +63,17 @@ export const drawDescrState = (g, stateDef) => { const addTspan = function(textEl, txt, isFirst) { const tSpan = textEl .append('tspan') - .attr('x', 2 * conf.padding) + .attr('x', 2 * getConfig().state.padding) .text(txt); if (!isFirst) { - tSpan.attr('dy', conf.textHeight); + tSpan.attr('dy', getConfig().state.textHeight); } }; const title = g .append('text') - .attr('x', 2 * conf.padding) - .attr('y', conf.textHeight + 1.5 * conf.padding) - .attr('font-size', 24) + .attr('x', 2 * getConfig().state.padding) + .attr('y', getConfig().state.textHeight + 1.5 * getConfig().state.padding) + .attr('font-size', getConfig().state.fontSize) .attr('class', 'state-title') .text(stateDef.id); @@ -87,8 +82,14 @@ export const drawDescrState = (g, stateDef) => { const description = g .append('text') // text label for the x axis - .attr('x', conf.padding) - .attr('y', titleHeight + conf.padding * 0.2 + conf.dividerMargin + conf.textHeight) + .attr('x', getConfig().state.padding) + .attr( + 'y', + titleHeight + + getConfig().state.padding * 0.2 + + getConfig().state.dividerMargin + + getConfig().state.textHeight + ) .attr('fill', 'white') .attr('class', 'state-description'); @@ -100,23 +101,23 @@ export const drawDescrState = (g, stateDef) => { const descrLine = g .append('line') // text label for the x axis - .attr('x1', conf.padding) - .attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2) - .attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2) + .attr('x1', getConfig().state.padding) + .attr('y1', getConfig().state.padding + titleHeight + getConfig().state.dividerMargin / 2) + .attr('y2', getConfig().state.padding + titleHeight + getConfig().state.dividerMargin / 2) .attr('class', 'descr-divider'); const descrBox = description.node().getBBox(); console.warn(descrBox.width, titleBox.width); const width = Math.max(descrBox.width, titleBox.width); - descrLine.attr('x2', width + 3 * conf.padding); + descrLine.attr('x2', width + 3 * getConfig().state.padding); // const classBox = title.node().getBBox(); g.insert('rect', ':first-child') - .attr('x', conf.padding) - .attr('y', conf.padding) - .attr('width', width + 2 * conf.padding) - .attr('height', descrBox.height + titleHeight + 2 * conf.padding) - .attr('rx', '5'); + .attr('x', getConfig().state.padding) + .attr('y', getConfig().state.padding) + .attr('width', width + 2 * getConfig().state.padding) + .attr('height', descrBox.height + titleHeight + 2 * getConfig().state.padding) + .attr('rx', getConfig().state.radius); return g; }; @@ -130,23 +131,23 @@ export const addIdAndBox = (g, stateDef) => { const addTspan = function(textEl, txt, isFirst) { const tSpan = textEl .append('tspan') - .attr('x', 2 * conf.padding) + .attr('x', 2 * getConfig().state.padding) .text(txt); if (!isFirst) { - tSpan.attr('dy', conf.textHeight); + tSpan.attr('dy', getConfig().state.textHeight); } }; const title = g .append('text') - .attr('x', 2 * conf.padding) - .attr('y', -15) - .attr('font-size', 24) + .attr('x', 2 * getConfig().state.padding) + .attr('y', getConfig().state.titleShift) + .attr('font-size', getConfig().state.fontSize) .attr('class', 'state-title') .text(stateDef.id); const titleHeight = title.node().getBBox().height; - const lineY = -9; + const lineY = 1 - getConfig().state.textHeight; const descrLine = g .append('line') // text label for the x axis .attr('x1', 0) @@ -156,32 +157,42 @@ export const addIdAndBox = (g, stateDef) => { const graphBox = g.node().getBBox(); title.attr('x', graphBox.width / 2 - title.node().getBBox().width / 2); - descrLine.attr('x2', graphBox.width + conf.padding); + descrLine.attr('x2', graphBox.width + getConfig().state.padding); // White color g.insert('rect', ':first-child') .attr('x', graphBox.x) .attr('y', lineY) .attr('style', 'fill: white; border-bottom: 1px') - .attr('width', graphBox.width + conf.padding) - .attr('height', graphBox.height + 3 + conf.textHeight - 17) + .attr('width', graphBox.width + getConfig().state.padding) + .attr( + 'height', + graphBox.height + getConfig().state.textHeight + getConfig().state.titleShift + 1 + ) .attr('rx', '0'); // Title background g.insert('rect', ':first-child') .attr('x', graphBox.x) - .attr('y', -15 - conf.textHeight - conf.padding) - .attr('width', graphBox.width + conf.padding) - .attr('height', 30) - .attr('rx', '5'); + .attr( + 'y', + getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding + ) + .attr('width', graphBox.width + getConfig().state.padding) + // Just needs to be higher then the descr line, will be clipped by the white color box + .attr('height', getConfig().state.textHeight * 3) + .attr('rx', getConfig().state.radius); // Full background g.insert('rect', ':first-child') .attr('x', graphBox.x) - .attr('y', -15 - conf.textHeight - conf.padding) - .attr('width', graphBox.width + conf.padding) - .attr('height', graphBox.height + 3 + conf.textHeight + 10) - .attr('rx', '5'); + .attr( + 'y', + getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding + ) + .attr('width', graphBox.width + getConfig().state.padding) + .attr('height', graphBox.height + 3 + 2 * getConfig().state.textHeight) + .attr('rx', getConfig().state.radius); return g; }; @@ -190,21 +201,27 @@ const drawEndState = g => { g.append('circle') .style('stroke', 'black') .style('fill', 'white') - .attr('r', 7) - .attr('cx', conf.padding + 7) - .attr('cy', conf.padding + 7); + .attr('r', getConfig().state.sizeUnit + getConfig().state.miniPadding) + .attr( + 'cx', + getConfig().state.padding + getConfig().state.sizeUnit + getConfig().state.miniPadding + ) + .attr( + 'cy', + getConfig().state.padding + getConfig().state.sizeUnit + getConfig().state.miniPadding + ); return g .append('circle') .style('stroke', 'black') .style('fill', 'black') - .attr('r', 5) - .attr('cx', conf.padding + 7) - .attr('cy', conf.padding + 7); + .attr('r', getConfig().state.sizeUnit) + .attr('cx', getConfig().state.padding + getConfig().state.sizeUnit + 2) + .attr('cy', getConfig().state.padding + getConfig().state.sizeUnit + 2); }; const drawForkJoinState = (g, stateDef) => { - let width = 70; - let height = 7; + let width = getConfig().state.forkWidth; + let height = getConfig().state.forkHeight; if (stateDef.parentId) { let tmp = width; @@ -217,8 +234,8 @@ const drawForkJoinState = (g, stateDef) => { .style('fill', 'black') .attr('width', width) .attr('height', height) - .attr('x', conf.padding) - .attr('y', conf.padding); + .attr('x', getConfig().state.padding) + .attr('y', getConfig().state.padding); }; export const drawText = function(elem, textData, width) { @@ -260,8 +277,8 @@ const _drawLongText = (_text, x, y, g) => { span.text(txt); const textBounds = span.node().getBBox(); textHeight += textBounds.height; - span.attr('x', x + conf.noteMargin); - span.attr('y', y + textHeight + 1.25 * conf.noteMargin); + span.attr('x', x + getConfig().state.noteMargin); + span.attr('y', y + textHeight + 1.25 * getConfig().state.noteMargin); // textWidth = Math.max(textBounds.width, textWidth); } } @@ -280,12 +297,12 @@ export const drawNote = (text, g) => { const note = g .append('rect') .attr('x', 0) - .attr('y', conf.padding); + .attr('y', getConfig().state.padding); const rectElem = g.append('g'); const { textWidth, textHeight } = _drawLongText(text, 0, 0, rectElem); - note.attr('height', textHeight + 2 * conf.noteMargin); - note.attr('width', textWidth + conf.noteMargin * 2); + note.attr('height', textHeight + 2 * getConfig().state.noteMargin); + note.attr('width', textWidth + getConfig().state.noteMargin * 2); return note; }; @@ -322,8 +339,8 @@ export const drawState = function(elem, stateDef, graph, doc) { if (stateDef.type === 'default' && stateDef.descriptions.length > 0) drawDescrState(g, stateDef); const stateBox = g.node().getBBox(); - stateInfo.width = stateBox.width + 2 * conf.padding; - stateInfo.height = stateBox.height + 2 * conf.padding; + stateInfo.width = stateBox.width + 2 * getConfig().state.padding; + stateInfo.height = stateBox.height + 2 * getConfig().state.padding; idCache.set(id, stateInfo); // stateCnt++; @@ -367,7 +384,7 @@ export const drawEdge = function(elem, path, relation) { .attr('id', 'edge' + edgeCount) .attr('class', 'relation'); let url = ''; - if (conf.arrowMarkerAbsolute) { + if (getConfig().state.arrowMarkerAbsolute) { url = window.location.protocol + '//' + @@ -396,10 +413,10 @@ export const drawEdge = function(elem, path, relation) { const bounds = label.node().getBBox(); g.insert('rect', ':first-child') .attr('class', 'box') - .attr('x', bounds.x - conf.padding / 2) - .attr('y', bounds.y - conf.padding / 2) - .attr('width', bounds.width + conf.padding) - .attr('height', bounds.height + conf.padding); + .attr('x', bounds.x - getConfig().state.padding / 2) + .attr('y', bounds.y - getConfig().state.padding / 2) + .attr('width', bounds.width + getConfig().state.padding) + .attr('height', bounds.height + getConfig().state.padding); // Debug points // path.points.forEach(point => { // g.append('circle') diff --git a/src/diagrams/state/stateRenderer.js b/src/diagrams/state/stateRenderer.js index d1f91c237..445e4758e 100644 --- a/src/diagrams/state/stateRenderer.js +++ b/src/diagrams/state/stateRenderer.js @@ -7,17 +7,24 @@ import { parser } from './parser/stateDiagram'; import utils from '../../utils'; import idCache from './id-cache'; import { drawState, addIdAndBox, drawEdge, drawNote } from './shapes'; +import { getConfig } from '../../config'; parser.yy = stateDb; let total = 0; // TODO Move conf object to main conf in mermaidAPI -const conf = { - dividerMargin: 10, - padding: 5, - textHeight: 10 -}; +let conf; +// { +// // Used +// padding: 5, +// // Font size factor, this is used to guess the width of the edges labels before rendering by dagre +// // layout. This might need updating if/when switching font +// fontSizeFactor: 5.02, +// labelHeight: 16, +// edgeLengthFactor: '20', +// compositTitleSize: 35 +// }; const transformationLog = {}; @@ -59,9 +66,10 @@ const insertMarkers = function(elem) { * @param id */ export const draw = function(text, id) { + conf = getConfig().state; parser.yy.clear(); parser.parse(text); - logger.warn('Rendering diagram ' + text); + logger.debug('Rendering diagram ' + text); // /// / Fetch the default direction, use TD if none was found const diagram = d3.select(`[id='${id}']`); @@ -76,12 +84,6 @@ export const draw = function(text, id) { // ranksep: '20' }); - // // Set an object for the graph label - // graph.setGraph({ - // isMultiGraph: false, - // rankdir: 'RL' - // }); - // // Default to assigning a new object as a label for each new edge. graph.setDefaultEdgeLabel(function() { return {}; @@ -93,7 +95,6 @@ export const draw = function(text, id) { const bounds = diagram.node().getBBox(); diagram.attr('height', '100%'); - // diagram.attr('width', 'fit-content'); diagram.attr('style', `width: ${bounds.width * 3 + conf.padding * 2};`); diagram.attr( 'viewBox', @@ -104,7 +105,7 @@ export const draw = function(text, id) { ); }; const getLabelWidth = text => { - return text ? text.length * 5.02 : 1; + return text ? text.length * conf.fontSizeFactor : 1; }; const renderDoc = (doc, diagram, parentId) => { @@ -122,7 +123,7 @@ const renderDoc = (doc, diagram, parentId) => { // acyclicer: 'greedy', rankdir: 'LR', ranker: 'tight-tree', - ranksep: '20' + ranksep: conf.edgeLengthFactor // isMultiGraph: false }); else { @@ -132,7 +133,7 @@ const renderDoc = (doc, diagram, parentId) => { // isCompound: true, // acyclicer: 'greedy', // ranker: 'longest-path' - ranksep: '20', + ranksep: conf.edgeLengthFactor, ranker: 'tight-tree' // ranker: 'network-simplex' // isMultiGraph: false @@ -173,14 +174,14 @@ const renderDoc = (doc, diagram, parentId) => { sub = addIdAndBox(sub, stateDef); let boxBounds = sub.node().getBBox(); node.width = boxBounds.width; - node.height = boxBounds.height + 10; - transformationLog[stateDef.id] = { y: 35 }; + node.height = boxBounds.height + 2 * conf.padding; + transformationLog[stateDef.id] = { y: conf.compositTitleSize }; } else { // sub = addIdAndBox(sub, stateDef); let boxBounds = sub.node().getBBox(); node.width = boxBounds.width; node.height = boxBounds.height; - // transformationLog[stateDef.id] = { y: 35 }; + // transformationLog[stateDef.id] = { y: conf.compositTitleSize }; } } else { node = drawState(diagram, stateDef, graph); @@ -220,7 +221,7 @@ const renderDoc = (doc, diagram, parentId) => { graph.setEdge(relation.id1, relation.id2, { relation: relation, width: getLabelWidth(relation.title), - height: 16, + height: conf.labelHeight, labelpos: 'c' }); }); diff --git a/src/mermaidAPI.js b/src/mermaidAPI.js index 9fa0901a4..40dc7fb8e 100644 --- a/src/mermaidAPI.js +++ b/src/mermaidAPI.js @@ -302,7 +302,28 @@ const config = { axisFormat: '%Y-%m-%d' }, class: {}, - git: {} + git: {}, + state: { + dividerMargin: 10, + sizeUnit: 5, + padding: 5, + textHeight: 10, + titleShift: -15, + noteMargin: 10, + forkWidth: 70, + forkHeight: 7, + // Used + padding: 5, + miniPadding: 2, + // Font size factor, this is used to guess the width of the edges labels before rendering by dagre + // layout. This might need updating if/when switching font + fontSizeFactor: 5.02, + fontSize: 24, + labelHeight: 16, + edgeLengthFactor: '20', + compositTitleSize: 35, + radius: 5 + } }; setLogLevel(config.logLevel);