mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-29 12:19:41 +02:00
Merge branch 'develop' into feature/Issue-1465_Class_migration
This commit is contained in:
63
src/diagrams/class/styles.js
Normal file
63
src/diagrams/class/styles.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const getStyles = options =>
|
||||
`g.classGroup text {
|
||||
fill: ${options.nodeBorder};
|
||||
fill: ${options.classText};
|
||||
stroke: none;
|
||||
font-family: ${options.fontFamily};
|
||||
font-size: 10px;
|
||||
|
||||
.title {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
|
||||
g.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
g.classGroup rect {
|
||||
fill: ${options.nodeBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
}
|
||||
|
||||
g.classGroup line {
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.classLabel .box {
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
fill: ${options.nodeBkg};
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.classLabel .label {
|
||||
fill: ${options.nodeBorder};
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.relation {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.dashed-line{
|
||||
stroke-dasharray: 3;
|
||||
}
|
||||
|
||||
#compositionStart, #compositionEnd, #dependencyStart, #dependencyEnd, #extensionStart, #extensionEnd {
|
||||
fill: ${options.lineColor};
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
#aggregationStart, #aggregationEnd {
|
||||
fill: ${options.nodeBkg};
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -5,6 +5,30 @@ export const getRows = s => {
|
||||
return str.split('#br#');
|
||||
};
|
||||
|
||||
export const removeScript = txt => {
|
||||
var rs = '';
|
||||
var idx = 0;
|
||||
|
||||
while (idx >= 0) {
|
||||
idx = txt.indexOf('<script');
|
||||
if (idx >= 0) {
|
||||
rs += txt.substr(0, idx);
|
||||
txt = txt.substr(idx + 1);
|
||||
|
||||
idx = txt.indexOf('</script>');
|
||||
if (idx >= 0) {
|
||||
idx += 9;
|
||||
txt = txt.substr(idx);
|
||||
}
|
||||
} else {
|
||||
rs += txt;
|
||||
idx = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rs;
|
||||
};
|
||||
|
||||
export const sanitizeText = (text, config) => {
|
||||
let txt = text;
|
||||
let htmlLabels = true;
|
||||
@@ -14,12 +38,18 @@ export const sanitizeText = (text, config) => {
|
||||
)
|
||||
htmlLabels = false;
|
||||
|
||||
if (config.securityLevel !== 'loose' && htmlLabels) {
|
||||
// eslint-disable-line
|
||||
txt = breakToPlaceholder(txt);
|
||||
txt = txt.replace(/</g, '<').replace(/>/g, '>');
|
||||
txt = txt.replace(/=/g, '=');
|
||||
txt = placeholderToBreak(txt);
|
||||
if (htmlLabels) {
|
||||
var level = config.securityLevel;
|
||||
|
||||
if (level == 'antiscript') {
|
||||
txt = removeScript(txt);
|
||||
} else if (level !== 'loose') {
|
||||
// eslint-disable-line
|
||||
txt = breakToPlaceholder(txt);
|
||||
txt = txt.replace(/</g, '<').replace(/>/g, '>');
|
||||
txt = txt.replace(/=/g, '=');
|
||||
txt = placeholderToBreak(txt);
|
||||
}
|
||||
}
|
||||
|
||||
return txt;
|
||||
@@ -27,6 +57,14 @@ export const sanitizeText = (text, config) => {
|
||||
|
||||
export const lineBreakRegex = /<br\s*\/?>/gi;
|
||||
|
||||
export const hasBreaks = text => {
|
||||
return /<br\s*[/]?>/gi.test(text);
|
||||
};
|
||||
|
||||
export const splitBreaks = text => {
|
||||
return text.split(/<br\s*[/]?>/gi);
|
||||
};
|
||||
|
||||
const breakToPlaceholder = s => {
|
||||
return s.replace(lineBreakRegex, '#br#');
|
||||
};
|
||||
@@ -38,5 +76,8 @@ const placeholderToBreak = s => {
|
||||
export default {
|
||||
getRows,
|
||||
sanitizeText,
|
||||
lineBreakRegex
|
||||
hasBreaks,
|
||||
splitBreaks,
|
||||
lineBreakRegex,
|
||||
removeScript
|
||||
};
|
||||
|
26
src/diagrams/common/common.spec.js
Normal file
26
src/diagrams/common/common.spec.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { removeScript } from './common';
|
||||
|
||||
describe('when securityLevel is antiscript, all script must be removed', function() {
|
||||
it('should remove all script block, script inline.', function() {
|
||||
const labelString = `1
|
||||
Act1: Hello 1<script src="http://abc.com/script1.js"></script>1
|
||||
<b>Act2</b>:
|
||||
1<script>
|
||||
alert('script run......');
|
||||
</script>1
|
||||
1`;
|
||||
|
||||
const result = removeScript(labelString);
|
||||
const hasScript = (result.indexOf("script") >= 0);
|
||||
expect(hasScript).toEqual(false);
|
||||
|
||||
const exactlyString = `1
|
||||
Act1: Hello 11
|
||||
<b>Act2</b>:
|
||||
11
|
||||
1`;
|
||||
|
||||
const isEqual = (result == exactlyString);
|
||||
expect(isEqual).toEqual(true);
|
||||
});
|
||||
});
|
@@ -43,6 +43,7 @@ const drawEntities = function(svgNode, entities, graph) {
|
||||
const textId = 'entity-' + id;
|
||||
const textNode = groupNode
|
||||
.append('text')
|
||||
.attr('class', 'er entityLabel')
|
||||
.attr('id', textId)
|
||||
.attr('x', 0)
|
||||
.attr('y', 0)
|
||||
@@ -65,6 +66,7 @@ const drawEntities = function(svgNode, entities, graph) {
|
||||
// Draw the rectangle - insert it before the text so that the text is not obscured
|
||||
const rectNode = groupNode
|
||||
.insert('rect', '#' + textId)
|
||||
.attr('class', 'er entityBox')
|
||||
.attr('fill', conf.fill)
|
||||
.attr('fill-opacity', '100%')
|
||||
.attr('stroke', conf.stroke)
|
||||
@@ -148,6 +150,7 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
|
||||
// Insert the line at the right place
|
||||
const svgPath = svg
|
||||
.insert('path', '#' + insert)
|
||||
.attr('class', 'er relationshipLine')
|
||||
.attr('d', lineFunction(edge.points))
|
||||
.attr('stroke', conf.stroke)
|
||||
.attr('fill', 'none');
|
||||
@@ -224,6 +227,7 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
|
||||
|
||||
const labelNode = svg
|
||||
.append('text')
|
||||
.attr('class', 'er relationshipLabel')
|
||||
.attr('id', labelId)
|
||||
.attr('x', labelPoint.x)
|
||||
.attr('y', labelPoint.y)
|
||||
@@ -241,6 +245,7 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
|
||||
// Insert the opaque rectangle before the text label
|
||||
svg
|
||||
.insert('rect', '#' + labelId)
|
||||
.attr('class', 'er relationshipLabelBox')
|
||||
.attr('x', labelPoint.x - labelBBox.width / 2)
|
||||
.attr('y', labelPoint.y - labelBBox.height / 2)
|
||||
.attr('width', labelBBox.width)
|
||||
@@ -339,9 +344,14 @@ export const draw = function(text, id) {
|
||||
const width = svgBounds.width + padding * 2;
|
||||
const height = svgBounds.height + padding * 2;
|
||||
|
||||
svg.attr('height', height);
|
||||
svg.attr('width', '100%');
|
||||
svg.attr('style', `max-width: ${width}px;`);
|
||||
if (conf.useMaxWidth) {
|
||||
svg.attr('width', '100%');
|
||||
svg.attr('style', `max-width: ${width}px;`);
|
||||
} else {
|
||||
svg.attr('height', height);
|
||||
svg.attr('width', width);
|
||||
}
|
||||
|
||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||
}; // draw
|
||||
|
||||
|
22
src/diagrams/er/styles.js
Normal file
22
src/diagrams/er/styles.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const getStyles = options =>
|
||||
`
|
||||
.entityBox {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
}
|
||||
|
||||
.relationshipLabelBox {
|
||||
fill: ${options.edgeLabelBackground};
|
||||
fillopactity: 0;
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
rect {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.relationshipLine {
|
||||
stroke: ${options.lineColor};
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -219,7 +219,7 @@ const setTooltip = function(ids, tooltip) {
|
||||
const setClickFun = function(_id, functionName) {
|
||||
let id = _id;
|
||||
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||
if (config.securityLevel !== 'loose') {
|
||||
if (getConfig().securityLevel !== 'loose') {
|
||||
return;
|
||||
}
|
||||
if (typeof functionName === 'undefined') {
|
||||
|
@@ -407,7 +407,7 @@ export const draw = function(text, id) {
|
||||
return flowDb.getTooltip(this.id);
|
||||
});
|
||||
|
||||
const padding = 8;
|
||||
const padding = conf.diagramPadding;
|
||||
const svgBounds = svg.node().getBBox();
|
||||
const width = svgBounds.width + padding * 2;
|
||||
const height = svgBounds.height + padding * 2;
|
||||
|
@@ -394,7 +394,7 @@ export const draw = function(text, id) {
|
||||
return flowDb.getTooltip(this.id);
|
||||
});
|
||||
|
||||
const padding = 8;
|
||||
const padding = conf.diagramPadding;
|
||||
const svgBounds = svg.node().getBBox();
|
||||
const width = svgBounds.width + padding * 2;
|
||||
const height = svgBounds.height + padding * 2;
|
||||
|
75
src/diagrams/flowchart/styles.js
Normal file
75
src/diagrams/flowchart/styles.js
Normal file
@@ -0,0 +1,75 @@
|
||||
const getStyles = options =>
|
||||
`.label {
|
||||
font-family: ${options.fontFamily};
|
||||
color: ${options.textColor};
|
||||
}
|
||||
|
||||
.label text {
|
||||
fill: ${options.textColor};
|
||||
}
|
||||
|
||||
.node rect,
|
||||
.node circle,
|
||||
.node ellipse,
|
||||
.node polygon,
|
||||
.node path {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.node .label {
|
||||
text-align: center;
|
||||
}
|
||||
.node.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.arrowheadPath {
|
||||
fill: ${options.arrowheadColor};
|
||||
}
|
||||
|
||||
.edgePath .path {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.flowchart-link {
|
||||
stroke: ${options.lineColor};
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.edgeLabel {
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
rect {
|
||||
opacity: 0.5;
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cluster rect {
|
||||
fill: ${options.secondBkg};
|
||||
stroke: ${options.clusterBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.cluster text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
div.mermaidTooltip {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 200px;
|
||||
padding: 2px;
|
||||
font-family: ${options.fontFamily};
|
||||
font-size: 12px;
|
||||
background: ${options.secondBkg};
|
||||
border: 1px solid ${options.border2};
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -4,7 +4,6 @@ import { logger } from '../../logger';
|
||||
import { getConfig } from '../../config';
|
||||
import utils from '../../utils';
|
||||
|
||||
const config = getConfig();
|
||||
let dateFormat = '';
|
||||
let axisFormat = '';
|
||||
let todayMarker = '';
|
||||
@@ -17,6 +16,9 @@ const tags = ['active', 'done', 'crit', 'milestone'];
|
||||
let funs = [];
|
||||
let inclusiveEndDates = false;
|
||||
|
||||
// The serial order of the task in the script
|
||||
let lastOrder = 0;
|
||||
|
||||
export const clear = function() {
|
||||
sections = [];
|
||||
tasks = [];
|
||||
@@ -32,6 +34,7 @@ export const clear = function() {
|
||||
todayMarker = '';
|
||||
excludes = [];
|
||||
inclusiveEndDates = false;
|
||||
lastOrder = 0;
|
||||
};
|
||||
|
||||
export const setAxisFormat = function(txt) {
|
||||
@@ -374,6 +377,9 @@ export const addTask = function(descr, data) {
|
||||
rawTask.done = taskInfo.done;
|
||||
rawTask.crit = taskInfo.crit;
|
||||
rawTask.milestone = taskInfo.milestone;
|
||||
rawTask.order = lastOrder;
|
||||
|
||||
lastOrder++;
|
||||
|
||||
const pos = rawTasks.push(rawTask);
|
||||
|
||||
@@ -462,7 +468,7 @@ const compileTasks = function() {
|
||||
*/
|
||||
export const setLink = function(ids, _linkStr) {
|
||||
let linkStr = _linkStr;
|
||||
if (config.securityLevel !== 'loose') {
|
||||
if (getConfig().securityLevel !== 'loose') {
|
||||
linkStr = sanitizeUrl(_linkStr);
|
||||
}
|
||||
ids.split(',').forEach(function(id) {
|
||||
@@ -491,7 +497,7 @@ export const setClass = function(ids, className) {
|
||||
};
|
||||
|
||||
const setClickFun = function(id, functionName, functionArgs) {
|
||||
if (config.securityLevel !== 'loose') {
|
||||
if (getConfig().securityLevel !== 'loose') {
|
||||
return;
|
||||
}
|
||||
if (typeof functionName === 'undefined') {
|
||||
|
@@ -176,6 +176,137 @@ describe('when using the ganttDb', function() {
|
||||
expect(tasks[6].task).toEqual('test7');
|
||||
});
|
||||
|
||||
it('should maintain the order in which tasks are created', function() {
|
||||
ganttDb.setTitle('Project Execution');
|
||||
ganttDb.setDateFormat('YYYY-MM-DD');
|
||||
ganttDb.addSection('section A section');
|
||||
ganttDb.addTask('Completed task', 'done, des1, 2014-01-06,2014-01-08');
|
||||
ganttDb.addTask('Active task', 'active, des2, 2014-01-09, 3d');
|
||||
ganttDb.addTask('Future task', 'des3, after des2, 5d');
|
||||
ganttDb.addTask('Future task2', 'des4, after des3, 5d');
|
||||
|
||||
ganttDb.addSection('section Critical tasks');
|
||||
ganttDb.addTask('Completed task in the critical line', 'crit, done, 2014-01-06,24h');
|
||||
ganttDb.addTask('Implement parser and jison', 'crit, done, after des1, 2d');
|
||||
ganttDb.addTask('Create tests for parser', 'crit, active, 3d');
|
||||
ganttDb.addTask('Future task in critical line', 'crit, 5d');
|
||||
ganttDb.addTask('Create tests for renderer', '2d');
|
||||
ganttDb.addTask('Add to mermaid', '1d');
|
||||
|
||||
ganttDb.addSection('section Documentation');
|
||||
ganttDb.addTask('Describe gantt syntax', 'active, a1, after des1, 3d');
|
||||
ganttDb.addTask('Add gantt diagram to demo page', 'after a1 , 20h');
|
||||
ganttDb.addTask('Add another diagram to demo page', 'doc1, after a1 , 48h');
|
||||
|
||||
ganttDb.addSection('section Last section');
|
||||
ganttDb.addTask('Describe gantt syntax', 'after doc1, 3d');
|
||||
ganttDb.addTask('Add gantt diagram to demo page', '20h');
|
||||
ganttDb.addTask('Add another diagram to demo page', '48h');
|
||||
|
||||
const tasks = ganttDb.getTasks();
|
||||
|
||||
// Section - A section
|
||||
expect(tasks[0].startTime).toEqual(moment('2014-01-06', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[0].endTime).toEqual(moment('2014-01-08', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[0].order).toEqual(0);
|
||||
expect(tasks[0].id).toEqual('des1');
|
||||
expect(tasks[0].task).toEqual('Completed task');
|
||||
|
||||
expect(tasks[1].startTime).toEqual(moment('2014-01-09', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[1].endTime).toEqual(moment('2014-01-12', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[1].order).toEqual(1);
|
||||
expect(tasks[1].id).toEqual('des2');
|
||||
expect(tasks[1].task).toEqual('Active task');
|
||||
|
||||
expect(tasks[2].startTime).toEqual(moment('2014-01-12', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[2].endTime).toEqual(moment('2014-01-17', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[2].order).toEqual(2);
|
||||
expect(tasks[2].id).toEqual('des3');
|
||||
expect(tasks[2].task).toEqual('Future task');
|
||||
|
||||
expect(tasks[3].startTime).toEqual(moment('2014-01-17', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[3].endTime).toEqual(moment('2014-01-22', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[3].order).toEqual(3);
|
||||
expect(tasks[3].id).toEqual('des4');
|
||||
expect(tasks[3].task).toEqual('Future task2');
|
||||
|
||||
// Section - Critical tasks
|
||||
expect(tasks[4].startTime).toEqual(moment('2014-01-06', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[4].endTime).toEqual(moment('2014-01-07', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[4].order).toEqual(4);
|
||||
expect(tasks[4].id).toEqual('task1');
|
||||
expect(tasks[4].task).toEqual('Completed task in the critical line');
|
||||
|
||||
expect(tasks[5].startTime).toEqual(moment('2014-01-08', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[5].endTime).toEqual(moment('2014-01-10', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[5].order).toEqual(5);
|
||||
expect(tasks[5].id).toEqual('task2');
|
||||
expect(tasks[5].task).toEqual('Implement parser and jison');
|
||||
|
||||
expect(tasks[6].startTime).toEqual(moment('2014-01-10', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[6].endTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[6].order).toEqual(6);
|
||||
expect(tasks[6].id).toEqual('task3');
|
||||
expect(tasks[6].task).toEqual('Create tests for parser');
|
||||
|
||||
expect(tasks[7].startTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[7].endTime).toEqual(moment('2014-01-18', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[7].order).toEqual(7);
|
||||
expect(tasks[7].id).toEqual('task4');
|
||||
expect(tasks[7].task).toEqual('Future task in critical line');
|
||||
|
||||
expect(tasks[8].startTime).toEqual(moment('2014-01-18', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[8].endTime).toEqual(moment('2014-01-20', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[8].order).toEqual(8);
|
||||
expect(tasks[8].id).toEqual('task5');
|
||||
expect(tasks[8].task).toEqual('Create tests for renderer');
|
||||
|
||||
expect(tasks[9].startTime).toEqual(moment('2014-01-20', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[9].endTime).toEqual(moment('2014-01-21', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[9].order).toEqual(9);
|
||||
expect(tasks[9].id).toEqual('task6');
|
||||
expect(tasks[9].task).toEqual('Add to mermaid');
|
||||
|
||||
// Section - Documentation
|
||||
expect(tasks[10].startTime).toEqual(moment('2014-01-08', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[10].endTime).toEqual(moment('2014-01-11', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[10].order).toEqual(10);
|
||||
expect(tasks[10].id).toEqual('a1');
|
||||
expect(tasks[10].task).toEqual('Describe gantt syntax');
|
||||
|
||||
expect(tasks[11].startTime).toEqual(moment('2014-01-11', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[11].endTime).toEqual(moment('2014-01-11 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
|
||||
expect(tasks[11].order).toEqual(11);
|
||||
expect(tasks[11].id).toEqual('task7');
|
||||
expect(tasks[11].task).toEqual('Add gantt diagram to demo page');
|
||||
|
||||
expect(tasks[12].startTime).toEqual(moment('2014-01-11', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[12].endTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[12].order).toEqual(12);
|
||||
expect(tasks[12].id).toEqual('doc1');
|
||||
expect(tasks[12].task).toEqual('Add another diagram to demo page');
|
||||
|
||||
// Section - Last section
|
||||
expect(tasks[13].startTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[13].endTime).toEqual(moment('2014-01-16', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[13].order).toEqual(13);
|
||||
expect(tasks[13].id).toEqual('task8');
|
||||
expect(tasks[13].task).toEqual('Describe gantt syntax');
|
||||
|
||||
expect(tasks[14].startTime).toEqual(moment('2014-01-16', 'YYYY-MM-DD').toDate());
|
||||
expect(tasks[14].endTime).toEqual(moment('2014-01-16 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
|
||||
expect(tasks[14].order).toEqual(14);
|
||||
expect(tasks[14].id).toEqual('task9');
|
||||
expect(tasks[14].task).toEqual('Add gantt diagram to demo page');
|
||||
|
||||
expect(tasks[15].startTime).toEqual(moment('2014-01-16 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
|
||||
expect(tasks[15].endTime).toEqual(moment('2014-01-18 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
|
||||
expect(tasks[15].order).toEqual(15);
|
||||
expect(tasks[15].id).toEqual('task10');
|
||||
expect(tasks[15].task).toEqual('Add another diagram to demo page');
|
||||
});
|
||||
|
||||
|
||||
it('should work when end date is the 31st', function() {
|
||||
ganttDb.setDateFormat('YYYY-MM-DD');
|
||||
ganttDb.addSection('Task endTime is on the 31st day of the month');
|
||||
|
@@ -80,6 +80,22 @@ export const draw = function(text, id) {
|
||||
|
||||
categories = checkUnique(categories);
|
||||
|
||||
function taskCompare(a, b) {
|
||||
const taskA = a.startTime;
|
||||
const taskB = b.startTime;
|
||||
let result = 0;
|
||||
if (taskA > taskB) {
|
||||
result = 1;
|
||||
} else if (taskA < taskB) {
|
||||
result = -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Sort the task array using the above taskCompare() so that
|
||||
// tasks are created based on their order of startTime
|
||||
taskArray.sort(taskCompare);
|
||||
|
||||
makeGant(taskArray, w, h);
|
||||
if (typeof conf.useWidth !== 'undefined') {
|
||||
elem.setAttribute('width', w);
|
||||
@@ -119,6 +135,8 @@ export const draw = function(text, id) {
|
||||
.append('rect')
|
||||
.attr('x', 0)
|
||||
.attr('y', function(d, i) {
|
||||
// Ignore the incoming i value and use our order instead
|
||||
i = d.order;
|
||||
return i * theGap + theTopPad - 2;
|
||||
})
|
||||
.attr('width', function() {
|
||||
@@ -160,6 +178,8 @@ export const draw = function(text, id) {
|
||||
return timeScale(d.startTime) + theSidePad;
|
||||
})
|
||||
.attr('y', function(d, i) {
|
||||
// Ignore the incoming i value and use our order instead
|
||||
i = d.order;
|
||||
return i * theGap + theTopPad;
|
||||
})
|
||||
.attr('width', function(d) {
|
||||
@@ -263,6 +283,8 @@ export const draw = function(text, id) {
|
||||
}
|
||||
})
|
||||
.attr('y', function(d, i) {
|
||||
// Ignore the incoming i value and use our order instead
|
||||
i = d.order;
|
||||
return i * theGap + conf.barHeight / 2 + (conf.fontSize / 2 - 2) + theTopPad;
|
||||
})
|
||||
.attr('text-height', theBarHeight)
|
||||
@@ -280,6 +302,7 @@ export const draw = function(text, id) {
|
||||
}
|
||||
|
||||
let secNum = 0;
|
||||
console.log(conf);
|
||||
for (let i = 0; i < categories.length; i++) {
|
||||
if (d.type === categories[i]) {
|
||||
secNum = i % conf.numberSectionStyles;
|
||||
|
261
src/diagrams/gantt/styles.js
Normal file
261
src/diagrams/gantt/styles.js
Normal file
@@ -0,0 +1,261 @@
|
||||
const getStyles = options =>
|
||||
`
|
||||
.mermaid-main-font {
|
||||
font-family: "trebuchet ms", verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
}
|
||||
|
||||
.section {
|
||||
stroke: none;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.section0 {
|
||||
fill: ${options.sectionBkgColor};
|
||||
}
|
||||
|
||||
.section2 {
|
||||
fill: ${options.sectionBkgColor2};
|
||||
}
|
||||
|
||||
.section1,
|
||||
.section3 {
|
||||
fill: ${options.altSectionBkgColor};
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.sectionTitle0 {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
.sectionTitle1 {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
.sectionTitle2 {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
.sectionTitle3 {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
text-anchor: start;
|
||||
font-size: 11px;
|
||||
text-height: 14px;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Grid and axis */
|
||||
|
||||
.grid .tick {
|
||||
stroke: ${options.gridColor};
|
||||
opacity: 0.8;
|
||||
shape-rendering: crispEdges;
|
||||
text {
|
||||
font-family: ${options.fontFamily};
|
||||
fill: ${options.textColor};
|
||||
}
|
||||
}
|
||||
|
||||
.grid path {
|
||||
stroke-width: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Today line */
|
||||
|
||||
.today {
|
||||
fill: none;
|
||||
stroke: ${options.todayLineColor};
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
|
||||
/* Task styling */
|
||||
|
||||
/* Default task */
|
||||
|
||||
.task {
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.taskText {
|
||||
text-anchor: middle;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
}
|
||||
|
||||
.taskText:not([font-size]) {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.taskTextOutsideRight {
|
||||
fill: ${options.taskTextDarkColor};
|
||||
text-anchor: start;
|
||||
font-size: 11px;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
|
||||
}
|
||||
|
||||
.taskTextOutsideLeft {
|
||||
fill: ${options.taskTextDarkColor};
|
||||
text-anchor: end;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* Special case clickable */
|
||||
.task.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.taskText.clickable {
|
||||
cursor: pointer;
|
||||
fill: ${options.taskTextClickableColor} !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.taskTextOutsideLeft.clickable {
|
||||
cursor: pointer;
|
||||
fill: ${options.taskTextClickableColor} !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.taskTextOutsideRight.clickable {
|
||||
cursor: pointer;
|
||||
fill: ${options.taskTextClickableColor} !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Specific task settings for the sections*/
|
||||
|
||||
.taskText0,
|
||||
.taskText1,
|
||||
.taskText2,
|
||||
.taskText3 {
|
||||
fill: ${options.taskTextColor};
|
||||
}
|
||||
|
||||
.task0,
|
||||
.task1,
|
||||
.task2,
|
||||
.task3 {
|
||||
fill: ${options.taskBkgColor};
|
||||
stroke: ${options.taskBorderColor};
|
||||
}
|
||||
|
||||
.taskTextOutside0,
|
||||
.taskTextOutside2
|
||||
{
|
||||
fill: ${options.taskTextOutsideColor};
|
||||
}
|
||||
|
||||
.taskTextOutside1,
|
||||
.taskTextOutside3 {
|
||||
fill: ${options.taskTextOutsideColor};
|
||||
}
|
||||
|
||||
|
||||
/* Active task */
|
||||
|
||||
.active0,
|
||||
.active1,
|
||||
.active2,
|
||||
.active3 {
|
||||
fill: ${options.activeTaskBkgColor};
|
||||
stroke: ${options.activeTaskBorderColor};
|
||||
}
|
||||
|
||||
.activeText0,
|
||||
.activeText1,
|
||||
.activeText2,
|
||||
.activeText3 {
|
||||
fill: ${options.taskTextDarkColor} !important;
|
||||
}
|
||||
|
||||
|
||||
/* Completed task */
|
||||
|
||||
.done0,
|
||||
.done1,
|
||||
.done2,
|
||||
.done3 {
|
||||
stroke: ${options.doneTaskBorderColor};
|
||||
fill: ${options.doneTaskBkgColor};
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.doneText0,
|
||||
.doneText1,
|
||||
.doneText2,
|
||||
.doneText3 {
|
||||
fill: ${options.taskTextDarkColor} !important;
|
||||
}
|
||||
|
||||
|
||||
/* Tasks on the critical line */
|
||||
|
||||
.crit0,
|
||||
.crit1,
|
||||
.crit2,
|
||||
.crit3 {
|
||||
stroke: ${options.critBorderColor};
|
||||
fill: ${options.critBkgColor};
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.activeCrit0,
|
||||
.activeCrit1,
|
||||
.activeCrit2,
|
||||
.activeCrit3 {
|
||||
stroke: ${options.critBorderColor};
|
||||
fill: ${options.activeTaskBkgColor};
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.doneCrit0,
|
||||
.doneCrit1,
|
||||
.doneCrit2,
|
||||
.doneCrit3 {
|
||||
stroke: ${options.critBorderColor};
|
||||
fill: ${options.doneTaskBkgColor};
|
||||
stroke-width: 2;
|
||||
cursor: pointer;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.milestone {
|
||||
transform: rotate(45deg) scale(0.8,0.8);
|
||||
}
|
||||
|
||||
.milestoneText {
|
||||
font-style: italic;
|
||||
}
|
||||
.doneCritText0,
|
||||
.doneCritText1,
|
||||
.doneCritText2,
|
||||
.doneCritText3 {
|
||||
fill: ${options.taskTextDarkColor} !important;
|
||||
}
|
||||
|
||||
.activeCritText0,
|
||||
.activeCritText1,
|
||||
.activeCritText2,
|
||||
.activeCritText3 {
|
||||
fill: ${options.taskTextDarkColor} !important;
|
||||
}
|
||||
|
||||
.titleText {
|
||||
text-anchor: middle;
|
||||
font-size: 18px;
|
||||
fill: ${options.taskTextDarkColor} ;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -1,5 +1,5 @@
|
||||
import { logger } from '../../logger';
|
||||
|
||||
import { random } from '../../utils';
|
||||
let commits = {};
|
||||
let head = null;
|
||||
let branches = { master: head };
|
||||
@@ -7,18 +7,8 @@ let curBranch = 'master';
|
||||
let direction = 'LR';
|
||||
let seq = 0;
|
||||
|
||||
function makeid(length) {
|
||||
var result = '';
|
||||
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
var charactersLength = characters.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getId() {
|
||||
return makeid(7);
|
||||
return random({ length: 7 });
|
||||
}
|
||||
|
||||
function isfastforwardable(currentCommit, otherCommit) {
|
||||
|
@@ -1,10 +1,9 @@
|
||||
|
||||
/*
|
||||
* Parse following
|
||||
* gitGraph:
|
||||
* commit
|
||||
* commit
|
||||
* branch
|
||||
* branch
|
||||
*/
|
||||
%lex
|
||||
|
||||
@@ -14,28 +13,28 @@
|
||||
|
||||
%%
|
||||
|
||||
(\r?\n)+ return 'NL';
|
||||
\s+ /* skip all whitespace */
|
||||
\#[^\n]* /* skip comments */
|
||||
\%%[^\n]* /* skip comments */
|
||||
"gitGraph" return 'GG';
|
||||
"commit" return 'COMMIT';
|
||||
"branch" return 'BRANCH';
|
||||
"merge" return 'MERGE';
|
||||
"reset" return 'RESET';
|
||||
"checkout" return 'CHECKOUT';
|
||||
"LR" return 'DIR';
|
||||
"BT" return 'DIR';
|
||||
":" return ':';
|
||||
"^" return 'CARET'
|
||||
"options"\r?\n this.begin("options");
|
||||
<options>"end"\r?\n this.popState();
|
||||
<options>[^\n]+\r?\n return 'OPT';
|
||||
["] this.begin("string");
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return 'STR';
|
||||
[a-zA-Z][a-zA-Z0-9_]+ return 'ID';
|
||||
<<EOF>> return 'EOF';
|
||||
(\r?\n)+ return 'NL';
|
||||
\s+ /* skip all whitespace */
|
||||
\#[^\n]* /* skip comments */
|
||||
\%%[^\n]* /* skip comments */
|
||||
"gitGraph" return 'GG';
|
||||
"commit" return 'COMMIT';
|
||||
"branch" return 'BRANCH';
|
||||
"merge" return 'MERGE';
|
||||
"reset" return 'RESET';
|
||||
"checkout" return 'CHECKOUT';
|
||||
"LR" return 'DIR';
|
||||
"BT" return 'DIR';
|
||||
":" return ':';
|
||||
"^" return 'CARET'
|
||||
"options"\r?\n this.begin("options");
|
||||
<options>"end"\r?\n this.popState();
|
||||
<options>[^\n]+\r?\n return 'OPT';
|
||||
["] this.begin("string");
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return 'STR';
|
||||
[a-zA-Z][-_\.a-zA-Z0-9]*[-_a-zA-Z0-9] return 'ID';
|
||||
<<EOF>> return 'EOF';
|
||||
|
||||
/lex
|
||||
|
||||
|
13
src/diagrams/git/styles.js
Normal file
13
src/diagrams/git/styles.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const getStyles = () =>
|
||||
`
|
||||
.commit-id,
|
||||
.commit-msg,
|
||||
.branch-label {
|
||||
fill: lightgrey;
|
||||
color: lightgrey;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
3
src/diagrams/info/styles.js
Normal file
3
src/diagrams/info/styles.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const getStyles = () => ``;
|
||||
|
||||
export default getStyles;
|
20
src/diagrams/pie/styles.js
Normal file
20
src/diagrams/pie/styles.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const getStyles = options =>
|
||||
`.pieTitleText {
|
||||
text-anchor: middle;
|
||||
font-size: 25px;
|
||||
fill: ${options.taskTextDarkColor};
|
||||
font-family: ${options.fontFamily};
|
||||
}
|
||||
.slice {
|
||||
font-family: ${options.fontFamily};
|
||||
fill: ${options.textColor};
|
||||
// fill: white;
|
||||
}
|
||||
.legend text {
|
||||
fill: ${options.taskTextDarkColor};
|
||||
font-family: ${options.fontFamily};
|
||||
font-size: 17px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -230,7 +230,7 @@ argDirective
|
||||
;
|
||||
|
||||
closeDirective
|
||||
: close_directive { yy.parseDirective('}%%', 'close_directive'); }
|
||||
: close_directive { yy.parseDirective('}%%', 'close_directive', 'sequence'); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { logger } from '../../logger';
|
||||
import { getConfig, setConfig } from '../../config';
|
||||
import mermaidAPI from '../../mermaidAPI';
|
||||
import configApi from '../../config';
|
||||
import common from '../common/common';
|
||||
import { logger } from '../../logger';
|
||||
|
||||
let prevActor = undefined;
|
||||
let actors = {};
|
||||
@@ -10,58 +11,9 @@ let title = '';
|
||||
let titleWrapped = false;
|
||||
let sequenceNumbersEnabled = false;
|
||||
let wrapEnabled = false;
|
||||
let configUpdated = false;
|
||||
let currentDirective = {};
|
||||
|
||||
export const parseDirective = function(statement, context) {
|
||||
try {
|
||||
if (statement !== undefined) {
|
||||
statement = statement.trim();
|
||||
switch (context) {
|
||||
case 'open_directive':
|
||||
currentDirective = {};
|
||||
break;
|
||||
case 'type_directive':
|
||||
currentDirective.type = statement.toLowerCase();
|
||||
break;
|
||||
case 'arg_directive':
|
||||
currentDirective.args = JSON.parse(statement);
|
||||
break;
|
||||
case 'close_directive':
|
||||
handleDirective(currentDirective);
|
||||
currentDirective = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Error while rendering sequenceDiagram directive: ${statement} jison context: ${context}`
|
||||
);
|
||||
logger.error(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDirective = function(directive) {
|
||||
logger.debug(`Directive type=${directive.type} with args:`, directive.args);
|
||||
switch (directive.type) {
|
||||
case 'init':
|
||||
case 'initialize':
|
||||
mermaidAPI.initialize(directive.args);
|
||||
break;
|
||||
case 'config':
|
||||
updateConfig(directive.args);
|
||||
break;
|
||||
case 'wrap':
|
||||
case 'nowrap':
|
||||
wrapEnabled = directive.type === 'wrap';
|
||||
break;
|
||||
default:
|
||||
logger.warn(
|
||||
`Unrecognized directive: source: '%%{${directive.type}: ${directive.args}}%%`,
|
||||
directive
|
||||
);
|
||||
break;
|
||||
}
|
||||
export const parseDirective = function(statement, context, type) {
|
||||
mermaidAPI.parseDirective(statement, context, type);
|
||||
};
|
||||
|
||||
export const addActor = function(id, name, description) {
|
||||
@@ -77,7 +29,7 @@ export const addActor = function(id, name, description) {
|
||||
actors[id] = {
|
||||
name: name,
|
||||
description: description.text,
|
||||
wrap: (description.wrap === null && autoWrap()) || !!description.wrap,
|
||||
wrap: (description.wrap === undefined && autoWrap()) || !!description.wrap,
|
||||
prevActor: prevActor
|
||||
};
|
||||
if (prevActor && actors[prevActor]) {
|
||||
@@ -111,28 +63,19 @@ export const addMessage = function(idFrom, idTo, message, answer) {
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
answer: answer
|
||||
});
|
||||
};
|
||||
|
||||
export const addSignal = function(idFrom, idTo, message = { text: null, wrap: null }, messageType) {
|
||||
logger.debug(
|
||||
'Adding message from=' +
|
||||
idFrom +
|
||||
' to=' +
|
||||
idTo +
|
||||
' message=' +
|
||||
message.text +
|
||||
' wrap=' +
|
||||
message.wrap +
|
||||
' type=' +
|
||||
messageType
|
||||
);
|
||||
|
||||
export const addSignal = function(
|
||||
idFrom,
|
||||
idTo,
|
||||
message = { text: undefined, wrap: undefined },
|
||||
messageType
|
||||
) {
|
||||
if (messageType === LINETYPE.ACTIVE_END) {
|
||||
const cnt = activationCount(idFrom.actor);
|
||||
logger.debug('Adding message from=', messages, cnt);
|
||||
if (cnt < 1) {
|
||||
// Bail out as there is an activation signal from an inactive participant
|
||||
let error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')');
|
||||
@@ -150,7 +93,7 @@ export const addSignal = function(idFrom, idTo, message = { text: null, wrap: nu
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
type: messageType
|
||||
});
|
||||
return true;
|
||||
@@ -180,12 +123,8 @@ export const enableSequenceNumbers = function() {
|
||||
};
|
||||
export const showSequenceNumbers = () => sequenceNumbersEnabled;
|
||||
|
||||
export const enableWrap = function() {
|
||||
wrapEnabled = true;
|
||||
};
|
||||
|
||||
export const disableWrap = function() {
|
||||
wrapEnabled = false;
|
||||
export const setWrap = function(wrapSetting) {
|
||||
wrapEnabled = wrapSetting;
|
||||
};
|
||||
|
||||
export const autoWrap = () => wrapEnabled;
|
||||
@@ -193,22 +132,23 @@ export const autoWrap = () => wrapEnabled;
|
||||
export const clear = function() {
|
||||
actors = {};
|
||||
messages = [];
|
||||
configUpdated = false;
|
||||
};
|
||||
|
||||
export const parseMessage = function(str) {
|
||||
const _str = str.trim();
|
||||
return {
|
||||
const message = {
|
||||
text: _str.replace(/^[:]?(?:no)?wrap:/, '').trim(),
|
||||
wrap:
|
||||
_str.match(/^[:]?(?:no)?wrap:/) === null
|
||||
? autoWrap()
|
||||
? common.hasBreaks(_str) || autoWrap()
|
||||
: _str.match(/^[:]?wrap:/) !== null
|
||||
? true
|
||||
: _str.match(/^[:]?nowrap:/) !== null
|
||||
? false
|
||||
: autoWrap()
|
||||
};
|
||||
logger.debug('parseMessage:', message);
|
||||
return message;
|
||||
};
|
||||
|
||||
export const LINETYPE = {
|
||||
@@ -251,7 +191,7 @@ export const addNote = function(actor, placement, message) {
|
||||
actor: actor,
|
||||
placement: placement,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap
|
||||
};
|
||||
|
||||
// Coerce actor into a [to, from, ...] array
|
||||
@@ -262,7 +202,7 @@ export const addNote = function(actor, placement, message) {
|
||||
from: actors[0],
|
||||
to: actors[1],
|
||||
message: message.text,
|
||||
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
type: LINETYPE.NOTE,
|
||||
placement: placement
|
||||
});
|
||||
@@ -270,20 +210,7 @@ export const addNote = function(actor, placement, message) {
|
||||
|
||||
export const setTitle = function(titleWrap) {
|
||||
title = titleWrap.text;
|
||||
titleWrapped = (titleWrap.wrap === null && autoWrap()) || !!titleWrap.wrap;
|
||||
};
|
||||
|
||||
export const updateConfig = function(config = getConfig()) {
|
||||
try {
|
||||
setConfig(config);
|
||||
configUpdated = true;
|
||||
} catch (error) {
|
||||
logger.error('Error: unable to parse config');
|
||||
}
|
||||
};
|
||||
|
||||
export const hasConfigChange = function() {
|
||||
return configUpdated;
|
||||
titleWrapped = (titleWrap.wrap === undefined && autoWrap()) || !!titleWrap.wrap;
|
||||
};
|
||||
|
||||
export const apply = function(param) {
|
||||
@@ -355,20 +282,17 @@ export default {
|
||||
addActor,
|
||||
addMessage,
|
||||
addSignal,
|
||||
enableWrap,
|
||||
disableWrap,
|
||||
autoWrap,
|
||||
setWrap,
|
||||
enableSequenceNumbers,
|
||||
showSequenceNumbers,
|
||||
autoWrap,
|
||||
getMessages,
|
||||
getActors,
|
||||
getActor,
|
||||
getActorKeys,
|
||||
getTitle,
|
||||
parseDirective,
|
||||
hasConfigChange,
|
||||
getConfig,
|
||||
updateConfig,
|
||||
getConfig: () => configApi.getConfig().sequence,
|
||||
getTitleWrapped,
|
||||
clear,
|
||||
parseMessage,
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
100
src/diagrams/sequence/styles.js
Normal file
100
src/diagrams/sequence/styles.js
Normal file
@@ -0,0 +1,100 @@
|
||||
const getStyles = options =>
|
||||
`.actor {
|
||||
stroke: ${options.actorBorder};
|
||||
fill: ${options.actorBkg};
|
||||
}
|
||||
|
||||
text.actor > tspan {
|
||||
fill: ${options.actorTextColor};
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.actor-line {
|
||||
stroke: ${options.actorLineColor};
|
||||
}
|
||||
|
||||
.messageLine0 {
|
||||
stroke-width: 1.5;
|
||||
stroke-dasharray: none;
|
||||
stroke: ${options.signalColor};
|
||||
}
|
||||
|
||||
.messageLine1 {
|
||||
stroke-width: 1.5;
|
||||
stroke-dasharray: 2, 2;
|
||||
stroke: ${options.signalColor};
|
||||
}
|
||||
|
||||
#arrowhead path {
|
||||
fill: ${options.signalColor};
|
||||
stroke: ${options.signalColor};
|
||||
}
|
||||
|
||||
.sequenceNumber {
|
||||
fill: ${options.sequenceNumberColor};
|
||||
}
|
||||
|
||||
#sequencenumber {
|
||||
fill: ${options.signalColor};
|
||||
}
|
||||
|
||||
#crosshead path {
|
||||
fill: ${options.signalColor};
|
||||
stroke: ${options.signalColor};
|
||||
}
|
||||
|
||||
.messageText {
|
||||
fill: ${options.signalTextColor};
|
||||
stroke: ${options.signalTextColor};
|
||||
}
|
||||
|
||||
.labelBox {
|
||||
stroke: ${options.labelBoxBorderColor};
|
||||
fill: ${options.labelBoxBkgColor};
|
||||
}
|
||||
|
||||
.labelText, .labelText > tspan {
|
||||
fill: ${options.labelTextColor};
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.loopText, .loopText > tspan {
|
||||
fill: ${options.loopTextColor};
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.loopLine {
|
||||
stroke-width: 2px;
|
||||
stroke-dasharray: 2, 2;
|
||||
stroke: ${options.labelBoxBorderColor};
|
||||
fill: ${options.labelBoxBorderColor};
|
||||
}
|
||||
|
||||
.note {
|
||||
//stroke: #decc93;
|
||||
stroke: ${options.noteBorderColor};
|
||||
fill: ${options.noteBkgColor};
|
||||
}
|
||||
|
||||
.noteText, .noteText > tspan {
|
||||
fill: ${options.noteTextColor};
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.activation0 {
|
||||
fill: ${options.activationBkgColor};
|
||||
stroke: ${options.activationBorderColor};
|
||||
}
|
||||
|
||||
.activation1 {
|
||||
fill: ${options.activationBkgColor};
|
||||
stroke: ${options.activationBorderColor};
|
||||
}
|
||||
|
||||
.activation2 {
|
||||
fill: ${options.activationBkgColor};
|
||||
stroke: ${options.activationBorderColor};
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -19,27 +19,133 @@ export const drawRect = function(elem, rectData) {
|
||||
};
|
||||
|
||||
export const drawText = function(elem, textData) {
|
||||
// Remove and ignore br:s
|
||||
const nText = textData.text.replace(common.lineBreakRegex, ' ');
|
||||
let prevTextHeight = 0,
|
||||
textHeight = 0;
|
||||
const lines = textData.wrap
|
||||
? textData.text.split(common.lineBreakRegex)
|
||||
: [textData.text.replace(common.lineBreakRegex, ' ')];
|
||||
|
||||
const textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
textElem.style('font-family', textData.fontFamily);
|
||||
textElem.style('font-size', textData.fontSize);
|
||||
textElem.style('font-weight', textData.fontWeight);
|
||||
textElem.attr('fill', textData.fill);
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
textElem.attr('class', textData.class);
|
||||
let textElems = [];
|
||||
let dy = 0;
|
||||
let yfunc = () => textData.y;
|
||||
if (
|
||||
typeof textData.valign !== 'undefined' &&
|
||||
typeof textData.textMargin !== 'undefined' &&
|
||||
textData.textMargin > 0
|
||||
) {
|
||||
switch (textData.valign) {
|
||||
case 'top':
|
||||
case 'start':
|
||||
yfunc = () => Math.round(textData.y + textData.textMargin);
|
||||
break;
|
||||
case 'middle':
|
||||
case 'center':
|
||||
yfunc = () =>
|
||||
Math.round(textData.y + (prevTextHeight + textHeight + textData.textMargin) / 2);
|
||||
break;
|
||||
case 'bottom':
|
||||
case 'end':
|
||||
yfunc = () =>
|
||||
Math.round(
|
||||
textData.y +
|
||||
(prevTextHeight + textHeight + 2 * textData.textMargin) -
|
||||
textData.textMargin
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (
|
||||
typeof textData.anchor !== 'undefined' &&
|
||||
typeof textData.textMargin !== 'undefined' &&
|
||||
typeof textData.width !== 'undefined'
|
||||
) {
|
||||
switch (textData.anchor) {
|
||||
case 'left':
|
||||
case 'start':
|
||||
textData.x = Math.round(textData.x + textData.textMargin);
|
||||
textData.anchor = 'start';
|
||||
textData.dominantBaseline = 'text-after-edge';
|
||||
textData.alignmentBaseline = 'middle';
|
||||
break;
|
||||
case 'middle':
|
||||
case 'center':
|
||||
textData.x = Math.round(textData.x + textData.width / 2);
|
||||
textData.anchor = 'middle';
|
||||
textData.dominantBaseline = 'middle';
|
||||
textData.alignmentBaseline = 'middle';
|
||||
break;
|
||||
case 'right':
|
||||
case 'end':
|
||||
textData.x = Math.round(textData.x + textData.width - textData.textMargin);
|
||||
textData.anchor = 'end';
|
||||
textData.dominantBaseline = 'text-before-edge';
|
||||
textData.alignmentBaseline = 'middle';
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i];
|
||||
if (
|
||||
typeof textData.textMargin !== 'undefined' &&
|
||||
textData.textMargin === 0 &&
|
||||
typeof textData.fontSize !== 'undefined'
|
||||
) {
|
||||
dy = i * textData.fontSize;
|
||||
}
|
||||
|
||||
const textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', yfunc());
|
||||
if (typeof textData.anchor !== 'undefined') {
|
||||
textElem
|
||||
.attr('text-anchor', textData.anchor)
|
||||
.attr('dominant-baseline', textData.dominantBaseline)
|
||||
.attr('alignment-baseline', textData.alignmentBaseline);
|
||||
}
|
||||
if (typeof textData.fontFamily !== 'undefined') {
|
||||
textElem.style('font-family', textData.fontFamily);
|
||||
}
|
||||
if (typeof textData.fontSize !== 'undefined') {
|
||||
textElem.style('font-size', textData.fontSize);
|
||||
}
|
||||
if (typeof textData.fontWeight !== 'undefined') {
|
||||
textElem.style('font-weight', textData.fontWeight);
|
||||
}
|
||||
if (typeof textData.fill !== 'undefined') {
|
||||
textElem.attr('fill', textData.fill);
|
||||
}
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
textElem.attr('class', textData.class);
|
||||
}
|
||||
if (typeof textData.dy !== 'undefined') {
|
||||
textElem.attr('dy', textData.dy);
|
||||
} else if (dy !== 0) {
|
||||
textElem.attr('dy', dy);
|
||||
}
|
||||
|
||||
if (textData.tspan) {
|
||||
const span = textElem.append('tspan');
|
||||
span.attr('x', textData.x);
|
||||
if (typeof textData.fill !== 'undefined') {
|
||||
span.attr('fill', textData.fill);
|
||||
}
|
||||
span.text(line);
|
||||
} else {
|
||||
textElem.text(line);
|
||||
}
|
||||
if (
|
||||
typeof textData.valign !== 'undefined' &&
|
||||
typeof textData.textMargin !== 'undefined' &&
|
||||
textData.textMargin > 0
|
||||
) {
|
||||
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
|
||||
prevTextHeight = textHeight;
|
||||
}
|
||||
|
||||
textElems.push(textElem);
|
||||
}
|
||||
|
||||
const span = textElem.append('tspan');
|
||||
span.attr('x', textData.x + textData.textMargin * 2);
|
||||
span.attr('fill', textData.fill);
|
||||
span.text(nText);
|
||||
|
||||
return textElem;
|
||||
return textElems;
|
||||
};
|
||||
|
||||
export const drawLabel = function(elem, txtObject) {
|
||||
@@ -67,17 +173,18 @@ export const drawLabel = function(elem, txtObject) {
|
||||
);
|
||||
}
|
||||
const polygon = elem.append('polygon');
|
||||
polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7));
|
||||
polygon.attr('points', genPoints(txtObject.x, txtObject.y, txtObject.width, txtObject.height, 7));
|
||||
polygon.attr('class', 'labelBox');
|
||||
|
||||
txtObject.y = txtObject.y + txtObject.labelMargin;
|
||||
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin;
|
||||
txtObject.y = txtObject.y + txtObject.height / 2;
|
||||
|
||||
drawText(elem, txtObject);
|
||||
return polygon;
|
||||
};
|
||||
|
||||
let actorCnt = -1;
|
||||
/**
|
||||
* Draws an actor in the diagram with the attaced line
|
||||
* Draws an actor in the diagram with the attached line
|
||||
* @param elem - The diagram we'll draw to.
|
||||
* @param actor - The actor to draw.
|
||||
* @param conf - drawText implementation discriminator object
|
||||
@@ -147,11 +254,20 @@ export const drawActivation = function(elem, bounds, verticalPos, conf, actorAct
|
||||
/**
|
||||
* Draws a loop in the diagram
|
||||
* @param elem - elemenet to append the loop to.
|
||||
* @param bounds - bounds of the given loop.
|
||||
* @param loopModel - loopModel of the given loop.
|
||||
* @param labelText - Text within the loop.
|
||||
* @param conf
|
||||
* @param conf - diagrom configuration
|
||||
*/
|
||||
export const drawLoop = function(elem, bounds, labelText, conf) {
|
||||
export const drawLoop = function(elem, loopModel, labelText, conf) {
|
||||
const {
|
||||
boxMargin,
|
||||
boxTextMargin,
|
||||
labelBoxHeight,
|
||||
labelBoxWidth,
|
||||
messageFontFamily: fontFamily,
|
||||
messageFontSize: fontSize,
|
||||
messageFontWeight: fontWeight
|
||||
} = conf;
|
||||
const g = elem.append('g');
|
||||
const drawLoopLine = function(startx, starty, stopx, stopy) {
|
||||
return g
|
||||
@@ -162,56 +278,77 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
|
||||
.attr('y2', stopy)
|
||||
.attr('class', 'loopLine');
|
||||
};
|
||||
drawLoopLine(bounds.startx, bounds.starty, bounds.stopx, bounds.starty);
|
||||
drawLoopLine(bounds.stopx, bounds.starty, bounds.stopx, bounds.stopy);
|
||||
drawLoopLine(bounds.startx, bounds.stopy, bounds.stopx, bounds.stopy);
|
||||
drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy);
|
||||
if (typeof bounds.sections !== 'undefined') {
|
||||
bounds.sections.forEach(function(item) {
|
||||
drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3');
|
||||
drawLoopLine(loopModel.startx, loopModel.starty, loopModel.stopx, loopModel.starty);
|
||||
drawLoopLine(loopModel.stopx, loopModel.starty, loopModel.stopx, loopModel.stopy);
|
||||
drawLoopLine(loopModel.startx, loopModel.stopy, loopModel.stopx, loopModel.stopy);
|
||||
drawLoopLine(loopModel.startx, loopModel.starty, loopModel.startx, loopModel.stopy);
|
||||
if (typeof loopModel.sections !== 'undefined') {
|
||||
loopModel.sections.forEach(function(item) {
|
||||
drawLoopLine(loopModel.startx, item.y, loopModel.stopx, item.y).style(
|
||||
'stroke-dasharray',
|
||||
'3, 3'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
let minSize =
|
||||
Math.round((3 * conf.fontSize) / 4) < 10 ? conf.fontSize : Math.round((3 * conf.fontSize) / 4);
|
||||
|
||||
let txt = getTextObj();
|
||||
txt.text = labelText;
|
||||
txt.x = bounds.startx;
|
||||
txt.y = bounds.starty;
|
||||
txt.labelMargin = 1.5 * 10; // This is the small box that says "loop"
|
||||
txt.fontFamily = conf.fontFamily;
|
||||
txt.fontSize = minSize;
|
||||
txt.fontWeight = conf.fontWeight;
|
||||
txt.class = 'labelText'; // Its size & position are fixed.
|
||||
txt.x = loopModel.startx;
|
||||
txt.y = loopModel.starty;
|
||||
txt.fontFamily = fontFamily;
|
||||
txt.fontSize = fontSize;
|
||||
txt.fontWeight = fontWeight;
|
||||
txt.anchor = 'middle';
|
||||
txt.valign = 'middle';
|
||||
txt.tspan = false;
|
||||
txt.width = labelBoxWidth || 50;
|
||||
txt.height = labelBoxHeight || 20;
|
||||
txt.textMargin = boxTextMargin;
|
||||
txt.class = 'labelText';
|
||||
|
||||
drawLabel(g, txt);
|
||||
|
||||
txt = getTextObj();
|
||||
txt.text = '[ ' + bounds.title + ' ]';
|
||||
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
|
||||
txt.y = bounds.starty + 1.5 * conf.boxMargin;
|
||||
txt.text = loopModel.title;
|
||||
txt.x = loopModel.startx + labelBoxWidth / 2 + (loopModel.stopx - loopModel.startx) / 2;
|
||||
txt.y = loopModel.starty + boxMargin + boxTextMargin;
|
||||
txt.anchor = 'middle';
|
||||
txt.valign = 'middle';
|
||||
txt.textMargin = boxTextMargin;
|
||||
txt.class = 'loopText';
|
||||
txt.fontFamily = conf.fontFamily;
|
||||
txt.fontSize = minSize;
|
||||
txt.fontWeight = conf.fontWeight;
|
||||
txt.fontFamily = fontFamily;
|
||||
txt.fontSize = fontSize;
|
||||
txt.fontWeight = fontWeight;
|
||||
txt.wrap = true;
|
||||
|
||||
let textElem = drawText(g, txt);
|
||||
let textHeight = (textElem._groups || textElem)[0][0].getBBox().height;
|
||||
|
||||
if (typeof bounds.sectionTitles !== 'undefined') {
|
||||
bounds.sectionTitles.forEach(function(item, idx) {
|
||||
if (item !== '') {
|
||||
txt.text = '[ ' + item + ' ]';
|
||||
txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin;
|
||||
if (typeof loopModel.sectionTitles !== 'undefined') {
|
||||
loopModel.sectionTitles.forEach(function(item, idx) {
|
||||
if (item.message) {
|
||||
txt.text = item.message;
|
||||
txt.x = loopModel.startx + (loopModel.stopx - loopModel.startx) / 2;
|
||||
txt.y = loopModel.sections[idx].y + boxMargin + boxTextMargin;
|
||||
txt.class = 'loopText';
|
||||
txt.anchor = 'middle';
|
||||
txt.valign = 'middle';
|
||||
txt.tspan = false;
|
||||
txt.fontFamily = fontFamily;
|
||||
txt.fontSize = fontSize;
|
||||
txt.fontWeight = fontWeight;
|
||||
txt.wrap = loopModel.wrap;
|
||||
textElem = drawText(g, txt);
|
||||
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
|
||||
let sectionHeight = Math.round(
|
||||
textElem
|
||||
.map(te => (te._groups || te)[0][0].getBBox().height)
|
||||
.reduce((acc, curr) => acc + curr)
|
||||
);
|
||||
loopModel.sections[idx].height += sectionHeight - (boxMargin + boxTextMargin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return textHeight + 4;
|
||||
loopModel.height = Math.round(loopModel.stopy - loopModel.starty);
|
||||
return g;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -300,23 +437,24 @@ export const insertArrowCrossHead = function(elem) {
|
||||
};
|
||||
|
||||
export const getTextObj = function() {
|
||||
const txt = {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
fill: undefined,
|
||||
'text-anchor': 'start',
|
||||
anchor: undefined,
|
||||
style: '#666',
|
||||
width: 100,
|
||||
height: 100,
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
textMargin: 0,
|
||||
rx: 0,
|
||||
ry: 0
|
||||
ry: 0,
|
||||
tspan: true,
|
||||
valign: undefined
|
||||
};
|
||||
return txt;
|
||||
};
|
||||
|
||||
export const getNoteRect = function() {
|
||||
const rect = {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
fill: '#EDF2AE',
|
||||
@@ -327,7 +465,6 @@ export const getNoteRect = function() {
|
||||
rx: 0,
|
||||
ry: 0
|
||||
};
|
||||
return rect;
|
||||
};
|
||||
|
||||
const _drawTextCandidateFunc = (function() {
|
||||
|
164
src/diagrams/state/styles.js
Normal file
164
src/diagrams/state/styles.js
Normal file
@@ -0,0 +1,164 @@
|
||||
const getStyles = options =>
|
||||
`g.stateGroup text {
|
||||
fill: ${options.nodeBorder};
|
||||
stroke: none;
|
||||
font-size: 10px;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
}
|
||||
g.stateGroup text {
|
||||
fill: ${options.textColor};
|
||||
stroke: none;
|
||||
font-size: 10px;
|
||||
|
||||
}
|
||||
g.stateGroup .state-title {
|
||||
font-weight: bolder;
|
||||
fill: ${options.labelColor};
|
||||
}
|
||||
|
||||
g.stateGroup rect {
|
||||
fill: ${options.nodeBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
}
|
||||
|
||||
g.stateGroup line {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.transition {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.stateGroup .composit {
|
||||
fill: ${options.background};
|
||||
border-bottom: 1px
|
||||
}
|
||||
|
||||
.stateGroup .alt-composit {
|
||||
fill: #e0e0e0;
|
||||
border-bottom: 1px
|
||||
}
|
||||
|
||||
.state-note {
|
||||
stroke: ${options.noteBorderColor};
|
||||
fill: ${options.noteBkgColor};
|
||||
|
||||
text {
|
||||
fill: black;
|
||||
stroke: none;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.stateLabel .box {
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
fill: ${options.nodeBkg};
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.stateLabel text {
|
||||
fill: ${options.labelColor};
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
}
|
||||
|
||||
.node circle.state-start {
|
||||
fill: black;
|
||||
stroke: black;
|
||||
}
|
||||
.node circle.state-end {
|
||||
fill: black;
|
||||
stroke: white;
|
||||
stroke-width: 1.5
|
||||
}
|
||||
|
||||
.node rect {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
#statediagram-barbEnd {
|
||||
fill: ${options.lineColor};
|
||||
}
|
||||
|
||||
.statediagram-cluster rect {
|
||||
fill: ${options.nodeBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.cluster-label, .nodeLabel {
|
||||
color: ${options.textColor};
|
||||
}
|
||||
|
||||
.statediagram-cluster rect.outer {
|
||||
rx: 5px;
|
||||
ry: 5px;
|
||||
}
|
||||
.statediagram-state .divider {
|
||||
stroke: ${options.nodeBorder};
|
||||
}
|
||||
|
||||
.statediagram-state .title-state {
|
||||
rx: 5px;
|
||||
ry: 5px;
|
||||
}
|
||||
.statediagram-cluster.statediagram-cluster .inner {
|
||||
fill: ${options.background};
|
||||
}
|
||||
.statediagram-cluster.statediagram-cluster-alt .inner {
|
||||
fill: #e0e0e0;
|
||||
}
|
||||
|
||||
.statediagram-cluster .inner {
|
||||
rx:0;
|
||||
ry:0;
|
||||
}
|
||||
|
||||
.statediagram-state rect.basic {
|
||||
rx: 5px;
|
||||
ry: 5px;
|
||||
}
|
||||
.statediagram-state rect.divider {
|
||||
stroke-dasharray: 10,10;
|
||||
fill: ${options.altBackground ? options.altBackground : '#efefef'};
|
||||
}
|
||||
|
||||
.note-edge {
|
||||
stroke-dasharray: 5;
|
||||
}
|
||||
|
||||
.statediagram-note rect {
|
||||
fill: ${options.noteBkgColor};
|
||||
stroke: ${options.noteBorderColor};
|
||||
stroke-width: 1px;
|
||||
rx: 0;
|
||||
ry: 0;
|
||||
}
|
||||
.statediagram-note rect {
|
||||
fill: ${options.noteBkgColor};
|
||||
stroke: ${options.noteBorderColor};
|
||||
stroke-width: 1px;
|
||||
rx: 0;
|
||||
ry: 0;
|
||||
}
|
||||
|
||||
.statediagram-note .nodeLabel {
|
||||
color: ${options.noteTextColor};
|
||||
}
|
||||
|
||||
#dependencyStart, #dependencyEnd {
|
||||
fill: ${options.lineColor};
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -232,12 +232,14 @@ export const drawTasks = function(diagram, tasks, verticalPos) {
|
||||
let sectionNumber = 0;
|
||||
let fill = '#CCC';
|
||||
let colour = 'black';
|
||||
let num = 0;
|
||||
|
||||
// Draw the tasks
|
||||
for (let i = 0; i < tasks.length; i++) {
|
||||
let task = tasks[i];
|
||||
if (lastSection !== task.section) {
|
||||
fill = fills[sectionNumber % fills.length];
|
||||
num = sectionNumber % fills.length;
|
||||
colour = textColours[sectionNumber % textColours.length];
|
||||
|
||||
const section = {
|
||||
@@ -245,6 +247,7 @@ export const drawTasks = function(diagram, tasks, verticalPos) {
|
||||
y: 50,
|
||||
text: task.section,
|
||||
fill,
|
||||
num,
|
||||
colour
|
||||
};
|
||||
|
||||
@@ -269,6 +272,7 @@ export const drawTasks = function(diagram, tasks, verticalPos) {
|
||||
task.height = conf.diagramMarginY;
|
||||
task.colour = colour;
|
||||
task.fill = fill;
|
||||
task.num = num;
|
||||
task.actors = taskActors;
|
||||
|
||||
// Draw the box with the attached line
|
||||
|
121
src/diagrams/user-journey/styles.js
Normal file
121
src/diagrams/user-journey/styles.js
Normal file
@@ -0,0 +1,121 @@
|
||||
const getStyles = options =>
|
||||
`.label {
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
color: ${options.textColor};
|
||||
}
|
||||
.mouth {
|
||||
stroke: #666;
|
||||
}
|
||||
|
||||
line {
|
||||
stroke: ${options.textColor}
|
||||
}
|
||||
|
||||
.legend {
|
||||
fill: ${options.textColor};
|
||||
}
|
||||
|
||||
.label text {
|
||||
fill: #333;
|
||||
}
|
||||
.label {
|
||||
color: ${options.textColor}
|
||||
}
|
||||
|
||||
.face {
|
||||
fill: #FFF8DC;
|
||||
stroke: #999;
|
||||
}
|
||||
|
||||
.node rect,
|
||||
.node circle,
|
||||
.node ellipse,
|
||||
.node polygon,
|
||||
.node path {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.node .label {
|
||||
text-align: center;
|
||||
}
|
||||
.node.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.arrowheadPath {
|
||||
fill: ${options.arrowheadColor};
|
||||
}
|
||||
|
||||
.edgePath .path {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.flowchart-link {
|
||||
stroke: ${options.lineColor};
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.edgeLabel {
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
rect {
|
||||
opacity: 0.5;
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cluster rect {
|
||||
fill: ${options.secondBkg};
|
||||
stroke: ${options.clusterBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.cluster text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
div.mermaidTooltip {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 200px;
|
||||
padding: 2px;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
font-size: 12px;
|
||||
background: ${options.secondBkg};
|
||||
border: 1px solid ${options.border2};
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.task-type-0, .section-type-0 {
|
||||
${options.fillType0 ? `fill: ${options.fillType0}` : ''};
|
||||
}
|
||||
.task-type-1, .section-type-1 {
|
||||
${options.fillType0 ? `fill: ${options.fillType1}` : ''};
|
||||
}
|
||||
.task-type-2, .section-type-2 {
|
||||
${options.fillType0 ? `fill: ${options.fillType2}` : ''};
|
||||
}
|
||||
.task-type-3, .section-type-3 {
|
||||
${options.fillType0 ? `fill: ${options.fillType3}` : ''};
|
||||
}
|
||||
.task-type-4, .section-type-4 {
|
||||
${options.fillType0 ? `fill: ${options.fillType4}` : ''};
|
||||
}
|
||||
.task-type-5, .section-type-5 {
|
||||
${options.fillType0 ? `fill: ${options.fillType5}` : ''};
|
||||
}
|
||||
.task-type-6, .section-type-6 {
|
||||
${options.fillType0 ? `fill: ${options.fillType6}` : ''};
|
||||
}
|
||||
.task-type-7, .section-type-7 {
|
||||
${options.fillType0 ? `fill: ${options.fillType7}` : ''};
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -24,8 +24,7 @@ export const drawFace = function(element, faceData) {
|
||||
.append('circle')
|
||||
.attr('cx', faceData.cx)
|
||||
.attr('cy', faceData.cy)
|
||||
.attr('fill', '#FFF8DC')
|
||||
.attr('stroke', '#999')
|
||||
.attr('class', 'face')
|
||||
.attr('r', radius)
|
||||
.attr('stroke-width', 2)
|
||||
.attr('overflow', 'visible');
|
||||
@@ -61,6 +60,7 @@ export const drawFace = function(element, faceData) {
|
||||
//mouth
|
||||
face
|
||||
.append('path')
|
||||
.attr('class', 'mouth')
|
||||
.attr('d', arc)
|
||||
.attr('transform', 'translate(' + faceData.cx + ',' + (faceData.cy + 2) + ')');
|
||||
}
|
||||
@@ -74,6 +74,7 @@ export const drawFace = function(element, faceData) {
|
||||
//mouth
|
||||
face
|
||||
.append('path')
|
||||
.attr('class', 'mouth')
|
||||
.attr('d', arc)
|
||||
.attr('transform', 'translate(' + faceData.cx + ',' + (faceData.cy + 7) + ')');
|
||||
}
|
||||
@@ -81,12 +82,13 @@ export const drawFace = function(element, faceData) {
|
||||
function ambivalent(face) {
|
||||
face
|
||||
.append('line')
|
||||
.attr('class', 'mouth')
|
||||
.attr('stroke', 2)
|
||||
.attr('x1', faceData.cx - 5)
|
||||
.attr('y1', faceData.cy + 7)
|
||||
.attr('x2', faceData.cx + 5)
|
||||
.attr('y2', faceData.cy + 7)
|
||||
.attr('class', 'task-line')
|
||||
.attr('class', 'mouth')
|
||||
.attr('stroke-width', '1px')
|
||||
.attr('stroke', '#666');
|
||||
}
|
||||
@@ -128,7 +130,8 @@ export const drawText = function(elem, textData) {
|
||||
const textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.attr('fill', textData.fill);
|
||||
textElem.attr('class', 'legend');
|
||||
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
@@ -184,7 +187,7 @@ export const drawSection = function(elem, section, conf) {
|
||||
rect.fill = section.fill;
|
||||
rect.width = conf.width;
|
||||
rect.height = conf.height;
|
||||
rect.class = 'journey-section';
|
||||
rect.class = 'journey-section section-type-' + section.num;
|
||||
rect.rx = 3;
|
||||
rect.ry = 3;
|
||||
drawRect(g, rect);
|
||||
@@ -196,7 +199,7 @@ export const drawSection = function(elem, section, conf) {
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height,
|
||||
{ class: 'journey-section' },
|
||||
{ class: 'journey-section section-type-' + section.num },
|
||||
conf,
|
||||
section.colour
|
||||
);
|
||||
@@ -237,7 +240,7 @@ export const drawTask = function(elem, task, conf) {
|
||||
rect.fill = task.fill;
|
||||
rect.width = conf.width;
|
||||
rect.height = conf.height;
|
||||
rect.class = 'task';
|
||||
rect.class = 'task task-type-' + task.num;
|
||||
rect.rx = 3;
|
||||
rect.ry = 3;
|
||||
drawRect(g, rect);
|
||||
@@ -356,7 +359,7 @@ const _drawTextCandidateFunc = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function byFo(content, g, x, y, width, height, textAttrs, conf, colour) {
|
||||
function byFo(content, g, x, y, width, height, textAttrs, conf) {
|
||||
const body = g.append('switch');
|
||||
const f = body
|
||||
.append('foreignObject')
|
||||
@@ -374,10 +377,11 @@ const _drawTextCandidateFunc = (function() {
|
||||
|
||||
text
|
||||
.append('div')
|
||||
.attr('class', 'label')
|
||||
.style('display', 'table-cell')
|
||||
.style('text-align', 'center')
|
||||
.style('vertical-align', 'middle')
|
||||
.style('color', colour)
|
||||
// .style('color', colour)
|
||||
.text(content);
|
||||
|
||||
byTspan(content, body, x, y, width, height, textAttrs, conf);
|
||||
|
Reference in New Issue
Block a user