Merge branch 'develop' into feature/1295_generic_rendering_engine

This commit is contained in:
Knut Sveidqvist
2020-04-11 18:53:47 +02:00
22 changed files with 275 additions and 29 deletions

View File

@@ -154,6 +154,28 @@ function stadium(parent, bbox, node) {
return shapeSvg;
}
function subroutine(parent, bbox, node) {
const w = bbox.width;
const h = bbox.height;
const points = [
{ x: 0, y: 0 },
{ x: w, y: 0 },
{ x: w, y: -h },
{ x: 0, y: -h },
{ x: 0, y: 0 },
{ x: -8, y: 0 },
{ x: w + 8, y: 0 },
{ x: w + 8, y: -h },
{ x: -8, y: -h },
{ x: -8, y: 0 }
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function(point) {
return dagreD3.intersect.polygon(node, points, point);
};
return shapeSvg;
}
function cylinder(parent, bbox, node) {
const w = bbox.width;
const rx = w / 2;
@@ -221,6 +243,7 @@ export function addToRender(render) {
render.shapes().question = question;
render.shapes().hexagon = hexagon;
render.shapes().stadium = stadium;
render.shapes().subroutine = subroutine;
render.shapes().cylinder = cylinder;
// Add custom shape for box with inverted arrow on left side
@@ -246,6 +269,7 @@ export function addToRenderV2(addShape) {
addShape({ question });
addShape({ hexagon });
addShape({ stadium });
addShape({ subroutine });
addShape({ cylinder });
// Add custom shape for box with inverted arrow on left side

View File

@@ -65,7 +65,8 @@ describe('flowchart shapes', function() {
['lean_right', 4, useWidth, useHeight],
['lean_left', 4, useWidth, useHeight],
['trapezoid', 4, useWidth, useHeight],
['inv_trapezoid', 4, useWidth, useHeight]
['inv_trapezoid', 4, useWidth, useHeight],
['subroutine', 10, useWidth, useHeight],
].forEach(function([shapeType, expectedPointCount, getW, getH]) {
it(`should add a ${shapeType} shape that renders a properly translated polygon element`, function() {
const mockRender = MockRender();

View File

@@ -119,6 +119,9 @@ export const addVertices = function(vert, g, svgId) {
case 'stadium':
_shape = 'stadium';
break;
case 'subroutine':
_shape = 'subroutine';
break;
case 'cylinder':
_shape = 'cylinder';
break;

View File

@@ -119,6 +119,9 @@ export const addVertices = function(vert, g, svgId) {
case 'stadium':
_shape = 'stadium';
break;
case 'subroutine':
_shape = 'subroutine';
break;
case 'cylinder':
_shape = 'cylinder';
break;
@@ -380,10 +383,6 @@ export const draw = function(text, id) {
const svgBounds = svg.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
logger.debug(
`new ViewBox 0 0 ${width} ${height}`,
`translate(${padding - g._label.marginx}, ${padding - g._label.marginy})`
);
if (conf.useMaxWidth) {
svg.attr('width', '100%');
@@ -393,10 +392,10 @@ export const draw = function(text, id) {
svg.attr('width', width);
}
svg.attr('viewBox', `0 0 ${width} ${height}`);
svg
.select('g')
.attr('transform', `translate(${padding - g._label.marginx}, ${padding - svgBounds.y})`);
// Ensure the viewBox includes the whole svgBounds area with extra space for padding
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
logger.debug(`viewBox ${vBox}`);
svg.attr('viewBox', vBox);
// Index nodes
flowDb.indexNodes('subGraph' + i);

View File

@@ -23,6 +23,7 @@ describe('the flowchart renderer', function() {
['circle', 'circle'],
['ellipse', 'ellipse'],
['stadium', 'stadium'],
['subroutine', 'subroutine'],
['cylinder', 'cylinder'],
['group', 'rect']
].forEach(function([type, expectedShape, expectedRadios = 0]) {

View File

@@ -87,6 +87,8 @@
"-)" return '-)';
"([" return 'STADIUMSTART';
"])" return 'STADIUMEND';
"[[" return 'SUBROUTINESTART';
"]]" return 'SUBROUTINEEND';
"[(" return 'CYLINDERSTART';
")]" return 'CYLINDEREND';
\- return 'MINUS';
@@ -316,6 +318,8 @@ vertex: idString SQS text SQE
{$$ = $1;yy.addVertex($1,$3,'ellipse');}
| idString STADIUMSTART text STADIUMEND
{$$ = $1;yy.addVertex($1,$3,'stadium');}
| idString SUBROUTINESTART text SUBROUTINEEND
{$$ = $1;yy.addVertex($1,$3,'subroutine');}
| idString CYLINDERSTART text CYLINDEREND
{$$ = $1;yy.addVertex($1,$3,'cylinder');}
| idString PS text PE
@@ -474,5 +478,5 @@ alphaNumToken : PUNCTUATION | AMP | UNICODE_TEXT | NUM| ALPHA | COLON | COMMA |
idStringToken : ALPHA|UNDERSCORE |UNICODE_TEXT | NUM| COLON | COMMA | PLUS | MINUS | DOWN |EQUALS | MULT | BRKT | DOT | PUNCTUATION | AMP;
graphCodeTokens: STADIUMSTART | STADIUMEND | CYLINDERSTART | CYLINDEREND | TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI;
graphCodeTokens: STADIUMSTART | STADIUMEND | SUBROUTINESTART | SUBROUTINEEND | CYLINDERSTART | CYLINDEREND | TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI;
%%

View File

@@ -6,6 +6,7 @@ import { getConfig } from '../../config';
const config = getConfig();
let dateFormat = '';
let axisFormat = '';
let todayMarker = '';
let excludes = [];
let title = '';
let sections = [];
@@ -27,6 +28,7 @@ export const clear = function() {
rawTasks = [];
dateFormat = '';
axisFormat = '';
todayMarker = '';
excludes = [];
inclusiveEndDates = false;
};
@@ -39,6 +41,14 @@ export const getAxisFormat = function() {
return axisFormat;
};
export const setTodayMarker = function(txt) {
todayMarker = txt;
};
export const getTodayMarker = function() {
return todayMarker;
};
export const setDateFormat = function(txt) {
dateFormat = txt;
};
@@ -572,6 +582,8 @@ export default {
endDatesAreInclusive,
setAxisFormat,
getAxisFormat,
setTodayMarker,
getTodayMarker,
setTitle,
getTitle,
addSection,

View File

@@ -21,6 +21,7 @@ describe('when using the ganttDb', function() {
beforeEach(function() {
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.enableInclusiveEndDates();
ganttDb.setTodayMarker('off');
ganttDb.setExcludes('weekends 2019-02-06,friday');
ganttDb.addSection('weekends skip test');
ganttDb.addTask('test1', 'id1,2019-02-01,1d');
@@ -34,6 +35,7 @@ describe('when using the ganttDb', function() {
${'getTitle'} | ${''}
${'getDateFormat'} | ${''}
${'getAxisFormat'} | ${''}
${'getTodayMarker'} | ${''}
${'getExcludes'} | ${[]}
${'getSections'} | ${[]}
${'endDatesAreInclusive'} | ${false}
@@ -216,4 +218,13 @@ describe('when using the ganttDb', function() {
expect(tasks[1].task).toEqual('test2');
});
});
it.each`
type | expected
${'hide'} | ${'off'}
${'style'} | ${'stoke:stroke-width:5px,stroke:#00f,opacity:0.5'}
`('should ${type} today marker', ({ expected }) => {
ganttDb.setTodayMarker(expected);
expect(ganttDb.getTodayMarker()).toEqual(expected);
});
});

View File

@@ -396,17 +396,25 @@ export const draw = function(text, id) {
}
function drawToday(theSidePad, theTopPad, w, h) {
const todayMarker = ganttDb.getTodayMarker();
if (todayMarker === 'off') {
return;
}
const todayG = svg.append('g').attr('class', 'today');
const today = new Date();
const todayLine = todayG.append('line');
todayG
.append('line')
todayLine
.attr('x1', timeScale(today) + theSidePad)
.attr('x2', timeScale(today) + theSidePad)
.attr('y1', conf.titleTopMargin)
.attr('y2', h - conf.titleTopMargin)
.attr('class', 'today');
if (todayMarker !== '') {
todayLine.attr('style', todayMarker.replace(/,/g, ';'));
}
}
// from this stackexchange question: http://stackoverflow.com/questions/1890203/unique-for-arrays-in-javascript

View File

@@ -55,13 +55,14 @@ that id.
"gantt" return 'gantt';
"dateFormat"\s[^#\n;]+ return 'dateFormat';
"inclusiveEndDates" return 'inclusiveEndDates';
"inclusiveEndDates" return 'inclusiveEndDates';
"axisFormat"\s[^#\n;]+ return 'axisFormat';
"excludes"\s[^#\n;]+ return 'excludes';
"todayMarker"\s[^\n;]+ return 'todayMarker';
\d\d\d\d"-"\d\d"-"\d\d return 'date';
"title"\s[^#\n;]+ return 'title';
"section"\s[^#:\n;]+ return 'section';
[^#:\n;]+ return 'taskTxt';
[^#:\n;]+ return 'taskTxt';
":"[^#\n;]+ return 'taskData';
":" return ':';
<<EOF>> return 'EOF';
@@ -93,9 +94,10 @@ line
statement
: dateFormat {yy.setDateFormat($1.substr(11));$$=$1.substr(11);}
| inclusiveEndDates {yy.enableInclusiveEndDates();$$=$1.substr(18);}
| inclusiveEndDates {yy.enableInclusiveEndDates();$$=$1.substr(18);}
| axisFormat {yy.setAxisFormat($1.substr(11));$$=$1.substr(11);}
| excludes {yy.setExcludes($1.substr(9));$$=$1.substr(9);}
| todayMarker {yy.setTodayMarker($1.substr(12));$$=$1.substr(12);}
| title {yy.setTitle($1.substr(6));$$=$1.substr(6);}
| section {yy.addSection($1.substr(8));$$=$1.substr(8);}
| clickStatement

View File

@@ -37,6 +37,14 @@ describe('when parsing a gantt diagram it', function() {
expect(parserFnConstructor(str)).not.toThrow();
});
it('should handle a todayMarker definition', function() {
spyOn(ganttDb, 'setTodayMarker');
const str =
'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid\nexcludes weekdays 2019-02-01\ntodayMarker off';
expect(parserFnConstructor(str)).not.toThrow();
expect(ganttDb.setTodayMarker).toHaveBeenCalledWith('off');
});
it('should handle a section definition', function() {
const str =
'gantt\n' +

View File

@@ -362,7 +362,7 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
line.attr('marker-start', 'url(' + url + '#sequencenumber)');
g.append('text')
.attr('x', startx)
.attr('y', verticalPos + 4)
.attr('y', verticalPos + 4 + totalOffset)
.attr('font-family', 'sans-serif')
.attr('font-size', '12px')
.attr('text-anchor', 'middle')

View File

@@ -75,8 +75,13 @@ export const draw = function(text, id) {
const width = bounds.width + padding * 2;
const height = bounds.height + padding * 2;
// Zoom in a bit
diagram.attr('width', width * 1.75);
if (conf.useMaxWidth) {
diagram.attr('width', '100%');
diagram.attr('style', `max-width: ${width * 1.75}px;`);
} else {
// Zoom in a bit
diagram.attr('width', width * 1.75);
}
// diagram.attr('height', bounds.height * 3 + conf.padding * 2);
diagram.attr(
'viewBox',