mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
#931 Aligning with code standard
This commit is contained in:
parent
cf05a8d8fa
commit
34de31195f
@ -1,33 +1,33 @@
|
|||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3';
|
||||||
import { sanitizeUrl } from '@braintree/sanitize-url'
|
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||||
import { logger } from '../../logger'
|
import { logger } from '../../logger';
|
||||||
import utils from '../../utils'
|
import utils from '../../utils';
|
||||||
import { getConfig } from '../../config'
|
import { getConfig } from '../../config';
|
||||||
|
|
||||||
const config = getConfig()
|
const config = getConfig();
|
||||||
let vertices = {}
|
let vertices = {};
|
||||||
let edges = []
|
let edges = [];
|
||||||
let classes = []
|
let classes = [];
|
||||||
let subGraphs = []
|
let subGraphs = [];
|
||||||
let subGraphLookup = {}
|
let subGraphLookup = {};
|
||||||
let tooltips = {}
|
let tooltips = {};
|
||||||
let subCount = 0
|
let subCount = 0;
|
||||||
let direction
|
let direction;
|
||||||
// Functions to be run after graph rendering
|
// Functions to be run after graph rendering
|
||||||
let funs = []
|
let funs = [];
|
||||||
|
|
||||||
const sanitize = text => {
|
const sanitize = text => {
|
||||||
let txt = text
|
let txt = text;
|
||||||
if (config.securityLevel !== 'loose') {
|
if (config.securityLevel !== 'loose') {
|
||||||
txt = txt.replace(/<br>/g, '#br#')
|
txt = txt.replace(/<br>/g, '#br#');
|
||||||
txt = txt.replace(/<br\S*?\/>/g, '#br#')
|
txt = txt.replace(/<br\S*?\/>/g, '#br#');
|
||||||
txt = txt.replace(/</g, '<').replace(/>/g, '>')
|
txt = txt.replace(/</g, '<').replace(/>/g, '>');
|
||||||
txt = txt.replace(/=/g, '=')
|
txt = txt.replace(/=/g, '=');
|
||||||
txt = txt.replace(/#br#/g, '<br/>')
|
txt = txt.replace(/#br#/g, '<br/>');
|
||||||
}
|
}
|
||||||
|
|
||||||
return txt
|
return txt;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called by parser when a node definition has been found
|
* Function called by parser when a node definition has been found
|
||||||
@ -37,53 +37,53 @@ const sanitize = text => {
|
|||||||
* @param style
|
* @param style
|
||||||
* @param classes
|
* @param classes
|
||||||
*/
|
*/
|
||||||
export const addVertex = function (_id, text, type, style, classes) {
|
export const addVertex = function(_id, text, type, style, classes) {
|
||||||
let txt
|
let txt;
|
||||||
let id = _id
|
let id = _id;
|
||||||
if (typeof id === 'undefined') {
|
if (typeof id === 'undefined') {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (id.trim().length === 0) {
|
if (id.trim().length === 0) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id[0].match(/\d/)) id = 's' + id
|
if (id[0].match(/\d/)) id = 's' + id;
|
||||||
|
|
||||||
if (typeof vertices[id] === 'undefined') {
|
if (typeof vertices[id] === 'undefined') {
|
||||||
vertices[id] = { id: id, styles: [], classes: [] }
|
vertices[id] = { id: id, styles: [], classes: [] };
|
||||||
}
|
}
|
||||||
if (typeof text !== 'undefined') {
|
if (typeof text !== 'undefined') {
|
||||||
txt = sanitize(text.trim())
|
txt = sanitize(text.trim());
|
||||||
|
|
||||||
// strip quotes if string starts and exnds with a quote
|
// strip quotes if string starts and exnds with a quote
|
||||||
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
|
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
|
||||||
txt = txt.substring(1, txt.length - 1)
|
txt = txt.substring(1, txt.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertices[id].text = txt
|
vertices[id].text = txt;
|
||||||
} else {
|
} else {
|
||||||
if (!vertices[id].text) {
|
if (!vertices[id].text) {
|
||||||
vertices[id].text = _id
|
vertices[id].text = _id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof type !== 'undefined') {
|
if (typeof type !== 'undefined') {
|
||||||
vertices[id].type = type
|
vertices[id].type = type;
|
||||||
}
|
}
|
||||||
if (typeof style !== 'undefined') {
|
if (typeof style !== 'undefined') {
|
||||||
if (style !== null) {
|
if (style !== null) {
|
||||||
style.forEach(function (s) {
|
style.forEach(function(s) {
|
||||||
vertices[id].styles.push(s)
|
vertices[id].styles.push(s);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof classes !== 'undefined') {
|
if (typeof classes !== 'undefined') {
|
||||||
if (classes !== null) {
|
if (classes !== null) {
|
||||||
classes.forEach(function (s) {
|
classes.forEach(function(s) {
|
||||||
vertices[id].classes.push(s)
|
vertices[id].classes.push(s);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called by parser when a link/edge definition has been found
|
* Function called by parser when a link/edge definition has been found
|
||||||
@ -92,134 +92,138 @@ export const addVertex = function (_id, text, type, style, classes) {
|
|||||||
* @param type
|
* @param type
|
||||||
* @param linktext
|
* @param linktext
|
||||||
*/
|
*/
|
||||||
export const addLink = function (_start, _end, type, linktext) {
|
export const addLink = function(_start, _end, type, linktext) {
|
||||||
let start = _start
|
let start = _start;
|
||||||
let end = _end
|
let end = _end;
|
||||||
if (start[0].match(/\d/)) start = 's' + start
|
if (start[0].match(/\d/)) start = 's' + start;
|
||||||
if (end[0].match(/\d/)) end = 's' + end
|
if (end[0].match(/\d/)) end = 's' + end;
|
||||||
logger.info('Got edge...', start, end)
|
logger.info('Got edge...', start, end);
|
||||||
|
|
||||||
const edge = { start: start, end: end, type: undefined, text: '' }
|
const edge = { start: start, end: end, type: undefined, text: '' };
|
||||||
linktext = type.text
|
linktext = type.text;
|
||||||
|
|
||||||
if (typeof linktext !== 'undefined') {
|
if (typeof linktext !== 'undefined') {
|
||||||
edge.text = sanitize(linktext.trim())
|
edge.text = sanitize(linktext.trim());
|
||||||
|
|
||||||
// strip quotes if string starts and exnds with a quote
|
// strip quotes if string starts and exnds with a quote
|
||||||
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
|
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
|
||||||
edge.text = edge.text.substring(1, edge.text.length - 1)
|
edge.text = edge.text.substring(1, edge.text.length - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof type !== 'undefined') {
|
if (typeof type !== 'undefined') {
|
||||||
edge.type = type.type
|
edge.type = type.type;
|
||||||
edge.stroke = type.stroke
|
edge.stroke = type.stroke;
|
||||||
}
|
}
|
||||||
edges.push(edge)
|
edges.push(edge);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a link's line interpolation algorithm
|
* Updates a link's line interpolation algorithm
|
||||||
* @param pos
|
* @param pos
|
||||||
* @param interpolate
|
* @param interpolate
|
||||||
*/
|
*/
|
||||||
export const updateLinkInterpolate = function (positions, interp) {
|
export const updateLinkInterpolate = function(positions, interp) {
|
||||||
positions.forEach(function (pos) {
|
positions.forEach(function(pos) {
|
||||||
if (pos === 'default') {
|
if (pos === 'default') {
|
||||||
edges.defaultInterpolate = interp
|
edges.defaultInterpolate = interp;
|
||||||
} else {
|
} else {
|
||||||
edges[pos].interpolate = interp
|
edges[pos].interpolate = interp;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a link with a style
|
* Updates a link with a style
|
||||||
* @param pos
|
* @param pos
|
||||||
* @param style
|
* @param style
|
||||||
*/
|
*/
|
||||||
export const updateLink = function (positions, style) {
|
export const updateLink = function(positions, style) {
|
||||||
positions.forEach(function (pos) {
|
positions.forEach(function(pos) {
|
||||||
if (pos === 'default') {
|
if (pos === 'default') {
|
||||||
edges.defaultStyle = style
|
edges.defaultStyle = style;
|
||||||
} else {
|
} else {
|
||||||
if (utils.isSubstringInArray('fill', style) === -1) {
|
if (utils.isSubstringInArray('fill', style) === -1) {
|
||||||
style.push('fill:none')
|
style.push('fill:none');
|
||||||
}
|
}
|
||||||
edges[pos].style = style
|
edges[pos].style = style;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export const addClass = function (id, style) {
|
export const addClass = function(id, style) {
|
||||||
if (typeof classes[id] === 'undefined') {
|
if (typeof classes[id] === 'undefined') {
|
||||||
classes[id] = { id: id, styles: [] }
|
classes[id] = { id: id, styles: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof style !== 'undefined') {
|
if (typeof style !== 'undefined') {
|
||||||
if (style !== null) {
|
if (style !== null) {
|
||||||
style.forEach(function (s) {
|
style.forEach(function(s) {
|
||||||
classes[id].styles.push(s)
|
classes[id].styles.push(s);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by parser when a graph definition is found, stores the direction of the chart.
|
* Called by parser when a graph definition is found, stores the direction of the chart.
|
||||||
* @param dir
|
* @param dir
|
||||||
*/
|
*/
|
||||||
export const setDirection = function (dir) {
|
export const setDirection = function(dir) {
|
||||||
direction = dir
|
direction = dir;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by parser when a special node is found, e.g. a clickable element.
|
* Called by parser when a special node is found, e.g. a clickable element.
|
||||||
* @param ids Comma separated list of ids
|
* @param ids Comma separated list of ids
|
||||||
* @param className Class to add
|
* @param className Class to add
|
||||||
*/
|
*/
|
||||||
export const setClass = function (ids, className) {
|
export const setClass = function(ids, className) {
|
||||||
ids.split(',').forEach(function (_id) {
|
ids.split(',').forEach(function(_id) {
|
||||||
let id = _id
|
let id = _id;
|
||||||
if (_id[0].match(/\d/)) id = 's' + id
|
if (_id[0].match(/\d/)) id = 's' + id;
|
||||||
if (typeof vertices[id] !== 'undefined') {
|
if (typeof vertices[id] !== 'undefined') {
|
||||||
vertices[id].classes.push(className)
|
vertices[id].classes.push(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof subGraphLookup[id] !== 'undefined') {
|
if (typeof subGraphLookup[id] !== 'undefined') {
|
||||||
subGraphLookup[id].classes.push(className)
|
subGraphLookup[id].classes.push(className);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const setTooltip = function (ids, tooltip) {
|
const setTooltip = function(ids, tooltip) {
|
||||||
ids.split(',').forEach(function (id) {
|
ids.split(',').forEach(function(id) {
|
||||||
if (typeof tooltip !== 'undefined') {
|
if (typeof tooltip !== 'undefined') {
|
||||||
tooltips[id] = sanitize(tooltip)
|
tooltips[id] = sanitize(tooltip);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const setClickFun = function (_id, functionName) {
|
const setClickFun = function(_id, functionName) {
|
||||||
let id = _id
|
let id = _id;
|
||||||
if (_id[0].match(/\d/)) id = 's' + id
|
if (_id[0].match(/\d/)) id = 's' + id;
|
||||||
if (config.securityLevel !== 'loose') {
|
if (config.securityLevel !== 'loose') {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (typeof functionName === 'undefined') {
|
if (typeof functionName === 'undefined') {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (typeof vertices[id] !== 'undefined') {
|
if (typeof vertices[id] !== 'undefined') {
|
||||||
funs.push(function (element) {
|
funs.push(function(element) {
|
||||||
const elem = document.querySelector(`[id="${id}"]`)
|
const elem = document.querySelector(`[id="${id}"]`);
|
||||||
if (elem !== null) {
|
if (elem !== null) {
|
||||||
elem.addEventListener('click', function () {
|
elem.addEventListener(
|
||||||
window[functionName](id)
|
'click',
|
||||||
}, false)
|
function() {
|
||||||
|
window[functionName](id);
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by parser when a link is found. Adds the URL to the vertex data.
|
* Called by parser when a link is found. Adds the URL to the vertex data.
|
||||||
@ -227,24 +231,24 @@ const setClickFun = function (_id, functionName) {
|
|||||||
* @param linkStr URL to create a link for
|
* @param linkStr URL to create a link for
|
||||||
* @param tooltip Tooltip for the clickable element
|
* @param tooltip Tooltip for the clickable element
|
||||||
*/
|
*/
|
||||||
export const setLink = function (ids, linkStr, tooltip) {
|
export const setLink = function(ids, linkStr, tooltip) {
|
||||||
ids.split(',').forEach(function (_id) {
|
ids.split(',').forEach(function(_id) {
|
||||||
let id = _id
|
let id = _id;
|
||||||
if (_id[0].match(/\d/)) id = 's' + id
|
if (_id[0].match(/\d/)) id = 's' + id;
|
||||||
if (typeof vertices[id] !== 'undefined') {
|
if (typeof vertices[id] !== 'undefined') {
|
||||||
if (config.securityLevel !== 'loose') {
|
if (config.securityLevel !== 'loose') {
|
||||||
vertices[id].link = sanitizeUrl(linkStr) // .replace(/javascript:.*/g, '')
|
vertices[id].link = sanitizeUrl(linkStr); // .replace(/javascript:.*/g, '')
|
||||||
} else {
|
} else {
|
||||||
vertices[id].link = linkStr
|
vertices[id].link = linkStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
setTooltip(ids, tooltip)
|
setTooltip(ids, tooltip);
|
||||||
setClass(ids, 'clickable')
|
setClass(ids, 'clickable');
|
||||||
}
|
};
|
||||||
export const getTooltip = function (id) {
|
export const getTooltip = function(id) {
|
||||||
return tooltips[id]
|
return tooltips[id];
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by parser when a click definition is found. Registers an event handler.
|
* Called by parser when a click definition is found. Registers an event handler.
|
||||||
@ -252,209 +256,219 @@ export const getTooltip = function (id) {
|
|||||||
* @param functionName Function to be called on click
|
* @param functionName Function to be called on click
|
||||||
* @param tooltip Tooltip for the clickable element
|
* @param tooltip Tooltip for the clickable element
|
||||||
*/
|
*/
|
||||||
export const setClickEvent = function (ids, functionName, tooltip) {
|
export const setClickEvent = function(ids, functionName, tooltip) {
|
||||||
ids.split(',').forEach(function (id) { setClickFun(id, functionName) })
|
ids.split(',').forEach(function(id) {
|
||||||
setTooltip(ids, tooltip)
|
setClickFun(id, functionName);
|
||||||
setClass(ids, 'clickable')
|
});
|
||||||
}
|
setTooltip(ids, tooltip);
|
||||||
|
setClass(ids, 'clickable');
|
||||||
|
};
|
||||||
|
|
||||||
export const bindFunctions = function (element) {
|
export const bindFunctions = function(element) {
|
||||||
funs.forEach(function (fun) {
|
funs.forEach(function(fun) {
|
||||||
fun(element)
|
fun(element);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
export const getDirection = function () {
|
export const getDirection = function() {
|
||||||
return direction
|
return direction;
|
||||||
}
|
};
|
||||||
/**
|
/**
|
||||||
* Retrieval function for fetching the found nodes after parsing has completed.
|
* Retrieval function for fetching the found nodes after parsing has completed.
|
||||||
* @returns {{}|*|vertices}
|
* @returns {{}|*|vertices}
|
||||||
*/
|
*/
|
||||||
export const getVertices = function () {
|
export const getVertices = function() {
|
||||||
return vertices
|
return vertices;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieval function for fetching the found links after parsing has completed.
|
* Retrieval function for fetching the found links after parsing has completed.
|
||||||
* @returns {{}|*|edges}
|
* @returns {{}|*|edges}
|
||||||
*/
|
*/
|
||||||
export const getEdges = function () {
|
export const getEdges = function() {
|
||||||
return edges
|
return edges;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieval function for fetching the found class definitions after parsing has completed.
|
* Retrieval function for fetching the found class definitions after parsing has completed.
|
||||||
* @returns {{}|*|classes}
|
* @returns {{}|*|classes}
|
||||||
*/
|
*/
|
||||||
export const getClasses = function () {
|
export const getClasses = function() {
|
||||||
return classes
|
return classes;
|
||||||
}
|
};
|
||||||
|
|
||||||
const setupToolTips = function (element) {
|
const setupToolTips = function(element) {
|
||||||
let tooltipElem = d3.select('.mermaidTooltip')
|
let tooltipElem = d3.select('.mermaidTooltip');
|
||||||
if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
|
if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
|
||||||
tooltipElem = d3.select('body')
|
tooltipElem = d3
|
||||||
|
.select('body')
|
||||||
.append('div')
|
.append('div')
|
||||||
.attr('class', 'mermaidTooltip')
|
.attr('class', 'mermaidTooltip')
|
||||||
.style('opacity', 0)
|
.style('opacity', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const svg = d3.select(element).select('svg')
|
const svg = d3.select(element).select('svg');
|
||||||
|
|
||||||
const nodes = svg.selectAll('g.node')
|
const nodes = svg.selectAll('g.node');
|
||||||
nodes
|
nodes
|
||||||
.on('mouseover', function () {
|
.on('mouseover', function() {
|
||||||
const el = d3.select(this)
|
const el = d3.select(this);
|
||||||
const title = el.attr('title')
|
const title = el.attr('title');
|
||||||
// Dont try to draw a tooltip if no data is provided
|
// Dont try to draw a tooltip if no data is provided
|
||||||
if (title === null) {
|
if (title === null) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const rect = this.getBoundingClientRect()
|
const rect = this.getBoundingClientRect();
|
||||||
|
|
||||||
tooltipElem.transition()
|
tooltipElem
|
||||||
|
.transition()
|
||||||
.duration(200)
|
.duration(200)
|
||||||
.style('opacity', '.9')
|
.style('opacity', '.9');
|
||||||
tooltipElem.html(el.attr('title'))
|
tooltipElem
|
||||||
.style('left', (rect.left + (rect.right - rect.left) / 2) + 'px')
|
.html(el.attr('title'))
|
||||||
.style('top', (rect.top - 14 + document.body.scrollTop) + 'px')
|
.style('left', rect.left + (rect.right - rect.left) / 2 + 'px')
|
||||||
el.classed('hover', true)
|
.style('top', rect.top - 14 + document.body.scrollTop + 'px');
|
||||||
|
el.classed('hover', true);
|
||||||
})
|
})
|
||||||
.on('mouseout', function () {
|
.on('mouseout', function() {
|
||||||
tooltipElem.transition()
|
tooltipElem
|
||||||
|
.transition()
|
||||||
.duration(500)
|
.duration(500)
|
||||||
.style('opacity', 0)
|
.style('opacity', 0);
|
||||||
const el = d3.select(this)
|
const el = d3.select(this);
|
||||||
el.classed('hover', false)
|
el.classed('hover', false);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
funs.push(setupToolTips)
|
funs.push(setupToolTips);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the internal graph db so that a new graph can be parsed.
|
* Clears the internal graph db so that a new graph can be parsed.
|
||||||
*/
|
*/
|
||||||
export const clear = function () {
|
export const clear = function() {
|
||||||
vertices = {}
|
vertices = {};
|
||||||
classes = {}
|
classes = {};
|
||||||
edges = []
|
edges = [];
|
||||||
funs = []
|
funs = [];
|
||||||
funs.push(setupToolTips)
|
funs.push(setupToolTips);
|
||||||
subGraphs = []
|
subGraphs = [];
|
||||||
subGraphLookup = {}
|
subGraphLookup = {};
|
||||||
subCount = 0
|
subCount = 0;
|
||||||
tooltips = []
|
tooltips = [];
|
||||||
}
|
};
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export const defaultStyle = function () {
|
export const defaultStyle = function() {
|
||||||
return 'fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;'
|
return 'fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;';
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the internal graph db so that a new graph can be parsed.
|
* Clears the internal graph db so that a new graph can be parsed.
|
||||||
*/
|
*/
|
||||||
export const addSubGraph = function (_id, list, _title) {
|
export const addSubGraph = function(_id, list, _title) {
|
||||||
let id = _id
|
let id = _id;
|
||||||
let title = _title
|
let title = _title;
|
||||||
if (_id === _title && _title.match(/\s/)) {
|
if (_id === _title && _title.match(/\s/)) {
|
||||||
id = undefined
|
id = undefined;
|
||||||
}
|
}
|
||||||
function uniq (a) {
|
function uniq(a) {
|
||||||
const prims = { 'boolean': {}, 'number': {}, 'string': {} }
|
const prims = { boolean: {}, number: {}, string: {} };
|
||||||
const objs = []
|
const objs = [];
|
||||||
|
|
||||||
return a.filter(function (item) {
|
return a.filter(function(item) {
|
||||||
const type = typeof item
|
const type = typeof item;
|
||||||
if (item.trim() === '') {
|
if (item.trim() === '') {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
if (type in prims) { return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true) } else { return objs.indexOf(item) >= 0 ? false : objs.push(item) }
|
if (type in prims) {
|
||||||
})
|
return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
|
||||||
|
} else {
|
||||||
|
return objs.indexOf(item) >= 0 ? false : objs.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let nodeList = []
|
let nodeList = [];
|
||||||
|
|
||||||
nodeList = uniq(nodeList.concat.apply(nodeList, list))
|
nodeList = uniq(nodeList.concat.apply(nodeList, list));
|
||||||
for (let i = 0; i < nodeList.length; i++) {
|
for (let i = 0; i < nodeList.length; i++) {
|
||||||
if (nodeList[i][0].match(/\d/)) nodeList[i] = 's' + nodeList[i]
|
if (nodeList[i][0].match(/\d/)) nodeList[i] = 's' + nodeList[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
id = id || ('subGraph' + subCount)
|
id = id || 'subGraph' + subCount;
|
||||||
if (id[0].match(/\d/)) id = 's' + id
|
if (id[0].match(/\d/)) id = 's' + id;
|
||||||
title = title || ''
|
title = title || '';
|
||||||
title = sanitize(title)
|
title = sanitize(title);
|
||||||
subCount = subCount + 1
|
subCount = subCount + 1;
|
||||||
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] }
|
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] };
|
||||||
subGraphs.push(subGraph)
|
subGraphs.push(subGraph);
|
||||||
subGraphLookup[id] = subGraph
|
subGraphLookup[id] = subGraph;
|
||||||
return id
|
return id;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getPosForId = function (id) {
|
const getPosForId = function(id) {
|
||||||
for (let i = 0; i < subGraphs.length; i++) {
|
for (let i = 0; i < subGraphs.length; i++) {
|
||||||
if (subGraphs[i].id === id) {
|
if (subGraphs[i].id === id) {
|
||||||
return i
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
};
|
||||||
let secCount = -1
|
let secCount = -1;
|
||||||
const posCrossRef = []
|
const posCrossRef = [];
|
||||||
const indexNodes2 = function (id, pos) {
|
const indexNodes2 = function(id, pos) {
|
||||||
const nodes = subGraphs[pos].nodes
|
const nodes = subGraphs[pos].nodes;
|
||||||
secCount = secCount + 1
|
secCount = secCount + 1;
|
||||||
if (secCount > 2000) {
|
if (secCount > 2000) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
posCrossRef[secCount] = pos
|
posCrossRef[secCount] = pos;
|
||||||
// Check if match
|
// Check if match
|
||||||
if (subGraphs[pos].id === id) {
|
if (subGraphs[pos].id === id) {
|
||||||
return {
|
return {
|
||||||
result: true,
|
result: true,
|
||||||
count: 0
|
count: 0
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = 0
|
let count = 0;
|
||||||
let posCount = 1
|
let posCount = 1;
|
||||||
while (count < nodes.length) {
|
while (count < nodes.length) {
|
||||||
const childPos = getPosForId(nodes[count])
|
const childPos = getPosForId(nodes[count]);
|
||||||
// Ignore regular nodes (pos will be -1)
|
// Ignore regular nodes (pos will be -1)
|
||||||
if (childPos >= 0) {
|
if (childPos >= 0) {
|
||||||
const res = indexNodes2(id, childPos)
|
const res = indexNodes2(id, childPos);
|
||||||
if (res.result) {
|
if (res.result) {
|
||||||
return {
|
return {
|
||||||
result: true,
|
result: true,
|
||||||
count: posCount + res.count
|
count: posCount + res.count
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
posCount = posCount + res.count
|
posCount = posCount + res.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count = count + 1
|
count = count + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: false,
|
result: false,
|
||||||
count: posCount
|
count: posCount
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getDepthFirstPos = function (pos) {
|
export const getDepthFirstPos = function(pos) {
|
||||||
return posCrossRef[pos]
|
return posCrossRef[pos];
|
||||||
}
|
};
|
||||||
export const indexNodes = function () {
|
export const indexNodes = function() {
|
||||||
secCount = -1
|
secCount = -1;
|
||||||
if (subGraphs.length > 0) {
|
if (subGraphs.length > 0) {
|
||||||
indexNodes2('none', subGraphs.length - 1, 0)
|
indexNodes2('none', subGraphs.length - 1, 0);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getSubGraphs = function () {
|
export const getSubGraphs = function() {
|
||||||
return subGraphs
|
return subGraphs;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
addVertex,
|
addVertex,
|
||||||
@ -478,4 +492,4 @@ export default {
|
|||||||
getDepthFirstPos,
|
getDepthFirstPos,
|
||||||
indexNodes,
|
indexNodes,
|
||||||
getSubGraphs
|
getSubGraphs
|
||||||
}
|
};
|
||||||
|
@ -1,274 +1,288 @@
|
|||||||
import graphlib from 'graphlibrary'
|
import graphlib from 'graphlibrary';
|
||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3';
|
||||||
|
|
||||||
import flowDb from './flowDb'
|
import flowDb from './flowDb';
|
||||||
import flow from './parser/flow'
|
import flow from './parser/flow';
|
||||||
import { getConfig } from '../../config'
|
import { getConfig } from '../../config';
|
||||||
import dagreD3 from 'dagre-d3-renderer'
|
import dagreD3 from 'dagre-d3-renderer';
|
||||||
import addHtmlLabel from 'dagre-d3-renderer/lib/label/add-html-label.js'
|
import addHtmlLabel from 'dagre-d3-renderer/lib/label/add-html-label.js';
|
||||||
import { logger } from '../../logger'
|
import { logger } from '../../logger';
|
||||||
import { interpolateToCurve } from '../../utils'
|
import { interpolateToCurve } from '../../utils';
|
||||||
|
|
||||||
const conf = {
|
const conf = {};
|
||||||
}
|
export const setConf = function(cnf) {
|
||||||
export const setConf = function (cnf) {
|
const keys = Object.keys(cnf);
|
||||||
const keys = Object.keys(cnf)
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
conf[keys[i]] = cnf[keys[i]]
|
conf[keys[i]] = cnf[keys[i]];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that adds the vertices found in the graph definition to the graph to be rendered.
|
* Function that adds the vertices found in the graph definition to the graph to be rendered.
|
||||||
* @param vert Object containing the vertices.
|
* @param vert Object containing the vertices.
|
||||||
* @param g The graph that is to be drawn.
|
* @param g The graph that is to be drawn.
|
||||||
*/
|
*/
|
||||||
export const addVertices = function (vert, g, svgId) {
|
export const addVertices = function(vert, g, svgId) {
|
||||||
const svg = d3.select(`[id="${svgId}"]`)
|
const svg = d3.select(`[id="${svgId}"]`);
|
||||||
const keys = Object.keys(vert)
|
const keys = Object.keys(vert);
|
||||||
|
|
||||||
const styleFromStyleArr = function (styleStr, arr, { label }) {
|
const styleFromStyleArr = function(styleStr, arr, { label }) {
|
||||||
if (!label) {
|
if (!label) {
|
||||||
// Create a compound style definition from the style definitions found for the node in the graph definition
|
// Create a compound style definition from the style definitions found for the node in the graph definition
|
||||||
for (let i = 0; i < arr.length; i++) {
|
for (let i = 0; i < arr.length; i++) {
|
||||||
if (typeof arr[i] !== 'undefined') {
|
if (typeof arr[i] !== 'undefined') {
|
||||||
styleStr = styleStr + arr[i] + ';'
|
styleStr = styleStr + arr[i] + ';';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < arr.length; i++) {
|
for (let i = 0; i < arr.length; i++) {
|
||||||
if (typeof arr[i] !== 'undefined') {
|
if (typeof arr[i] !== 'undefined') {
|
||||||
if (arr[i].match('^color:')) styleStr = styleStr + arr[i] + ';'
|
if (arr[i].match('^color:')) styleStr = styleStr + arr[i] + ';';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return styleStr
|
return styleStr;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||||
keys.forEach(function (id) {
|
keys.forEach(function(id) {
|
||||||
const vertex = vert[id]
|
const vertex = vert[id];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable for storing the classes for the vertex
|
* Variable for storing the classes for the vertex
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
let classStr = ''
|
let classStr = '';
|
||||||
if (vertex.classes.length > 0) {
|
if (vertex.classes.length > 0) {
|
||||||
classStr = vertex.classes.join(' ')
|
classStr = vertex.classes.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable for storing the extracted style for the vertex
|
* Variable for storing the extracted style for the vertex
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
let style = ''
|
let style = '';
|
||||||
// Create a compound style definition from the style definitions found for the node in the graph definition
|
// Create a compound style definition from the style definitions found for the node in the graph definition
|
||||||
style = styleFromStyleArr(style, vertex.styles, { label: false })
|
style = styleFromStyleArr(style, vertex.styles, { label: false });
|
||||||
let labelStyle = ''
|
let labelStyle = '';
|
||||||
labelStyle = styleFromStyleArr(labelStyle, vertex.styles, { label: true })
|
labelStyle = styleFromStyleArr(labelStyle, vertex.styles, { label: true });
|
||||||
|
|
||||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||||
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id
|
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
|
||||||
|
|
||||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||||
let vertexNode
|
let vertexNode;
|
||||||
if (getConfig().flowchart.htmlLabels) {
|
if (getConfig().flowchart.htmlLabels) {
|
||||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||||
const node = { label: vertexText.replace(/fa[lrsb]?:fa-[\w-]+/g, s => `<i class='${s.replace(':', ' ')}'></i>`) }
|
const node = {
|
||||||
vertexNode = addHtmlLabel(svg, node).node()
|
label: vertexText.replace(
|
||||||
vertexNode.parentNode.removeChild(vertexNode)
|
/fa[lrsb]?:fa-[\w-]+/g,
|
||||||
|
s => `<i class='${s.replace(':', ' ')}'></i>`
|
||||||
|
)
|
||||||
|
};
|
||||||
|
vertexNode = addHtmlLabel(svg, node).node();
|
||||||
|
vertexNode.parentNode.removeChild(vertexNode);
|
||||||
} else {
|
} else {
|
||||||
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text')
|
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||||
|
|
||||||
const rows = vertexText.split(/<br[/]{0,1}>/)
|
const rows = vertexText.split(/<br[/]{0,1}>/);
|
||||||
|
|
||||||
for (let j = 0; j < rows.length; j++) {
|
for (let j = 0; j < rows.length; j++) {
|
||||||
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan')
|
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve')
|
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||||
tspan.setAttribute('dy', '1em')
|
tspan.setAttribute('dy', '1em');
|
||||||
tspan.setAttribute('x', '1')
|
tspan.setAttribute('x', '1');
|
||||||
tspan.textContent = rows[j]
|
tspan.textContent = rows[j];
|
||||||
svgLabel.appendChild(tspan)
|
svgLabel.appendChild(tspan);
|
||||||
}
|
}
|
||||||
vertexNode = svgLabel
|
vertexNode = svgLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the node has a link, we wrap it in a SVG link
|
// If the node has a link, we wrap it in a SVG link
|
||||||
if (vertex.link) {
|
if (vertex.link) {
|
||||||
const link = document.createElementNS('http://www.w3.org/2000/svg', 'a')
|
const link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link)
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener')
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
|
||||||
link.appendChild(vertexNode)
|
link.appendChild(vertexNode);
|
||||||
vertexNode = link
|
vertexNode = link;
|
||||||
}
|
}
|
||||||
|
|
||||||
let radious = 0
|
let radious = 0;
|
||||||
let _shape = ''
|
let _shape = '';
|
||||||
// Set the shape based parameters
|
// Set the shape based parameters
|
||||||
switch (vertex.type) {
|
switch (vertex.type) {
|
||||||
case 'round':
|
case 'round':
|
||||||
radious = 5
|
radious = 5;
|
||||||
_shape = 'rect'
|
_shape = 'rect';
|
||||||
break
|
break;
|
||||||
case 'square':
|
case 'square':
|
||||||
_shape = 'rect'
|
_shape = 'rect';
|
||||||
break
|
break;
|
||||||
case 'diamond':
|
case 'diamond':
|
||||||
_shape = 'question'
|
_shape = 'question';
|
||||||
break
|
break;
|
||||||
case 'odd':
|
case 'odd':
|
||||||
_shape = 'rect_left_inv_arrow'
|
_shape = 'rect_left_inv_arrow';
|
||||||
break
|
break;
|
||||||
case 'lean_right':
|
case 'lean_right':
|
||||||
_shape = 'lean_right'
|
_shape = 'lean_right';
|
||||||
break
|
break;
|
||||||
case 'lean_left':
|
case 'lean_left':
|
||||||
_shape = 'lean_left'
|
_shape = 'lean_left';
|
||||||
break
|
break;
|
||||||
case 'trapezoid':
|
case 'trapezoid':
|
||||||
_shape = 'trapezoid'
|
_shape = 'trapezoid';
|
||||||
break
|
break;
|
||||||
case 'inv_trapezoid':
|
case 'inv_trapezoid':
|
||||||
_shape = 'inv_trapezoid'
|
_shape = 'inv_trapezoid';
|
||||||
break
|
break;
|
||||||
case 'odd_right':
|
case 'odd_right':
|
||||||
_shape = 'rect_left_inv_arrow'
|
_shape = 'rect_left_inv_arrow';
|
||||||
break
|
break;
|
||||||
case 'circle':
|
case 'circle':
|
||||||
_shape = 'circle'
|
_shape = 'circle';
|
||||||
break
|
break;
|
||||||
case 'ellipse':
|
case 'ellipse':
|
||||||
_shape = 'ellipse'
|
_shape = 'ellipse';
|
||||||
break
|
break;
|
||||||
case 'group':
|
case 'group':
|
||||||
_shape = 'rect'
|
_shape = 'rect';
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
_shape = 'rect'
|
_shape = 'rect';
|
||||||
}
|
}
|
||||||
// Add the node
|
// Add the node
|
||||||
g.setNode(vertex.id, { labelType: 'svg', labelStyle: labelStyle, shape: _shape, label: vertexNode, rx: radious, ry: radious, 'class': classStr, style: style, id: vertex.id })
|
g.setNode(vertex.id, {
|
||||||
})
|
labelType: 'svg',
|
||||||
}
|
labelStyle: labelStyle,
|
||||||
|
shape: _shape,
|
||||||
|
label: vertexNode,
|
||||||
|
rx: radious,
|
||||||
|
ry: radious,
|
||||||
|
class: classStr,
|
||||||
|
style: style,
|
||||||
|
id: vertex.id
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add edges to graph based on parsed graph defninition
|
* Add edges to graph based on parsed graph defninition
|
||||||
* @param {Object} edges The edges to add to the graph
|
* @param {Object} edges The edges to add to the graph
|
||||||
* @param {Object} g The graph object
|
* @param {Object} g The graph object
|
||||||
*/
|
*/
|
||||||
export const addEdges = function (edges, g) {
|
export const addEdges = function(edges, g) {
|
||||||
let cnt = 0
|
let cnt = 0;
|
||||||
|
|
||||||
let defaultStyle
|
let defaultStyle;
|
||||||
if (typeof edges.defaultStyle !== 'undefined') {
|
if (typeof edges.defaultStyle !== 'undefined') {
|
||||||
defaultStyle = edges.defaultStyle.toString().replace(/,/g, ';')
|
defaultStyle = edges.defaultStyle.toString().replace(/,/g, ';');
|
||||||
}
|
}
|
||||||
|
|
||||||
edges.forEach(function (edge) {
|
edges.forEach(function(edge) {
|
||||||
cnt++
|
cnt++;
|
||||||
const edgeData = {}
|
const edgeData = {};
|
||||||
|
|
||||||
// Set link type for rendering
|
// Set link type for rendering
|
||||||
if (edge.type === 'arrow_open') {
|
if (edge.type === 'arrow_open') {
|
||||||
edgeData.arrowhead = 'none'
|
edgeData.arrowhead = 'none';
|
||||||
} else {
|
} else {
|
||||||
edgeData.arrowhead = 'normal'
|
edgeData.arrowhead = 'normal';
|
||||||
}
|
}
|
||||||
|
|
||||||
let style = ''
|
let style = '';
|
||||||
if (typeof edge.style !== 'undefined') {
|
if (typeof edge.style !== 'undefined') {
|
||||||
edge.style.forEach(function (s) {
|
edge.style.forEach(function(s) {
|
||||||
style = style + s + ';'
|
style = style + s + ';';
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
switch (edge.stroke) {
|
switch (edge.stroke) {
|
||||||
case 'normal':
|
case 'normal':
|
||||||
style = 'fill:none'
|
style = 'fill:none';
|
||||||
if (typeof defaultStyle !== 'undefined') {
|
if (typeof defaultStyle !== 'undefined') {
|
||||||
style = defaultStyle
|
style = defaultStyle;
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
case 'dotted':
|
case 'dotted':
|
||||||
style = 'stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;'
|
style = 'stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;';
|
||||||
break
|
break;
|
||||||
case 'thick':
|
case 'thick':
|
||||||
style = 'stroke: #333; stroke-width: 3.5px;fill:none'
|
style = 'stroke: #333; stroke-width: 3.5px;fill:none';
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
edgeData.style = style
|
edgeData.style = style;
|
||||||
|
|
||||||
if (typeof edge.interpolate !== 'undefined') {
|
if (typeof edge.interpolate !== 'undefined') {
|
||||||
edgeData.curve = interpolateToCurve(edge.interpolate, d3.curveLinear)
|
edgeData.curve = interpolateToCurve(edge.interpolate, d3.curveLinear);
|
||||||
} else if (typeof edges.defaultInterpolate !== 'undefined') {
|
} else if (typeof edges.defaultInterpolate !== 'undefined') {
|
||||||
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, d3.curveLinear)
|
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, d3.curveLinear);
|
||||||
} else {
|
} else {
|
||||||
edgeData.curve = interpolateToCurve(conf.curve, d3.curveLinear)
|
edgeData.curve = interpolateToCurve(conf.curve, d3.curveLinear);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof edge.text === 'undefined') {
|
if (typeof edge.text === 'undefined') {
|
||||||
if (typeof edge.style !== 'undefined') {
|
if (typeof edge.style !== 'undefined') {
|
||||||
edgeData.arrowheadStyle = 'fill: #333'
|
edgeData.arrowheadStyle = 'fill: #333';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
edgeData.arrowheadStyle = 'fill: #333'
|
edgeData.arrowheadStyle = 'fill: #333';
|
||||||
if (typeof edge.style === 'undefined') {
|
if (typeof edge.style === 'undefined') {
|
||||||
edgeData.labelpos = 'c'
|
edgeData.labelpos = 'c';
|
||||||
if (getConfig().flowchart.htmlLabels) {
|
if (getConfig().flowchart.htmlLabels) {
|
||||||
edgeData.labelType = 'html'
|
edgeData.labelType = 'html';
|
||||||
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>'
|
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
|
||||||
} else {
|
} else {
|
||||||
edgeData.labelType = 'text'
|
edgeData.labelType = 'text';
|
||||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none'
|
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
|
||||||
edgeData.label = edge.text.replace(/<br>/g, '\n')
|
edgeData.label = edge.text.replace(/<br>/g, '\n');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
edgeData.label = edge.text.replace(/<br>/g, '\n')
|
edgeData.label = edge.text.replace(/<br>/g, '\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add the edge to the graph
|
// Add the edge to the graph
|
||||||
g.setEdge(edge.start, edge.end, edgeData, cnt)
|
g.setEdge(edge.start, edge.end, edgeData, cnt);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the all the styles from classDef statements in the graph definition.
|
* Returns the all the styles from classDef statements in the graph definition.
|
||||||
* @returns {object} classDef styles
|
* @returns {object} classDef styles
|
||||||
*/
|
*/
|
||||||
export const getClasses = function (text) {
|
export const getClasses = function(text) {
|
||||||
logger.info('Extracting classes')
|
logger.info('Extracting classes');
|
||||||
flowDb.clear()
|
flowDb.clear();
|
||||||
const parser = flow.parser
|
const parser = flow.parser;
|
||||||
parser.yy = flowDb
|
parser.yy = flowDb;
|
||||||
|
|
||||||
// Parse the graph definition
|
// Parse the graph definition
|
||||||
parser.parse(text)
|
parser.parse(text);
|
||||||
return flowDb.getClasses()
|
return flowDb.getClasses();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
||||||
* @param text
|
* @param text
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
export const draw = function (text, id) {
|
export const draw = function(text, id) {
|
||||||
logger.info('Drawing flowchart')
|
logger.info('Drawing flowchart');
|
||||||
flowDb.clear()
|
flowDb.clear();
|
||||||
const parser = flow.parser
|
const parser = flow.parser;
|
||||||
parser.yy = flowDb
|
parser.yy = flowDb;
|
||||||
|
|
||||||
// Parse the graph definition
|
// Parse the graph definition
|
||||||
try {
|
try {
|
||||||
parser.parse(text)
|
parser.parse(text);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.debug('Parsing failed')
|
logger.debug('Parsing failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the default direction, use TD if none was found
|
// Fetch the default direction, use TD if none was found
|
||||||
let dir = flowDb.getDirection()
|
let dir = flowDb.getDirection();
|
||||||
if (typeof dir === 'undefined') {
|
if (typeof dir === 'undefined') {
|
||||||
dir = 'TD'
|
dir = 'TD';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the input mermaid.graph
|
// Create the input mermaid.graph
|
||||||
@ -280,196 +294,238 @@ export const draw = function (text, id) {
|
|||||||
rankdir: dir,
|
rankdir: dir,
|
||||||
marginx: 20,
|
marginx: 20,
|
||||||
marginy: 20
|
marginy: 20
|
||||||
|
|
||||||
})
|
|
||||||
.setDefaultEdgeLabel(function () {
|
|
||||||
return {}
|
|
||||||
})
|
})
|
||||||
|
.setDefaultEdgeLabel(function() {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
let subG
|
let subG;
|
||||||
const subGraphs = flowDb.getSubGraphs()
|
const subGraphs = flowDb.getSubGraphs();
|
||||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||||
subG = subGraphs[i]
|
subG = subGraphs[i];
|
||||||
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes)
|
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the verices/nodes and edges/links from the parsed graph definition
|
// Fetch the verices/nodes and edges/links from the parsed graph definition
|
||||||
const vert = flowDb.getVertices()
|
const vert = flowDb.getVertices();
|
||||||
|
|
||||||
const edges = flowDb.getEdges()
|
const edges = flowDb.getEdges();
|
||||||
|
|
||||||
let i = 0
|
let i = 0;
|
||||||
for (i = subGraphs.length - 1; i >= 0; i--) {
|
for (i = subGraphs.length - 1; i >= 0; i--) {
|
||||||
subG = subGraphs[i]
|
subG = subGraphs[i];
|
||||||
|
|
||||||
d3.selectAll('cluster').append('text')
|
d3.selectAll('cluster').append('text');
|
||||||
|
|
||||||
for (let j = 0; j < subG.nodes.length; j++) {
|
for (let j = 0; j < subG.nodes.length; j++) {
|
||||||
g.setParent(subG.nodes[j], subG.id)
|
g.setParent(subG.nodes[j], subG.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addVertices(vert, g, id)
|
addVertices(vert, g, id);
|
||||||
addEdges(edges, g)
|
addEdges(edges, g);
|
||||||
|
|
||||||
// Create the renderer
|
// Create the renderer
|
||||||
const Render = dagreD3.render
|
const Render = dagreD3.render;
|
||||||
const render = new Render()
|
const render = new Render();
|
||||||
|
|
||||||
// Add custom shape for rhombus type of boc (decision)
|
// Add custom shape for rhombus type of boc (decision)
|
||||||
render.shapes().question = function (parent, bbox, node) {
|
render.shapes().question = function(parent, bbox, node) {
|
||||||
const w = bbox.width
|
const w = bbox.width;
|
||||||
const h = bbox.height
|
const h = bbox.height;
|
||||||
const s = (w + h) * 0.9
|
const s = (w + h) * 0.9;
|
||||||
const points = [
|
const points = [
|
||||||
{ x: s / 2, y: 0 },
|
{ x: s / 2, y: 0 },
|
||||||
{ x: s, y: -s / 2 },
|
{ x: s, y: -s / 2 },
|
||||||
{ x: s / 2, y: -s },
|
{ x: s / 2, y: -s },
|
||||||
{ x: 0, y: -s / 2 }
|
{ x: 0, y: -s / 2 }
|
||||||
]
|
];
|
||||||
const shapeSvg = parent.insert('polygon', ':first-child')
|
const shapeSvg = parent
|
||||||
.attr('points', points.map(function (d) {
|
.insert('polygon', ':first-child')
|
||||||
return d.x + ',' + d.y
|
.attr(
|
||||||
}).join(' '))
|
'points',
|
||||||
|
points
|
||||||
|
.map(function(d) {
|
||||||
|
return d.x + ',' + d.y;
|
||||||
|
})
|
||||||
|
.join(' ')
|
||||||
|
)
|
||||||
.attr('rx', 5)
|
.attr('rx', 5)
|
||||||
.attr('ry', 5)
|
.attr('ry', 5)
|
||||||
.attr('transform', 'translate(' + (-s / 2) + ',' + (s * 2 / 4) + ')')
|
.attr('transform', 'translate(' + -s / 2 + ',' + (s * 2) / 4 + ')');
|
||||||
node.intersect = function (point) {
|
node.intersect = function(point) {
|
||||||
return dagreD3.intersect.polygon(node, points, point)
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
}
|
};
|
||||||
return shapeSvg
|
return shapeSvg;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
// Add custom shape for box with inverted arrow on left side
|
||||||
render.shapes().rect_left_inv_arrow = function (parent, bbox, node) {
|
render.shapes().rect_left_inv_arrow = function(parent, bbox, node) {
|
||||||
const w = bbox.width
|
const w = bbox.width;
|
||||||
const h = bbox.height
|
const h = bbox.height;
|
||||||
const points = [
|
const points = [
|
||||||
{ x: -h / 2, y: 0 },
|
{ x: -h / 2, y: 0 },
|
||||||
{ x: w, y: 0 },
|
{ x: w, y: 0 },
|
||||||
{ x: w, y: -h },
|
{ x: w, y: -h },
|
||||||
{ x: -h / 2, y: -h },
|
{ x: -h / 2, y: -h },
|
||||||
{ x: 0, y: -h / 2 }
|
{ x: 0, y: -h / 2 }
|
||||||
]
|
];
|
||||||
const shapeSvg = parent.insert('polygon', ':first-child')
|
const shapeSvg = parent
|
||||||
.attr('points', points.map(function (d) {
|
.insert('polygon', ':first-child')
|
||||||
return d.x + ',' + d.y
|
.attr(
|
||||||
}).join(' '))
|
'points',
|
||||||
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
|
points
|
||||||
node.intersect = function (point) {
|
.map(function(d) {
|
||||||
return dagreD3.intersect.polygon(node, points, point)
|
return d.x + ',' + d.y;
|
||||||
}
|
})
|
||||||
return shapeSvg
|
.join(' ')
|
||||||
}
|
)
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')');
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
// Add custom shape for box with inverted arrow on left side
|
||||||
render.shapes().lean_right = function (parent, bbox, node) {
|
render.shapes().lean_right = function(parent, bbox, node) {
|
||||||
const w = bbox.width
|
const w = bbox.width;
|
||||||
const h = bbox.height
|
const h = bbox.height;
|
||||||
const points = [
|
const points = [
|
||||||
{ x: -2 * h / 6, y: 0 },
|
{ x: (-2 * h) / 6, y: 0 },
|
||||||
{ x: w - h / 6, y: 0 },
|
{ x: w - h / 6, y: 0 },
|
||||||
{ x: w + 2 * h / 6, y: -h },
|
{ x: w + (2 * h) / 6, y: -h },
|
||||||
{ x: h / 6, y: -h }
|
{ x: h / 6, y: -h }
|
||||||
]
|
];
|
||||||
const shapeSvg = parent.insert('polygon', ':first-child')
|
const shapeSvg = parent
|
||||||
.attr('points', points.map(function (d) {
|
.insert('polygon', ':first-child')
|
||||||
return d.x + ',' + d.y
|
.attr(
|
||||||
}).join(' '))
|
'points',
|
||||||
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
|
points
|
||||||
node.intersect = function (point) {
|
.map(function(d) {
|
||||||
return dagreD3.intersect.polygon(node, points, point)
|
return d.x + ',' + d.y;
|
||||||
}
|
})
|
||||||
return shapeSvg
|
.join(' ')
|
||||||
}
|
)
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')');
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
// Add custom shape for box with inverted arrow on left side
|
||||||
render.shapes().lean_left = function (parent, bbox, node) {
|
render.shapes().lean_left = function(parent, bbox, node) {
|
||||||
const w = bbox.width
|
const w = bbox.width;
|
||||||
const h = bbox.height
|
const h = bbox.height;
|
||||||
const points = [
|
const points = [
|
||||||
{ x: 2 * h / 6, y: 0 },
|
{ x: (2 * h) / 6, y: 0 },
|
||||||
{ x: w + h / 6, y: 0 },
|
{ x: w + h / 6, y: 0 },
|
||||||
{ x: w - 2 * h / 6, y: -h },
|
{ x: w - (2 * h) / 6, y: -h },
|
||||||
{ x: -h / 6, y: -h }
|
{ x: -h / 6, y: -h }
|
||||||
]
|
];
|
||||||
const shapeSvg = parent.insert('polygon', ':first-child')
|
const shapeSvg = parent
|
||||||
.attr('points', points.map(function (d) {
|
.insert('polygon', ':first-child')
|
||||||
return d.x + ',' + d.y
|
.attr(
|
||||||
}).join(' '))
|
'points',
|
||||||
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
|
points
|
||||||
node.intersect = function (point) {
|
.map(function(d) {
|
||||||
return dagreD3.intersect.polygon(node, points, point)
|
return d.x + ',' + d.y;
|
||||||
}
|
})
|
||||||
return shapeSvg
|
.join(' ')
|
||||||
}
|
)
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')');
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
// Add custom shape for box with inverted arrow on left side
|
||||||
render.shapes().trapezoid = function (parent, bbox, node) {
|
render.shapes().trapezoid = function(parent, bbox, node) {
|
||||||
const w = bbox.width
|
const w = bbox.width;
|
||||||
const h = bbox.height
|
const h = bbox.height;
|
||||||
const points = [
|
const points = [
|
||||||
{ x: -2 * h / 6, y: 0 },
|
{ x: (-2 * h) / 6, y: 0 },
|
||||||
{ x: w + 2 * h / 6, y: 0 },
|
{ x: w + (2 * h) / 6, y: 0 },
|
||||||
{ x: w - h / 6, y: -h },
|
{ x: w - h / 6, y: -h },
|
||||||
{ x: h / 6, y: -h }
|
{ x: h / 6, y: -h }
|
||||||
]
|
];
|
||||||
const shapeSvg = parent.insert('polygon', ':first-child')
|
const shapeSvg = parent
|
||||||
.attr('points', points.map(function (d) {
|
.insert('polygon', ':first-child')
|
||||||
return d.x + ',' + d.y
|
.attr(
|
||||||
}).join(' '))
|
'points',
|
||||||
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
|
points
|
||||||
node.intersect = function (point) {
|
.map(function(d) {
|
||||||
return dagreD3.intersect.polygon(node, points, point)
|
return d.x + ',' + d.y;
|
||||||
}
|
})
|
||||||
return shapeSvg
|
.join(' ')
|
||||||
}
|
)
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')');
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
// Add custom shape for box with inverted arrow on left side
|
||||||
render.shapes().inv_trapezoid = function (parent, bbox, node) {
|
render.shapes().inv_trapezoid = function(parent, bbox, node) {
|
||||||
const w = bbox.width
|
const w = bbox.width;
|
||||||
const h = bbox.height
|
const h = bbox.height;
|
||||||
const points = [
|
const points = [
|
||||||
{ x: h / 6, y: 0 },
|
{ x: h / 6, y: 0 },
|
||||||
{ x: w - h / 6, y: 0 },
|
{ x: w - h / 6, y: 0 },
|
||||||
{ x: w + 2 * h / 6, y: -h },
|
{ x: w + (2 * h) / 6, y: -h },
|
||||||
{ x: -2 * h / 6, y: -h }
|
{ x: (-2 * h) / 6, y: -h }
|
||||||
]
|
];
|
||||||
const shapeSvg = parent.insert('polygon', ':first-child')
|
const shapeSvg = parent
|
||||||
.attr('points', points.map(function (d) {
|
.insert('polygon', ':first-child')
|
||||||
return d.x + ',' + d.y
|
.attr(
|
||||||
}).join(' '))
|
'points',
|
||||||
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
|
points
|
||||||
node.intersect = function (point) {
|
.map(function(d) {
|
||||||
return dagreD3.intersect.polygon(node, points, point)
|
return d.x + ',' + d.y;
|
||||||
}
|
})
|
||||||
return shapeSvg
|
.join(' ')
|
||||||
}
|
)
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')');
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on right side
|
// Add custom shape for box with inverted arrow on right side
|
||||||
render.shapes().rect_right_inv_arrow = function (parent, bbox, node) {
|
render.shapes().rect_right_inv_arrow = function(parent, bbox, node) {
|
||||||
const w = bbox.width
|
const w = bbox.width;
|
||||||
const h = bbox.height
|
const h = bbox.height;
|
||||||
const points = [
|
const points = [
|
||||||
{ x: 0, y: 0 },
|
{ x: 0, y: 0 },
|
||||||
{ x: w + h / 2, y: 0 },
|
{ x: w + h / 2, y: 0 },
|
||||||
{ x: w, y: -h / 2 },
|
{ x: w, y: -h / 2 },
|
||||||
{ x: w + h / 2, y: -h },
|
{ x: w + h / 2, y: -h },
|
||||||
{ x: 0, y: -h }
|
{ x: 0, y: -h }
|
||||||
]
|
];
|
||||||
const shapeSvg = parent.insert('polygon', ':first-child')
|
const shapeSvg = parent
|
||||||
.attr('points', points.map(function (d) {
|
.insert('polygon', ':first-child')
|
||||||
return d.x + ',' + d.y
|
.attr(
|
||||||
}).join(' '))
|
'points',
|
||||||
.attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')')
|
points
|
||||||
node.intersect = function (point) {
|
.map(function(d) {
|
||||||
return dagreD3.intersect.polygon(node, points, point)
|
return d.x + ',' + d.y;
|
||||||
}
|
})
|
||||||
return shapeSvg
|
.join(' ')
|
||||||
}
|
)
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')');
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
// Add our custom arrow - an empty arrowhead
|
// Add our custom arrow - an empty arrowhead
|
||||||
render.arrows().none = function normal (parent, id, edge, type) {
|
render.arrows().none = function normal(parent, id, edge, type) {
|
||||||
const marker = parent.append('marker')
|
const marker = parent
|
||||||
|
.append('marker')
|
||||||
.attr('id', id)
|
.attr('id', id)
|
||||||
.attr('viewBox', '0 0 10 10')
|
.attr('viewBox', '0 0 10 10')
|
||||||
.attr('refX', 9)
|
.attr('refX', 9)
|
||||||
@ -477,16 +533,16 @@ export const draw = function (text, id) {
|
|||||||
.attr('markerUnits', 'strokeWidth')
|
.attr('markerUnits', 'strokeWidth')
|
||||||
.attr('markerWidth', 8)
|
.attr('markerWidth', 8)
|
||||||
.attr('markerHeight', 6)
|
.attr('markerHeight', 6)
|
||||||
.attr('orient', 'auto')
|
.attr('orient', 'auto');
|
||||||
|
|
||||||
const path = marker.append('path')
|
const path = marker.append('path').attr('d', 'M 0 0 L 0 0 L 0 0 z');
|
||||||
.attr('d', 'M 0 0 L 0 0 L 0 0 z')
|
dagreD3.util.applyStyle(path, edge[type + 'Style']);
|
||||||
dagreD3.util.applyStyle(path, edge[type + 'Style'])
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Override normal arrowhead defined in d3. Remove style & add class to allow css styling.
|
// Override normal arrowhead defined in d3. Remove style & add class to allow css styling.
|
||||||
render.arrows().normal = function normal (parent, id, edge, type) {
|
render.arrows().normal = function normal(parent, id, edge, type) {
|
||||||
const marker = parent.append('marker')
|
const marker = parent
|
||||||
|
.append('marker')
|
||||||
.attr('id', id)
|
.attr('id', id)
|
||||||
.attr('viewBox', '0 0 10 10')
|
.attr('viewBox', '0 0 10 10')
|
||||||
.attr('refX', 9)
|
.attr('refX', 9)
|
||||||
@ -494,76 +550,76 @@ export const draw = function (text, id) {
|
|||||||
.attr('markerUnits', 'strokeWidth')
|
.attr('markerUnits', 'strokeWidth')
|
||||||
.attr('markerWidth', 8)
|
.attr('markerWidth', 8)
|
||||||
.attr('markerHeight', 6)
|
.attr('markerHeight', 6)
|
||||||
.attr('orient', 'auto')
|
.attr('orient', 'auto');
|
||||||
|
|
||||||
marker.append('path')
|
marker
|
||||||
|
.append('path')
|
||||||
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
|
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
|
||||||
.attr('class', 'arrowheadPath')
|
.attr('class', 'arrowheadPath')
|
||||||
.style('stroke-width', 1)
|
.style('stroke-width', 1)
|
||||||
.style('stroke-dasharray', '1,0')
|
.style('stroke-dasharray', '1,0');
|
||||||
}
|
};
|
||||||
|
|
||||||
// Set up an SVG group so that we can translate the final graph.
|
// Set up an SVG group so that we can translate the final graph.
|
||||||
const svg = d3.select(`[id="${id}"]`)
|
const svg = d3.select(`[id="${id}"]`);
|
||||||
|
|
||||||
// Run the renderer. This is what draws the final graph.
|
// Run the renderer. This is what draws the final graph.
|
||||||
const element = d3.select('#' + id + ' g')
|
const element = d3.select('#' + id + ' g');
|
||||||
render(element, g)
|
render(element, g);
|
||||||
|
|
||||||
element.selectAll('g.node')
|
element.selectAll('g.node').attr('title', function() {
|
||||||
.attr('title', function () {
|
return flowDb.getTooltip(this.id);
|
||||||
return flowDb.getTooltip(this.id)
|
});
|
||||||
})
|
|
||||||
|
|
||||||
const padding = 8
|
const padding = 8;
|
||||||
const width = g.maxX - g.minX + padding * 2
|
const width = g.maxX - g.minX + padding * 2;
|
||||||
const height = g.maxY - g.minY + padding * 2
|
const height = g.maxY - g.minY + padding * 2;
|
||||||
svg.attr('width', '100%')
|
svg.attr('width', '100%');
|
||||||
svg.attr('style', `max-width: ${width}px;`)
|
svg.attr('style', `max-width: ${width}px;`);
|
||||||
svg.attr('viewBox', `0 0 ${width} ${height}`)
|
svg.attr('viewBox', `0 0 ${width} ${height}`);
|
||||||
svg.select('g').attr('transform', `translate(${padding - g.minX}, ${padding - g.minY})`)
|
svg.select('g').attr('transform', `translate(${padding - g.minX}, ${padding - g.minY})`);
|
||||||
|
|
||||||
// Index nodes
|
// Index nodes
|
||||||
flowDb.indexNodes('subGraph' + i)
|
flowDb.indexNodes('subGraph' + i);
|
||||||
|
|
||||||
// reposition labels
|
// reposition labels
|
||||||
for (i = 0; i < subGraphs.length; i++) {
|
for (i = 0; i < subGraphs.length; i++) {
|
||||||
subG = subGraphs[i]
|
subG = subGraphs[i];
|
||||||
|
|
||||||
if (subG.title !== 'undefined') {
|
if (subG.title !== 'undefined') {
|
||||||
const clusterRects = document.querySelectorAll('#' + id + ' #' + subG.id + ' rect')
|
const clusterRects = document.querySelectorAll('#' + id + ' #' + subG.id + ' rect');
|
||||||
const clusterEl = document.querySelectorAll('#' + id + ' #' + subG.id)
|
const clusterEl = document.querySelectorAll('#' + id + ' #' + subG.id);
|
||||||
|
|
||||||
const xPos = clusterRects[0].x.baseVal.value
|
const xPos = clusterRects[0].x.baseVal.value;
|
||||||
const yPos = clusterRects[0].y.baseVal.value
|
const yPos = clusterRects[0].y.baseVal.value;
|
||||||
const width = clusterRects[0].width.baseVal.value
|
const width = clusterRects[0].width.baseVal.value;
|
||||||
const cluster = d3.select(clusterEl[0])
|
const cluster = d3.select(clusterEl[0]);
|
||||||
const te = cluster.select('.label')
|
const te = cluster.select('.label');
|
||||||
te.attr('transform', `translate(${xPos + width / 2}, ${yPos + 14})`)
|
te.attr('transform', `translate(${xPos + width / 2}, ${yPos + 14})`);
|
||||||
te.attr('id', id + 'Text')
|
te.attr('id', id + 'Text');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add label rects for non html labels
|
// Add label rects for non html labels
|
||||||
if (!getConfig().flowchart.htmlLabels) {
|
if (!getConfig().flowchart.htmlLabels) {
|
||||||
const labels = document.querySelectorAll('#' + id + ' .edgeLabel .label')
|
const labels = document.querySelectorAll('#' + id + ' .edgeLabel .label');
|
||||||
for (let k = 0; k < labels.length; k++) {
|
for (let k = 0; k < labels.length; k++) {
|
||||||
const label = labels[k]
|
const label = labels[k];
|
||||||
|
|
||||||
// Get dimensions of label
|
// Get dimensions of label
|
||||||
const dim = label.getBBox()
|
const dim = label.getBBox();
|
||||||
|
|
||||||
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
|
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||||
rect.setAttribute('rx', 0)
|
rect.setAttribute('rx', 0);
|
||||||
rect.setAttribute('ry', 0)
|
rect.setAttribute('ry', 0);
|
||||||
rect.setAttribute('width', dim.width)
|
rect.setAttribute('width', dim.width);
|
||||||
rect.setAttribute('height', dim.height)
|
rect.setAttribute('height', dim.height);
|
||||||
rect.setAttribute('style', 'fill:#e8e8e8;')
|
rect.setAttribute('style', 'fill:#e8e8e8;');
|
||||||
|
|
||||||
label.insertBefore(rect, label.firstChild)
|
label.insertBefore(rect, label.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setConf,
|
setConf,
|
||||||
@ -571,4 +627,4 @@ export default {
|
|||||||
addEdges,
|
addEdges,
|
||||||
getClasses,
|
getClasses,
|
||||||
draw
|
draw
|
||||||
}
|
};
|
||||||
|
@ -1,38 +1,37 @@
|
|||||||
import flowDb from '../flowDb'
|
import flowDb from '../flowDb';
|
||||||
import flow from './flow'
|
import flow from './flow';
|
||||||
import { setConfig } from '../../../config'
|
import { setConfig } from '../../../config';
|
||||||
|
|
||||||
setConfig({
|
setConfig({
|
||||||
securityLevel: 'strict',
|
securityLevel: 'strict'
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('when parsing flowcharts', function () {
|
describe('when parsing flowcharts', function() {
|
||||||
beforeEach(function () {
|
beforeEach(function() {
|
||||||
flow.parser.yy = flowDb
|
flow.parser.yy = flowDb;
|
||||||
flow.parser.yy.clear()
|
flow.parser.yy.clear();
|
||||||
})
|
});
|
||||||
|
|
||||||
it('should handle chaining of vertices', function () {
|
it('should handle chaining of vertices', function() {
|
||||||
const res = flow.parser.parse(`
|
const res = flow.parser.parse(`
|
||||||
graph TD
|
graph TD
|
||||||
A-->B-->C;
|
A-->B-->C;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
expect(vert['A'].id).toBe('A')
|
expect(vert['A'].id).toBe('A');
|
||||||
expect(vert['B'].id).toBe('B')
|
expect(vert['B'].id).toBe('B');
|
||||||
expect(vert['C'].id).toBe('C')
|
expect(vert['C'].id).toBe('C');
|
||||||
expect(edges.length).toBe(2)
|
expect(edges.length).toBe(2);
|
||||||
expect(edges[0].start).toBe('A')
|
expect(edges[0].start).toBe('A');
|
||||||
expect(edges[0].end).toBe('B')
|
expect(edges[0].end).toBe('B');
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
expect(edges[0].text).toBe('')
|
expect(edges[0].text).toBe('');
|
||||||
expect(edges[1].start).toBe('B')
|
expect(edges[1].start).toBe('B');
|
||||||
expect(edges[1].end).toBe('C')
|
expect(edges[1].end).toBe('C');
|
||||||
expect(edges[1].type).toBe('arrow')
|
expect(edges[1].type).toBe('arrow');
|
||||||
expect(edges[1].text).toBe('')
|
expect(edges[1].text).toBe('');
|
||||||
})
|
});
|
||||||
|
});
|
||||||
})
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,223 +1,223 @@
|
|||||||
import flowDb from '../flowDb'
|
import flowDb from '../flowDb';
|
||||||
import flow from './flow'
|
import flow from './flow';
|
||||||
import { setConfig } from '../../../config'
|
import { setConfig } from '../../../config';
|
||||||
|
|
||||||
setConfig({
|
setConfig({
|
||||||
securityLevel: 'strict',
|
securityLevel: 'strict'
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('when parsing subgraphs', function () {
|
describe('when parsing subgraphs', function() {
|
||||||
beforeEach(function () {
|
beforeEach(function() {
|
||||||
flow.parser.yy = flowDb
|
flow.parser.yy = flowDb;
|
||||||
flow.parser.yy.clear()
|
flow.parser.yy.clear();
|
||||||
})
|
});
|
||||||
it('should handle subgraph with tab indentation', function () {
|
it('should handle subgraph with tab indentation', function() {
|
||||||
const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2\nend')
|
const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2\nend');
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
expect(subgraph.nodes.length).toBe(2)
|
expect(subgraph.nodes.length).toBe(2);
|
||||||
expect(subgraph.nodes[0]).toBe('a2')
|
expect(subgraph.nodes[0]).toBe('a2');
|
||||||
expect(subgraph.nodes[1]).toBe('a1')
|
expect(subgraph.nodes[1]).toBe('a1');
|
||||||
expect(subgraph.title).toBe('One')
|
expect(subgraph.title).toBe('One');
|
||||||
expect(subgraph.id).toBe('One')
|
expect(subgraph.id).toBe('One');
|
||||||
})
|
});
|
||||||
it('should handle subgraph with chaining nodes indentation', function () {
|
it('should handle subgraph with chaining nodes indentation', function() {
|
||||||
const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2-->a3\nend')
|
const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2-->a3\nend');
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
expect(subgraph.nodes.length).toBe(3)
|
expect(subgraph.nodes.length).toBe(3);
|
||||||
expect(subgraph.nodes[0]).toBe('a3')
|
expect(subgraph.nodes[0]).toBe('a3');
|
||||||
expect(subgraph.nodes[1]).toBe('a2')
|
expect(subgraph.nodes[1]).toBe('a2');
|
||||||
expect(subgraph.nodes[2]).toBe('a1')
|
expect(subgraph.nodes[2]).toBe('a1');
|
||||||
expect(subgraph.title).toBe('One')
|
expect(subgraph.title).toBe('One');
|
||||||
expect(subgraph.id).toBe('One')
|
expect(subgraph.id).toBe('One');
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle subgraph with multiple words in title', function () {
|
|
||||||
const res = flow.parser.parse('graph TB\nsubgraph "Some Title"\n\ta1-->a2\nend')
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
|
||||||
expect(subgraphs.length).toBe(1)
|
|
||||||
const subgraph = subgraphs[0]
|
|
||||||
expect(subgraph.nodes.length).toBe(2)
|
|
||||||
expect(subgraph.nodes[0]).toBe('a2')
|
|
||||||
expect(subgraph.nodes[1]).toBe('a1')
|
|
||||||
expect(subgraph.title).toBe('Some Title')
|
|
||||||
expect(subgraph.id).toBe('subGraph0')
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle subgraph with id and title notation', function () {
|
it('should handle subgraph with multiple words in title', function() {
|
||||||
const res = flow.parser.parse('graph TB\nsubgraph some-id[Some Title]\n\ta1-->a2\nend')
|
const res = flow.parser.parse('graph TB\nsubgraph "Some Title"\n\ta1-->a2\nend');
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
expect(subgraph.nodes.length).toBe(2)
|
expect(subgraph.nodes.length).toBe(2);
|
||||||
expect(subgraph.nodes[0]).toBe('a2')
|
expect(subgraph.nodes[0]).toBe('a2');
|
||||||
expect(subgraph.nodes[1]).toBe('a1')
|
expect(subgraph.nodes[1]).toBe('a1');
|
||||||
expect(subgraph.title).toBe('Some Title')
|
expect(subgraph.title).toBe('Some Title');
|
||||||
expect(subgraph.id).toBe('some-id')
|
expect(subgraph.id).toBe('subGraph0');
|
||||||
});
|
});
|
||||||
|
|
||||||
xit('should handle subgraph without id and space in title', function () {
|
it('should handle subgraph with id and title notation', function() {
|
||||||
const res = flow.parser.parse('graph TB\nsubgraph Some Title\n\ta1-->a2\nend')
|
const res = flow.parser.parse('graph TB\nsubgraph some-id[Some Title]\n\ta1-->a2\nend');
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
expect(subgraph.nodes.length).toBe(2)
|
expect(subgraph.nodes.length).toBe(2);
|
||||||
expect(subgraph.nodes[0]).toBe('a1')
|
expect(subgraph.nodes[0]).toBe('a2');
|
||||||
expect(subgraph.nodes[1]).toBe('a2')
|
expect(subgraph.nodes[1]).toBe('a1');
|
||||||
expect(subgraph.title).toBe('Some Title')
|
expect(subgraph.title).toBe('Some Title');
|
||||||
expect(subgraph.id).toBe('some-id')
|
expect(subgraph.id).toBe('some-id');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle subgraph id starting with a number', function () {
|
xit('should handle subgraph without id and space in title', function() {
|
||||||
|
const res = flow.parser.parse('graph TB\nsubgraph Some Title\n\ta1-->a2\nend');
|
||||||
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
|
expect(subgraphs.length).toBe(1);
|
||||||
|
const subgraph = subgraphs[0];
|
||||||
|
expect(subgraph.nodes.length).toBe(2);
|
||||||
|
expect(subgraph.nodes[0]).toBe('a1');
|
||||||
|
expect(subgraph.nodes[1]).toBe('a2');
|
||||||
|
expect(subgraph.title).toBe('Some Title');
|
||||||
|
expect(subgraph.id).toBe('some-id');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle subgraph id starting with a number', function() {
|
||||||
const res = flow.parser.parse(`graph TD
|
const res = flow.parser.parse(`graph TD
|
||||||
A[Christmas] -->|Get money| B(Go shopping)
|
A[Christmas] -->|Get money| B(Go shopping)
|
||||||
subgraph 1test
|
subgraph 1test
|
||||||
A
|
A
|
||||||
end`)
|
end`);
|
||||||
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
expect(subgraph.nodes.length).toBe(1)
|
expect(subgraph.nodes.length).toBe(1);
|
||||||
expect(subgraph.nodes[0]).toBe('A')
|
expect(subgraph.nodes[0]).toBe('A');
|
||||||
expect(subgraph.id).toBe('s1test')
|
expect(subgraph.id).toBe('s1test');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle subgraphs1', function () {
|
it('should handle subgraphs1', function() {
|
||||||
const res = flow.parser.parse('graph TD;A-->B;subgraph myTitle;c-->d;end;')
|
const res = flow.parser.parse('graph TD;A-->B;subgraph myTitle;c-->d;end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
it('should handle subgraphs with title in quotes', function () {
|
it('should handle subgraphs with title in quotes', function() {
|
||||||
const res = flow.parser.parse('graph TD;A-->B;subgraph "title in quotes";c-->d;end;')
|
const res = flow.parser.parse('graph TD;A-->B;subgraph "title in quotes";c-->d;end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
|
|
||||||
expect(subgraph.title).toBe('title in quotes')
|
expect(subgraph.title).toBe('title in quotes');
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
it('should handle subgraphs in old style that was broken', function () {
|
it('should handle subgraphs in old style that was broken', function() {
|
||||||
const res = flow.parser.parse('graph TD;A-->B;subgraph old style that is broken;c-->d;end;')
|
const res = flow.parser.parse('graph TD;A-->B;subgraph old style that is broken;c-->d;end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
|
|
||||||
expect(subgraph.title).toBe('old style that is broken')
|
expect(subgraph.title).toBe('old style that is broken');
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
it('should handle subgraphs with dashes in the title', function () {
|
it('should handle subgraphs with dashes in the title', function() {
|
||||||
const res = flow.parser.parse('graph TD;A-->B;subgraph a-b-c;c-->d;end;')
|
const res = flow.parser.parse('graph TD;A-->B;subgraph a-b-c;c-->d;end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
|
|
||||||
expect(subgraph.title).toBe('a-b-c')
|
expect(subgraph.title).toBe('a-b-c');
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
it('should handle subgraphs with id and title in brackets', function () {
|
it('should handle subgraphs with id and title in brackets', function() {
|
||||||
const res = flow.parser.parse('graph TD;A-->B;subgraph uid1[text of doom];c-->d;end;')
|
const res = flow.parser.parse('graph TD;A-->B;subgraph uid1[text of doom];c-->d;end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
|
|
||||||
expect(subgraph.title).toBe('text of doom')
|
expect(subgraph.title).toBe('text of doom');
|
||||||
expect(subgraph.id).toBe('uid1')
|
expect(subgraph.id).toBe('uid1');
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
it('should handle subgraphs with id and title in brackets and quotes', function () {
|
it('should handle subgraphs with id and title in brackets and quotes', function() {
|
||||||
const res = flow.parser.parse('graph TD;A-->B;subgraph uid2["text of doom"];c-->d;end;')
|
const res = flow.parser.parse('graph TD;A-->B;subgraph uid2["text of doom"];c-->d;end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
|
|
||||||
expect(subgraph.title).toBe('text of doom')
|
expect(subgraph.title).toBe('text of doom');
|
||||||
expect(subgraph.id).toBe('uid2')
|
expect(subgraph.id).toBe('uid2');
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
it('should handle subgraphs with id and title in brackets without spaces', function () {
|
it('should handle subgraphs with id and title in brackets without spaces', function() {
|
||||||
const res = flow.parser.parse('graph TD;A-->B;subgraph uid2[textofdoom];c-->d;end;')
|
const res = flow.parser.parse('graph TD;A-->B;subgraph uid2[textofdoom];c-->d;end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
const subgraphs = flow.parser.yy.getSubGraphs()
|
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||||
expect(subgraphs.length).toBe(1)
|
expect(subgraphs.length).toBe(1);
|
||||||
const subgraph = subgraphs[0]
|
const subgraph = subgraphs[0];
|
||||||
|
|
||||||
expect(subgraph.title).toBe('textofdoom')
|
expect(subgraph.title).toBe('textofdoom');
|
||||||
expect(subgraph.id).toBe('uid2')
|
expect(subgraph.id).toBe('uid2');
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
|
|
||||||
it('should handle subgraphs2', function () {
|
it('should handle subgraphs2', function() {
|
||||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\n\n c-->d \nend\n')
|
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\n\n c-->d \nend\n');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
|
|
||||||
it('should handle nested subgraphs', function () {
|
it('should handle nested subgraphs', function() {
|
||||||
const str = 'graph TD\n' +
|
const str =
|
||||||
|
'graph TD\n' +
|
||||||
'A-->B\n' +
|
'A-->B\n' +
|
||||||
'subgraph myTitle\n\n' +
|
'subgraph myTitle\n\n' +
|
||||||
' c-->d \n\n' +
|
' c-->d \n\n' +
|
||||||
' subgraph inner\n\n e-->f \n end \n\n' +
|
' subgraph inner\n\n e-->f \n end \n\n' +
|
||||||
' subgraph inner\n\n h-->i \n end \n\n' +
|
' subgraph inner\n\n h-->i \n end \n\n' +
|
||||||
'end\n'
|
'end\n';
|
||||||
const res = flow.parser.parse(str)
|
const res = flow.parser.parse(str);
|
||||||
})
|
});
|
||||||
|
|
||||||
it('should handle subgraphs4', function () {
|
it('should handle subgraphs4', function() {
|
||||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-->d\nend;')
|
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-->d\nend;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
|
|
||||||
it('should handle subgraphs5', function () {
|
it('should handle subgraphs5', function() {
|
||||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-- text -->d\nd-->e\n end;')
|
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-- text -->d\nd-->e\n end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices()
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges()
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
expect(edges[0].type).toBe('arrow')
|
expect(edges[0].type).toBe('arrow');
|
||||||
})
|
});
|
||||||
|
});
|
||||||
})
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user