Merge branch 'develop' into feature/Issue-1465_Class_migration

This commit is contained in:
Ashish Jain
2020-07-22 18:23:47 +02:00
100 changed files with 326089 additions and 6581 deletions

View 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;

View File

@@ -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, '&lt;').replace(/>/g, '&gt;');
txt = txt.replace(/=/g, '&equals;');
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, '&lt;').replace(/>/g, '&gt;');
txt = txt.replace(/=/g, '&equals;');
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
};

View 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);
});
});

View File

@@ -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
View 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;

View File

@@ -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') {

View File

@@ -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;

View File

@@ -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;

View 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;

View File

@@ -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') {

View File

@@ -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');

View File

@@ -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;

View 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;

View File

@@ -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) {

View File

@@ -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

View 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;

View File

@@ -0,0 +1,3 @@
const getStyles = () => ``;
export default getStyles;

View 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;

View File

@@ -230,7 +230,7 @@ argDirective
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive'); }
: close_directive { yy.parseDirective('}%%', 'close_directive', 'sequence'); }
;
%%

View File

@@ -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

View 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;

View File

@@ -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() {

View 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;

View File

@@ -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

View 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;

View File

@@ -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);